The deploy-vendor-e2e job has been failing with the certctl-test-server
container restarting endlessly. Diagnostic dump (added in 3b96b35)
finally surfaced the actual cause:
Failed to load configuration: SCEP profile 0 (PathID="e2eintune")
has empty CHALLENGE_PASSWORD — refuse to start (CWE-306: per-profile
shared secret is the sole application-layer auth boundary; an empty
password would allow any client reaching /scep/e2eintune to enroll
a CSR against issuer "iss-local")
Same shape as the encryption-key fix that landed in c4157fd: a config
validation gate added in code that the test compose never got updated
to satisfy, hidden pre-Phase-5 because the matrix-collapse hadn't yet
forced the certctl-server to actually boot in CI.
Root cause is more interesting than just "missing env var." The
2026-04-29 SCEP RFC 8894 + Intune master bundle Phase I added an
`e2eintune` SCEP profile to docker-compose.test.yml expecting
deploy/test/scep_intune_e2e_test.go to exercise it. That integration
test does exist (//go:build integration) but **NO CI job ever
selects it** — ci.yml's deploy-vendor-e2e job runs only
`-run 'VendorEdge_'` (line 379), and no other job invokes
`go test -tags integration` with a SCEP selector. Confirmed via
`grep -rnE "scep_intune|SCEPIntune" .github/workflows/` returning
empty.
Worse: the supporting fixtures (ra.crt + ra.key + intune_trust_anchor.pem)
were documented in deploy/test/fixtures/README.md with the
regeneration recipe but never actually committed. Pre-Phase-5 the
test stack didn't fully boot the server in CI, so the entire stack
of debt — dead config + missing fixtures + no consumer test — sat
silent until the matrix collapse forced the boot path.
Fixing this with a fake CHALLENGE_PASSWORD value would silence the
immediate validator but leave the real problem in place: maintenance
cost on test config that no test exercises. Same critique applies
to "let me commit fake fixtures" — the fixtures alone don't add
test coverage when no CI job runs the SCEP test.
The complete-path fix is to make the test compose match what CI
actually exercises:
- deploy/docker-compose.test.yml: drop CERTCTL_SCEP_ENABLED + the
full e2eintune profile env var family (10 lines) + the
./test/fixtures volume mount (1 line). Replace with an in-line
comment explaining why SCEP is intentionally disabled and what
needs to come back together when SCEP is added to CI for real.
- scripts/ci-guards/test-compose-scep-coherence.sh (new, 22nd
guard): refuses any future state where CERTCTL_SCEP_ENABLED=true
in test compose without ALL of:
1. A CI job that runs the SCEP integration test (matched by
scep_intune | SCEPIntune | -run [Ss]cep in ci.yml)
2. The fixture files actually committed (ra.crt, ra.key,
intune_trust_anchor.pem)
3. The ./test/fixtures:/etc/certctl/scep:ro volume mount
Verified manually with the same pattern as the H-1 guard:
clean tree → exit 0; deliberate SCEP_ENABLED=true regression →
exit 1 with 5 ::error:: annotations covering each gap; restore
→ exit 0 again.
- scripts/ci-guards/README.md: 21 → 22 guards, new row.
The fixtures README at deploy/test/fixtures/README.md keeps the
regeneration recipe so the eventual SCEP CI job lands cleanly: the
operator who adds the SCEP job restores the env vars, regenerates
+ commits the fixtures, and the guard auto-passes.
Pattern (now firm across this CI-stabilization sequence):
- Pre-existing latent bug
- Old CI structurally hid it (per-vendor matrix, missing boot path)
- Phase-5 matrix collapse + new diagnostic infra exposed it
- Direct fix unblocks today
- Regression guard prevents the same shape of drift forever
Encryption-key (c4157fd) was the same shape; this is its sibling.