# `ci/` — portable merge gate (runnable today, without Gitea) **Task T-0.2 · R-TEST-02 (reproducible, single-command) · Owner WS-GITOPS (CI).** The same merge gate the Gitea Actions workflow runs ([`.gitea/workflows/`](../.gitea/workflows/README.md)), as plain scripts + a Makefile so the gates are runnable **now**, before any Gitea host or cluster exists. CI and a laptop call the *identical* scripts, so `make -C ci gate` == the CI merge gate. ## Quick start ```bash make -C ci gate # the single command: run every stage + the R-TEST-03 decision make -C ci help # list targets make -C ci tools # which pinned tools are installed locally make -C ci touched # print the touched-requirement subset for this branch vs main ``` Individual stages: ```bash make -C ci lint # yaml/lint (no cluster; live now) make -C ci l0 # ServiceDefinition schema + Kyverno (no cluster; live now) make -C ci l1 # L1 rendering checks (no cluster; live now) make -C ci conformance # L2/L3 in-cluster Chainsaw Job (SKIPS unless CLUSTER_AVAILABLE=true) ``` ## Exit-code contract Every stage script uses: **`0` = pass · `1` = fail (blocks merge) · `3` = SKIPPED** (cluster-gated with no cluster, or an unwired seam / missing tool). A `3` is **never** counted as green — that is how the gate stays honest in Phase 0 (no fake green). ## Reproducibility (R-TEST-02) - **Version-pinned:** all tool versions live in [`versions.env`](versions.env) — the single source of truth shared by the local scripts and the CI installer. Bumping a version is a normal feature-branch → main change. - **Single command, environment-agnostic:** `make -C ci gate` on any machine with the pinned tools. - **Deterministic:** no cluster state is assumed; L2/L3 SKIP unless a cluster is explicitly declared. ## Files ``` ci/ Makefile targets: lint · l0 · l1 · conformance · gate · touched · tools · versions versions.env PINNED tool versions (R-TEST-02) — single source of truth lib.sh shared helpers: logging, tool checks, cluster detection, artifact paths yamllint.yaml lint config for the yaml/lint stage lint.sh Stage: yaml/lint l0.sh Stage: ServiceDefinition schema validation + Kyverno L0 policy gate l1.sh Stage: L1 rendering checks (Chainsaw L1 via the conformance runner) conformance.sh Stage: L2/L3 in-cluster Chainsaw Job (trigger + collect) touched-requirements.sh compute the R-* subset a change touches (drives the R-TEST-03 filter) gate.sh run all stages + the merge decision (the single command) README.md this file ``` ## Integration seams — entrypoints owned by OTHER agents This gate is an **orchestrator**. It does not implement schema validation, Kyverno policies, or the conformance runner — those are other workstreams' deliverables. Each seam is **env-overridable** so the owning agent / PM can reconcile the real entrypoint **without editing these scripts**. Defaults below are this workstream's **assumptions** — flagged for the PM to verify at integration. | Seam | Owner / task | Env override | Assumed default | Assumed interface | |---|---|---|---|---| | ServiceDefinition schema validator | WS-GITOPS · **T-0.3** (`schemas/`) | `SCHEMA_VALIDATE_CMD` | `schemas/validate.sh` | `validate.sh catalog/*.yaml` → exit 0/1; `--version` supported | | Kyverno L0 policies + tests | WS-TEST · **T-0.5** (`platform/kyverno/`) | `KYVERNO_POLICY_DIR` | `platform/kyverno` | contains `kyverno-test.yaml` files discoverable by `kyverno test