CI/CD Pipeline
Comprehensive documentation for the GitHub Actions continuous integration and deployment workflows.
Overview
The project uses five specialized GitHub Actions workflows that validate different aspects of the codebase:
| Workflow | Focus | Platforms | Database Support |
|---|---|---|---|
| Rust | Core Rust quality gate | Ubuntu | SQLite |
| Backend CI | Comprehensive backend + frontend | Ubuntu | SQLite + PostgreSQL |
| Cross-Platform | OS compatibility | Linux, macOS, Windows | Mixed |
| SDK Tests | TypeScript SDK bridge | Ubuntu | SQLite |
| MCP Compliance | Protocol specification | Ubuntu | SQLite |
All workflows run on pushes to main, debug/*, feature/*, claude/* branches and on pull requests to main.
Workflow Details
Rust Workflow
File: .github/workflows/rust.yml
Purpose: Fast quality gate for core Rust development
When it runs: All pushes and PRs
What it validates:
- Code formatting (
cargo fmt --check) - Clippy zero-tolerance linting
- Security audit (
cargo deny check) - Architectural validation (
./scripts/architectural-validation.sh) - Release build (
cargo build --release) - Test coverage with
cargo-llvm-cov - Codecov upload
Database: SQLite in-memory only
Key characteristics:
- Single Ubuntu runner
- Full quality checks
- ~8-10 minutes runtime
- Generates coverage report
Environment variables:
DATABASE_URL="sqlite::memory:"
ENCRYPTION_KEY="rEFe91l6lqLahoyl9OSzum9dKa40VvV5RYj8bHGNTeo="
PIERRE_MASTER_ENCRYPTION_KEY="rEFe91l6lqLahoyl9OSzum9dKa40VvV5RYj8bHGNTeo="
STRAVA_CLIENT_ID="test_client_id_ci"
STRAVA_CLIENT_SECRET="test_client_secret_ci"
STRAVA_REDIRECT_URI="http://localhost:8080/auth/strava/callback"
Backend CI Workflow
File: .github/workflows/ci.yml
Purpose: Comprehensive backend and frontend validation with multi-database support
When it runs: All pushes and PRs
What it validates:
Job 1: backend-tests (SQLite)
- Code formatting
- Clippy zero-tolerance
- Security audit
- Architectural validation
- Secret pattern validation (
./scripts/validate-no-secrets.sh) - All tests with SQLite coverage
- Codecov upload (flag:
backend-sqlite)
Job 2: postgres-tests (PostgreSQL)
- PostgreSQL 16 service container startup
- Connection verification
- Database plugin tests (
--features postgresql) - All tests with PostgreSQL coverage (30-minute timeout)
- Codecov upload (flag:
backend-postgresql)
Job 3: frontend-tests
- Node.js 20 setup
- npm lint (
npm run lint) - TypeScript type checking (
npx tsc --noEmit) - Frontend tests with coverage (
npm run test:coverage) - Frontend build (
npm run build) - Codecov upload (flag:
frontend)
Key characteristics:
- Three parallel jobs
- Separate coverage for each database
- Frontend validation included
- ~15-35 minutes runtime (PostgreSQL job is longest)
PostgreSQL configuration:
POSTGRES_USER=pierre
POSTGRES_PASSWORD=ci_test_password
POSTGRES_DB=pierre_mcp_server
POSTGRES_MAX_CONNECTIONS=3
POSTGRES_MIN_CONNECTIONS=1
POSTGRES_ACQUIRE_TIMEOUT=20
Cross-Platform Tests Workflow
File: .github/workflows/cross-platform.yml
Purpose: Verify code works across Linux, macOS, and Windows
When it runs: Pushes and PRs that modify:
src/**tests/**Cargo.tomlorCargo.lock.github/workflows/cross-platform.yml
What it validates:
Matrix strategy: Runs on 3 platforms in parallel
- ubuntu-latest (with PostgreSQL)
- macos-latest (SQLite only)
- windows-latest (SQLite only)
Platform-specific behavior:
Ubuntu:
- PostgreSQL 16 service container
- All features enabled (
--all-features) - Clippy with all features
- Tests with
--test-threads=1
macOS:
- SQLite in-memory
- Default features only
- Clippy without
--all-features - Standard test execution
Windows:
- SQLite in-memory
- Default features only
- Release mode tests (
--release) for speed - Clippy without
--all-features
Key characteristics:
- Path filtering (only Rust code changes)
- No coverage reporting
- No architectural validation
- No security audit
- Lightweight, fast checks
- ~10-15 minutes per platform
What it doesn’t do:
- Coverage generation (focused on compatibility)
- Heavy validation steps (delegated to other workflows)
SDK Tests Workflow
File: .github/workflows/sdk-tests.yml
Purpose: TypeScript SDK bridge validation and integration with Rust server
When it runs: Pushes and PRs that modify:
sdk/**.github/workflows/sdk-tests.yml
What it validates:
- Node.js 20 + Rust 1.91.0 setup
- SDK dependency installation (
npm ci --prefer-offline) - SDK bridge build (
npm run build) - SDK unit tests (
npm run test:unit) - Rust server debug build (
cargo build) - SDK integration tests (
npm run test:integration) - SDK E2E tests (
npm run test:e2e) - Test artifact upload (7-day retention)
Key characteristics:
- Path filtering (only SDK changes)
- Multi-language validation (TypeScript + Rust)
- Debug Rust build (faster for integration tests)
--forceExitflag for clean Jest shutdown- ~8-12 minutes runtime
Test levels:
- Unit: SDK-only tests (no Rust dependency)
- Integration: SDK ↔ Rust server communication
- E2E: Complete workflow testing
MCP Compliance Workflow
File: .github/workflows/mcp-compliance.yml
Purpose: Validate MCP protocol specification compliance
When it runs: All pushes and PRs
What it validates:
- Python 3.11 + Node.js 20 + Rust 1.91.0 setup
- MCP Validator installation (cloned from
Janix-ai/mcp-validator) - SDK dependency installation
- SDK bridge build
- SDK TypeScript types validation:
- Checks
src/types.tsexists - Rejects placeholder content
- Requires pre-generated types in repository
- Checks
- MCP compliance validation (
./scripts/ensure_mcp_compliance.sh) - Artifact cleanup
Key characteristics:
- Multi-language stack (Python + Node.js + Rust)
- External validation tool
- Strict type generation requirements
- Disk space management (aggressive cleanup)
- CI-specific flags (
CI=true,GITHUB_ACTIONS=true) - Security flags (
PIERRE_ALLOW_INTERACTIVE_OAUTH=false) - ~10-15 minutes runtime
Environment variables:
CI="true"
GITHUB_ACTIONS="true"
HTTP_PORT=8080
DATABASE_URL="sqlite::memory:"
PIERRE_MASTER_ENCRYPTION_KEY="rEFe91l6lqLahoyl9OSzum9dKa40VvV5RYj8bHGNTeo="
PIERRE_ALLOW_INTERACTIVE_OAUTH="false"
PIERRE_RSA_KEY_SIZE="2048"
Workflow Triggers
Push Triggers
All workflows run on these branches:
maindebug/*feature/*claude/*
Pull Request Triggers
All workflows run on PRs to:
main
Path Filtering
Some workflows only run when specific files change:
Cross-Platform Tests:
src/**tests/**Cargo.toml,Cargo.lock.github/workflows/cross-platform.yml
SDK Tests:
sdk/**.github/workflows/sdk-tests.yml
Optimization rationale: Path filtering reduces CI resource usage by skipping irrelevant workflow runs. For example, changing only SDK code doesn’t require cross-platform Rust validation.
Understanding CI/CD Results
Status Indicators
- ✅ Green check: All validations passed
- ⚠️ Yellow circle: Workflow in progress
- ❌ Red X: One or more checks failed
Common Failure Patterns
Formatting Failure
error: left behind trailing whitespace
Fix: Run cargo fmt locally before committing
Clippy Failure
error: using `unwrap()` on a `Result` value
Fix: Use proper error handling with ? operator or ok_or_else()
Test Failure
test result: FAILED. 1245 passed; 7 failed
Fix: Run cargo test locally to reproduce, fix failing tests
Security Audit Failure
error: 1 security advisory found
Fix: Run cargo deny check locally, update dependencies or add justified ignore
Architectural Validation Failure
ERROR: Found unwrap() usage in production code
Fix: Run ./scripts/architectural-validation.sh locally, fix violations
PostgreSQL Connection Failure
ERROR: PostgreSQL connection timeout
Cause: PostgreSQL service container not ready Fix: Usually transient, re-run workflow
SDK Type Validation Failure
ERROR: src/types.ts contains placeholder content
Fix: Run npm run generate-types locally with running server, commit generated types
Viewing Detailed Logs
- Navigate to Actions tab in GitHub
- Click on the workflow run
- Click on the failing job
- Expand the failing step
- Review error output
Local Validation Before Push
Run the same checks locally to catch issues before CI:
# 1. Format code
cargo fmt
# 2. Architectural validation
./scripts/architectural-validation.sh
# 3. Zero-tolerance clippy
cargo clippy --tests -- \
-W clippy::all \
-W clippy::pedantic \
-W clippy::nursery \
-D warnings
# 4. Run all tests
cargo test
# 5. Security audit
cargo deny check
# 6. SDK tests (if SDK changed)
cd sdk
npm run test:unit
npm run test:integration
npm run test:e2e
cd ..
# 7. Frontend tests (if frontend changed)
cd frontend
npm run lint
npm run test:coverage
npm run build
cd ..
Shortcut: Use validation script
./scripts/lint-and-test.sh
Debugging CI/CD Failures
Reproducing Locally
Match CI environment exactly:
# Set CI environment variables
export DATABASE_URL="sqlite::memory:"
export ENCRYPTION_KEY="rEFe91l6lqLahoyl9OSzum9dKa40VvV5RYj8bHGNTeo="
export PIERRE_MASTER_ENCRYPTION_KEY="rEFe91l6lqLahoyl9OSzum9dKa40VvV5RYj8bHGNTeo="
export STRAVA_CLIENT_ID="test_client_id_ci"
export STRAVA_CLIENT_SECRET="test_client_secret_ci"
export STRAVA_REDIRECT_URI="http://localhost:8080/auth/strava/callback"
# Run tests matching CI configuration
cargo test --test-threads=1
Platform-Specific Issues
macOS vs Linux differences:
- File system case sensitivity
- Line ending handling (CRLF vs LF)
- Path separator differences
Windows-specific issues:
- Longer compilation times (run release mode tests)
- Path length limitations
- File locking behavior
PostgreSQL-Specific Debugging
Start local PostgreSQL matching CI:
docker run -d \
--name postgres-ci \
-e POSTGRES_USER=pierre \
-e POSTGRES_PASSWORD=ci_test_password \
-e POSTGRES_DB=pierre_mcp_server \
-p 5432:5432 \
postgres:16-alpine
# Wait for startup
sleep 5
# Run PostgreSQL tests
export DATABASE_URL="postgresql://pierre:ci_test_password@localhost:5432/pierre_mcp_server"
cargo test --features postgresql
# Cleanup
docker stop postgres-ci
docker rm postgres-ci
SDK Integration Debugging
Run SDK tests with debug output:
cd sdk
# Build Rust server in debug mode
cd ..
cargo build
cd sdk
# Run tests with verbose output
npm run test:integration -- --verbose
npm run test:e2e -- --verbose
Coverage Reporting
Codecov Integration
Coverage reports are uploaded to Codecov with specific flags:
backend-sqlite: SQLite test coveragebackend-postgresql: PostgreSQL test coveragefrontend: Frontend test coverage
Viewing Coverage
- Navigate to Codecov dashboard
- Filter by flag to see database-specific coverage
- Review coverage trends over time
- Identify untested code paths
Coverage Thresholds
No enforced thresholds (yet), but aim for:
- Core business logic: >80%
- Database plugins: >75%
- Protocol handlers: >70%
Workflow Maintenance
Updating Rust Version
When updating Rust toolchain:
- Update
rust-toolchainfile - Update
.github/workflows/*.yml(search fordtolnay/rust-toolchain@) - Test locally with new version
- Commit and verify all workflows pass
Updating Dependencies
When updating crate dependencies:
- Run
cargo update - Test locally
- Check
cargo deny checkfor new advisories - Update
deny.tomlif needed (with justification) - Commit and verify CI passes
Adding New Workflow
When adding new validation:
- Create workflow file in
.github/workflows/ - Test workflow on feature branch
- Document in this file
- Update summary table
- Add to
contributing.mdreview process
Cost Optimization
Cache Strategy
Workflows use actions/cache@v4 for:
- Rust dependencies (
~/.cargo/) - Compiled artifacts (
target/) - Node.js dependencies (
node_modules/)
Cache keys include:
- OS (
${{ runner.os }}) - Rust version
Cargo.lockhash
Disk Space Management
Ubuntu runners have limited disk space (~14GB usable).
Free disk space steps:
- Remove unused Android SDK
- Remove unused .NET frameworks
- Remove unused Docker images
- Clean Cargo cache
Workflows using cleanup:
- Rust workflow
- Backend CI workflow
- Cross-Platform Tests workflow
- MCP Compliance workflow
Parallel Execution
Jobs run in parallel when independent:
- Backend CI: 3 jobs in parallel (SQLite, PostgreSQL, frontend)
- Cross-Platform: 3 jobs in parallel (Linux, macOS, Windows)
Total CI time: ~30-35 minutes (longest job determines duration)
Troubleshooting Reference
“failed to get X as a dependency”
Cause: Network timeout fetching crate Fix: Re-run workflow (transient issue)
“disk quota exceeded”
Cause: Insufficient disk space on runner Fix: Workflow already includes cleanup; may need to reduce artifact size
“database connection pool exhausted”
Cause: Tests creating too many connections
Fix: Tests use --test-threads=1 to serialize execution
“clippy warnings found”
Cause: New clippy version detected additional issues
Fix: Run cargo clippy --fix locally, review and commit
“mcp validator not found”
Cause: Failed to clone mcp-validator repository Fix: Re-run workflow (transient network issue)
“sdk types contain placeholder”
Cause: Generated types not committed to repository
Fix: Run npm run generate-types locally with server running, commit result
Best Practices
Before Creating PR
- Run
./scripts/lint-and-test.shlocally - Verify all tests pass
- Check clippy with zero warnings
- Review architectural validation
- If SDK changed, run SDK tests
- If frontend changed, run frontend tests
Reviewing PR CI Results
- Wait for all workflows to complete
- Review any failures immediately
- Don’t merge with failing workflows
- Check coverage hasn’t decreased significantly
- Review security audit warnings
Maintaining CI/CD Health
- Monitor workflow run times (alert if >50% increase)
- Review dependency updates monthly
- Update Rust version quarterly
- Keep workflows DRY (extract common steps to scripts)
- Document any workflow changes in this file
Future Improvements
Planned enhancements:
- Enforce coverage thresholds
- Add benchmark regression testing
- Add performance profiling workflow
- Add automated dependency updates (Dependabot)
- Add deployment workflow for releases
- Add E2E testing with real Strava API (secure credentials)