# ADR 0007 — CI pipeline (GitHub Actions)

- Status: Accepted
- Date: 2026-08-19

## Context

Phase 9 builds the CI pipeline (stages 1–7; deploy is Phase 10). It must run
static analysis, unit and integration tests independently, enforce coverage,
scan for vulnerabilities, build a versioned jar, and publish a signed multi-arch
image with an SBOM.

## Decisions

- **Independent unit/integration jobs sharing one coverage gate.** Surefire
  (`*Test`) and Failsafe (`*IT`) are toggled by `skipUnitTests`/
  `skipIntegrationTests`, and JaCoCo writes **two exec files** (`jacoco-ut.exec`,
  `jacoco-it.exec`). The `unit-test` and `integration-test` jobs each produce and
  upload one; a separate `coverage-gate` job downloads both, runs
  `jacoco:merge → report → check` against the merged data, enforces the ≥90%
  service-package thresholds, publishes the HTML report, and comments coverage on
  the PR. This gives an honest combined number without either test job gating in
  isolation. The same executions run locally under `mvn verify`, so dev and CI use
  one config.
- **PR vs push scope.** `pull_request` runs stages 1–6 (no image push);
  `push` to `main` and `v*` tags runs everything including the `docker` job
  (`if: github.event_name == 'push'`). Concurrency groups cancel superseded runs
  per ref.
- **GHCR via the built-in `GITHUB_TOKEN`; cosign keyless.** No long-lived registry
  secret is needed — `GITHUB_TOKEN` (packages: write) pushes to GHCR and cosign
  signs by digest with OIDC (id-token: write). A guard step fails with a readable
  message if a required secret is missing. Images are tagged `sha-<short>`, the
  git tag, and `latest` on `main` only.
- **Supply chain.** Buildx builds `linux/amd64,linux/arm64` with provenance and an
  attested SBOM; a Syft CycloneDX SBOM is also uploaded as an artifact. Trivy
  scans the filesystem (job 5) and the built image (job 7) at HIGH/CRITICAL, with
  a `.trivyignore` allow-list for triaged findings. Dependabot keeps Maven, Actions,
  and Docker deps current.
- **Local parity.** `make verify` / `scripts/verify.sh` run the exact gate
  (clean + static analysis + unit + integration + coverage) before pushing, and
  set the Colima-specific Testcontainers env locally (never in CI, which uses a
  native Docker runner with Ryuk enabled).

## Consequences

- All seven job commands were validated locally (`validate`, `unit-test`,
  `integration-test`, `coverage-gate` merge/check, and `make verify`).
- Deploy (staging/prod), the rollback workflow, and Newman post-deploy smoke tests
  are Phases 10 and 12.
