aws-samples / aws-samples/sample-autonomous-cloud-coding-agents
feat(ci): single source of truth for prek↔CI — parameterize scans, pin scanner toolchain, add hook/CI parity contract
- Dominant language
- TypeScript
- Stars
- 143
- Forks
- 46
- Avg merge
- 3d 9h
- Merged PRs (30d)
- 20
Description
> **Filed during the ABCA validation-loop CI/CD review** (Bonk, 2026-06-12). Closes the structural gap behind the #313 incident: there are currently **two sources of truth** for what "the checks" mean — client-side `prek` hooks and server-side CI — and nothing keeps them in sync, so `--no-verify` skips a *different* set of checks than CI enforces, silently. Depends on the merge gate from #327 being real first.
### Component
Tooling / CI
### Describe the feature
Make the `mise` task the **single source of truth** for every scan, with `prek` and GitHub Actions both as thin invokers of the same task names, and machine-verify that the local and server gate sets cannot drift.
The model (from the review's prek↔CI division-of-labor analysis):
**1. All scanner logic + flags live in `mise.toml`, nowhere else.** No `gitleaks …` args inline in `.pre-commit-config.yaml` entries, no scanner invocations inline in workflow YAML — both call `mise run `. Already mostly true here; finish it (the hook entries currently shell out to `mise run …`, which is the right shape — keep all flags in the task).
**2. Scope is a *parameter* of the task, not a forked task.** One `security:secrets` task parameterized by an env var:
```
gitleaks git --log-opts="${SCAN_RANGE:---all}" --redact --no-banner
```
- `prek` pre-push sets `SCAN_RANGE` to the outgoing range (`origin/main..HEAD`).
- the CI per-PR job (#327) sets it to `origin/$BASE..HEAD`.
- the scheduled all-refs sweep sets it to `--all`.
Same rule set, same `.gitleaks.toml`, same binary — only the commit window differs. No second task to drift. (Migrate off the deprecated `gitleaks detect`/`protect` to `gitleaks git` as part of this — see #327/#328.)
**3. Pin the scanner toolchain.** `mise.toml [tools]` currently has `prek = "latest"`, `gitleaks = "latest"`, `semgrep = "latest"`, `osv-scanner = "latest"`, `grype = "latest"`, zizmor `"latest"`, and the `jdx/mise-action` calls have no `version:`. So the binaries that *are* the gates auto-update on every dev machine and CI run — meaning local gitleaks 8.x and CI gitleaks 8.y can disagree on the same bytes (a hidden third source of truth), and a compromised scanner release is code execution everywhere `mise run install` runs. Ironic next to the fully SHA-pinned GitHub Actions. Pin exact versions in `[tools]` and `version:` in `mise-action`; let the existing Dependabot config bump them (it covers npm/uv/docker/actions but not mise `[tools]` today, so add that ecosystem or a Renovate manager).
**4. Add a 4th `drift-prevention` contract: prek↔CI parity.** The repo already machine-verifies three contracts (`check:types-sync`, `check:constants-sync`, `check:coverage-thresholds-sync`). Add `check:hooks-ci-sync`: assert that every hook `entry` in `.pre-commit-config.yaml` resolves to a `mise` task that also appears in the CI-required DAG (the `build` + `security-pr` jobs from #327). This turns hook↔CI parity from a convention into a failing check — if someone adds a pre-push scan that CI doesn't enforce (or vice-versa), the build breaks.
### Why it matters here
The #313 incident is a drift story: the local hooks scanned for secrets, CI (per-PR) did not, and `--no-verify` walked past the only gate that was running. Once #327 makes CI authoritative, the failure mode inverts — CI enforces something the hooks don't, or the hooks scan with a different tool version than CI. A single parameterized task + pinned tools + a parity contract makes "the checks" mean exactly one thing in both places, and `--no-verify` then skips only the *courtesy* (the fast local pre-flight), never the *gate*.
### Acceptance criteria
- [ ] `security:secrets` (and the other scan tasks) are parameterized by `SCAN_RANGE`; prek, the per-PR CI job, and the scheduled sweep all invoke the **same** task with different scope.
- [ ] No scanner flags live in `.pre-commit-config.yaml` entries or workflow YAML — only `mise run `.
- [ ] All scanner tools in `mise.toml [tools]` are pinned to exact versions; `mise-action` calls pin `version:`; bumps flow through Dependabot/Renovate.
- [ ] `check:hooks-ci-sync` exists in `:drift-prevention` and fails the build when a prek hook entry has no corresponding mise task in the CI-required DAG (and vice-versa).
- [ ] A red CI check names the exact failing task; `mise run ` reproduces it locally byte-for-byte.
### Other information
Source: ABCA validation-loop CI/CD review (Bonk + Fable-5, 2026-06-12) — prek↔CI division-of-labor + supply-chain pinning findings. Effort: **M**. Depends on #327 (a real merge gate) landing first; the parity check is meaningless until the CI-required DAG is defined. Per ADR-003 this issue needs the `approved` label before work begins. Note the agent-specific caveat from #327 §E: this scheme runs PR-branch-controlled task definitions, so CODEOWNERS on `mise.toml` / `.pre-commit-config.yaml` is load-bearing, not optional.
Contributor guide
Assessment
This issue has not been assessed yet.