docs: add ADR-0015 for the CI/CD pipeline (Gitea Actions, trunk-based + squash-merge, thin YAML)

Pin the CI/CD shape with an explicit two-level structure, anticipating
the GitLab migration on the 6-18-month horizon:

Level 1 - vendor-neutral, survives the migration:
- Trunk-based with short-lived feature branches; squash-merge only.
- Branch protection on main: no direct push, no force push, linear
  history, required green CI, required reviewers = 0 in v1 (raised to
  >=1 when a second contributor joins), branch deletion after merge.
- Required CI gates (all blocking): format, lint, type-check, test,
  build (nx affected), audit (pnpm + Trivy), secret-scan (gitleaks),
  commit-lint (Conventional Commits on the PR commit range). Future
  a11y and perf gates land with their respective ADRs.
- Conventional Commits validated locally (hook from ADR-0007) and in
  CI as defense in depth.
- Signed commits recommended but not required in v1; revisited at the
  GitLab migration.
- Thin YAML: all orchestration logic lives in package.json scripts
  (ci:check, ci:scan, ci:commits) and Nx targets. Workflow files only
  do checkout, setup, cache, and call one script per job. The migration
  rewrites the YAML wrappers, never the gates.
- Secrets convention SCOPE_PURPOSE; gitleaks enforces no-secrets-in-code.
- Container images / deploy explicitly out of scope (deferred to the
  on-prem infrastructure ADR).

Level 2 - Gitea Actions specific, will be superseded by a GitLab
migration ADR:
- Engine: Gitea Actions (built-in, GitHub Actions-compatible syntax,
  partial portability hedge if the org pivots to GitHub).
- Runners: >=3 self-hosted act_runner instances on-prem, Debian image
  pinned by SHA, weekly rebuild via security-scheduled.yml.
- Three workflow files: ci.yml (PR + push to main), release.yml
  (stub for tag, populated by the deploy ADR), security-scheduled.yml
  (weekly Trivy + gitleaks full-tree scan + Renovate trigger).

Migration weight estimated at 3-5 days dev/ops when GitLab arrives:
the YAML is rewritten, the gates and scripts are unchanged. A future
ADR will explicitly supersede only the level-2 sections.

decisions/README.md index updated. CLAUDE.md gains an explicit 'CI/CD'
line pointing to ADR-0015 and noting the future GitLab supersession.
This commit is contained in:
Julien Gautier
2026-04-30 11:21:30 +02:00
parent a20330a474
commit 49712d0bbf
3 changed files with 314 additions and 0 deletions
+1
View File
@@ -43,6 +43,7 @@ The structural choices are recorded as ADRs and summarized below. Any change to
- **Observability:** Pino + `nestjs-pino` for structured JSON logs, OpenTelemetry SDK + auto-instrumentations for traces, W3C Trace Context propagation across SPA → BFF → DB → Redis, `nestjs-cls` for request-scoped context (`trace_id`, `session_id`, `user_id_hash`, `audience`), 100 % sampling at the app with tail sampling deferred to the OTel Collector, stdout + OTLP shipping — see [ADR-0012](decisions/0012-observability-pino-opentelemetry.md).
- **Audit trail:** dedicated `audit.events` schema in the same Postgres instance, append-only by Postgres role grants (`audit_writer` INSERT, `audit_reader` SELECT, `audit_archiver` DELETE older than retention; no `UPDATE`/`TRUNCATE` to anyone); 365-day retention default; cross-referenced with app logs via `trace_id` and `actor_id_hash` (same salt); blocking writes (no audit ⇒ no action) — see [ADR-0013](decisions/0013-audit-trail-separated-postgres-append-only.md).
- **Downstream API access:** unified `DownstreamApiClient` (`@nestjs/axios` + `cockatiel`), per-service `DownstreamApiConfig`; default auth strategy is **OBO via MSAL Node** for Entra-protected APIs (downstream-scoped tokens cached in Redis with AES-256-GCM under a dedicated key); fallback strategy is service credential + signed `X-User-Assertion` JWT (BFF JWKS at `/.well-known/jwks.json`); per-call audience pre-check; no `axios`/`fetch` outside `src/downstream/` — see [ADR-0014](decisions/0014-downstream-api-access-obo-pattern.md).
- **CI/CD:** **Gitea Actions** (level-2 implementation; will be superseded by a GitLab migration ADR within 6-18 months). Trunk-based with squash-merge, branch protection on `main`, all CI gates blocking. Thin YAML — orchestration logic lives in `package.json` scripts (`ci:check`, `ci:scan`, `ci:commits`) and Nx targets, runnable locally. Gates: format / lint / type-check / test / build / audit / secret-scan / commit-lint, plus future `a11y` and `perf`. Self-hosted `act_runner` on-prem. Conventional Commits validated locally (hook) and in CI (defense in depth). Required reviewer count = 0 in v1, raised to ≥1 once a second contributor joins. Signed commits recommended, revisited at GitLab migration — see [ADR-0015](decisions/0015-cicd-gitea-actions.md).
- **Local quality gates:** Husky + lint-staged + commitlint with Conventional Commits — see [ADR-0007](decisions/0007-pre-commit-hooks-and-conventional-commits.md).
- **Runtime:** Node.js latest LTS major.