ci: add a Caproni end-to-end job and environment

Summary

Adds an end-to-end job that brings up a Caproni cluster, deploys this branch's build of Artifact Registry into it, and drives the service through its HTTP APIs.

Path What
test/caproni/ The environment: AR plus PostgreSQL, Valkey and Garage. Four deployers, no GitLab monolith, no TLS.
scripts/e2e/ install-tools.sh, caproni-up.sh, run-e2e-tests.sh, collect-diagnostics.sh.
test:e2e:caproni The job wiring them together.

The suite provisions a namespace through the GitLab API (POST /api/gitlab/v1/namespaces), then creates a repository in it through the management API (POST /api/v1/:slug/repositories), asserting an exact status per call plus the response fields and defaults both contracts document — including the idempotent replay (200, same UUID) and the name-conflict 409.

It gates the diff, not a release. scripts/chart-gen.sh stamps the chart's appVersion with the image tag, and the image is loaded into the k3d nodes with k3d image import. Nothing is pushed, so there is no pull secret to provision, no per-merge-request image to garbage-collect, and it behaves identically on the security mirror and on forks, where $CI_REGISTRY_IMAGE would not be readable from the cluster.

This is not the development rig — that is gitlab-org/gitlab-caproni, and caproni/README.md is retargeted to it here (it still pointed at the twice-superseded caproni-demo). Full rationale, local usage, and the deviations from the upstream Caproni snippet: docs/dev/caproni-e2e.md.

Governing ADRs

scripts/adr-freshness.sh reports the mirror stale for 007, 020, 021 and 022. I diffed ADR-020 against upstream: the drift is link rewrites plus an ADR-021 boundary clarification, neither bearing on this change.

  • ADR-024 (Infrastructure delivery) — conforms, and exercises it. The environment deploys the chart scripts/chart-gen.sh generates from .runway/fairway.yaml — the same descriptor Runway deploys from — rather than a bespoke test chart.
  • ADR-005 (Artifact delivery mode) — conforms. The environment sets the instance default to DELIVERY_MODE_PROXY, which is the ADR's documented case for clients that cannot reach the storage backend directly: a pre-signed URL would point at the deps-garage ClusterIP, unreachable from the job container.
  • ADR-020 (Authentication flow) — conforms, with a coverage gap worth stating. The environment selects the existing auth.bootstrap_token development stub. Token exchange would need the monolith's JWKS and therefore a monolith in the cluster, which is what this environment deliberately omits. The suite does not exercise ADR-020's token-exchange path.
  • ADR-001 / ADR-007 (Organization anchor, schema) — conforms. The suite provisions with the (gitlab, organization, <numeric id>) anchor tuple; a non-organization or non-numeric anchor makes usage-data attribution drop the event.
  • ADR-023 (Code structure) — no conflict. Its locked paths are cmd/, internal/, internal/format/<name>/ and the depguard packages; test/ and scripts/ are unlocked, and the tree is explicitly "not a mandate". test/caproni is the layout the Caproni testing docs assume.

Testing

The job is the test. Evidence from the branch:

Pipeline Commit Result
2767155675 9ee22e9a (post-rebase) 57/57 green, test:e2e:caproni 267s
2763259172 d55a4b21 12/12 green, test:e2e:caproni 249s

The tip commit df96431e changes comments only — no code or configuration — verified by diffing every touched file with comments stripped. Its pipeline runs with this MR.

Also verified locally: shellcheck, shfmt, yamllint, glab ci lint, markdownlint, Vale, lychee.

An earlier iteration regressed the job from 231s to 456s. That was diagnosed from per-line trace timestamps to an unscoped mise x -- installing the whole repository toolchain (+65s, fixed in cc6a22d1) and a one-off 137s stall in the caproni plugin's release lookup (did not reproduce). The Postgres gate added in 27a6e5ae is net negative cost: it drops the readiness wait from 102s to 17s by keeping AR from crash-looping on a missing database.

Reviewable LOC

1,235 added lines, so per development-model.md here is the split and why it is not split further:

Group Code Comments Docs
scripts/e2e/ (4 scripts) 367 219
test/caproni/ (3 YAML) 134 60
CI and repo config 69 47
Documentation (3 .md) 210
Total 570 326 210

Code is 570 lines; the rest is comments (326), documentation (210) and blanks (129). Splitting would not help: the environment, the scripts that drive it, and the job that runs them are only verifiable together — a test/caproni that nothing runs, or a suite with no environment, is unreviewable and untestable in isolation. The intermediate commits are individually reviewable and tell the story in order.

Scenario catalogs

No catalog change. Per guardrail 12 this is ci/docs rather than feat/fix, and the suite is a smoke test rather than a named-scenario harness, so it flips no Status in docs/testing/. It overlaps e2e.oci.setup.create-repository, which additionally requires the new repository to work as a push target.

Note for the reviewer

No plan MR precedes this. Every commit is ci: or docs:, which conventions.md classifies as toil, but the change is large enough that the toil/feature boundary is a fair question to raise — flagging it rather than leaving it implicit.

Related to #318

Merge request reports

Loading
Loading