MACP Control Plane — CI/CD Reference
Workflows
| Workflow | Trigger | What it does |
|---|---|---|
| ci.yml | push/PR → main | lint, typecheck, unit tests (+coverage summary), integration tests, npm audit gate, secret scan, convention sweeps, build, Docker build (push + Trivy on main only) |
| release.yml | tag v*.*.* | Trivy-gated semver image push to GHCR + GitHub Release |
| codeql.yml | push/PR → main, weekly | CodeQL static analysis (javascript-typescript) |
| integration-tests.yml | manual | integration tests against mock / docker / remote runtime, optional Python agent E2E |
| deploy.yml | manual (tag input) | SSH deploy to the production VM — dormant until DEPLOY_SSH_* secrets exist |
| notify-website.yml | push → main (docs paths) | repository-dispatch to the website repo |
CI pipeline (ci.yml)
lint ─┐
typecheck ─┤
test (unit + coverage) ─┼→ build → docker (every PR: build-only; main: push to GHCR + Trivy CRITICAL gate)
audit (npm audit, prod deps, high+) ─┤
check-env-secrets ─┤
conventions (CLAUDE.md grep sweeps) ─┘
test → integration-test (postgres:16 service on 5433, mock runtime)- Concurrency: superseded PR runs are cancelled;
mainpushes never are (a killed docker job could leave a partiallatesttag). - Node version comes from
.nvmrceverywhere (node-version-file) — one place to bump. - Coverage is reported in the job step-summary and uploaded as an artifact; there is deliberately no blocking threshold.
- PR Docker builds run without pushing, so a broken Dockerfile fails the PR, not the merge to
main. - The private
@multiagentcoordinationprotocol/protopackage installs viaNODE_AUTH_TOKEN=${{ secrets.GITHUB_TOKEN }}(Actions) and a BuildKit secretnpm_token(Docker builds).
Releases
- Bump
versioninpackage.json(the release workflow warns on tag/package.json drift). git tag v0.6.0 && git push origin v0.6.0- The workflow builds the image, scans it with Trivy (
CRITICAL,ignore-unfixed) before anything reaches the registry, then pushesv0.6.0,v0.6, andlatest(pre-release tags likev0.6.0-rc.1skiplatestand are marked pre-release), and creates a GitHub Release with generated notes.
Security & dependency automation
- npm audit (
ci.ymlauditjob): checks high/critical advisories in production dependencies. Currently report-only (continue-on-error) — the dependency tree has high/critical advisories with no non-breaking fix (e.g. multer / path-to-regexp via@nestjs, protobufjs via otel), so a hard gate would block every build. Flip it to blocking (removecontinue-on-errorand addauditback tobuild'sneeds) once those are upgraded. - Trivy: image CVE scan on
main(post-push, report-only) and on release (pre-push, hard gate — blocks the tag push). CRITICAL only, unfixed CVEs ignored. - CodeQL: JS/TS analysis on PRs plus a Monday-morning schedule. Requires GitHub Advanced Security on private repos.
- Dependabot: weekly npm (minor+patch grouped,
@multiagentcoordinationprotocol/protoexcluded — proto upgrades are deliberate absorptions) and weekly github-actions updates. Requires theDEPENDABOT_GHPR_TOKENDependabot secret (classic PAT,read:packages) so lockfile regeneration can resolve the private registry — without it every npm update PR fails.
Required secrets
| Secret | Where | Purpose |
|---|---|---|
GITHUB_TOKEN | built-in | GHCR push, private package install, release creation |
DEPENDABOT_GHPR_TOKEN | Dependabot secrets | private-registry resolution for Dependabot npm updates |
DEPLOY_SSH_HOST / DEPLOY_SSH_USER / DEPLOY_SSH_KEY | Actions secrets | optional remote deploy (deploy.yml stays dormant without them) |
WEBSITE_SYNC_TOKEN | Actions secrets | notify-website dispatch (pre-existing) |
Deployment
Single-VM Docker Compose — see deploy/README.md for the runbook (deploy.sh deploy <tag> / rollback / status, .env.prod setup, backup notes). Images are pinned by explicit tag (TAG=vX.Y.Z); deploy.sh records .current_tag/.previous_tag and verifies /healthz before declaring success. Rollback swaps the app image only — migrations are forward-only.