Bundle: ci-pipeline-cleanup, Phase 12. NEW docs/ci-pipeline.md (operator-facing guide to the on-push pipeline): - Trigger model (push, daily, tag) - Per-job deep-dive for all 5 CI jobs + 2 CodeQL jobs - The 20 regression guards table with what each catches - Coverage threshold management - Three-tier make convention (verify, verify-deploy, verify-docs) - Adding a new check (where it goes, auto-pickup) - Troubleshooting matrix - Status check accounting (19 → 7) - Required GitHub branch protection list (operator action) NEW cowork/ci-pipeline-cleanup/v2.X.0-release-notes.md — operator-facing release notes covering all 13 phases + the operator action items post-merge. NEW cowork/ci-pipeline-cleanup/reddit-beat.md — Reddit / HN announce draft (don't auto-post; operator times manually after the tag lands). Active Focus updated in cowork/CLAUDE.md (workspace, separate edit since CLAUDE.md isn't in the repo) — added ci-pipeline-cleanup entry to 'Recently shipped bundles' + new env-var summary line + two new operator-decision items (RAM headroom + branch protection rules).
7.5 KiB
certctl v2.X.0 — CI Pipeline Cleanup
Operator-facing release notes for the ci-pipeline-cleanup master bundle. Operator picks the exact
v2.X.0from the increment-from-the-last-tag rule.
TL;DR
Restructured the on-push CI pipeline. Status checks per push drop from
19 → 7. ci.yml shrinks 1488 → ~430 lines (-71%). Three lying
fields closed (staticcheck soft-gate; Bundle II's fabricated digest
regex-only check; Windows matrix that validated nothing). Five new
gates added (digest validity, go mod tidy drift, gofmt parity,
OpenAPI ↔ handler parity, Docker build smoke).
Zero product behavior changes. No migrations, no API changes, no connector behavior changes. CI-only refactor.
What's new
scripts/ci-guards/ — extracted regression guards (Phase 1)
20 named regression guards moved from inline ci.yml bash to sibling
scripts:
G-1-jwt-auth-literal.sh,L-001-insecure-skip-verify.sh,H-001-bare-from.sh,M-012-no-root-user.sh,H-009-readme-jwt.sh,G-2-api-key-hash-json.sh,U-2-plaintext-healthcheck.sh,U-3-migration-mount.sh,D-1-D-2-statusbadge-phantom.sh,L-1-bulk-action-loop.sh,B-1-orphan-crud.sh,S-2-strings-contains-err.sh,G-3-env-docs-drift.sh,test-naming-convention.sh,S-1-hardcoded-source-counts.sh,P-1-documented-orphan-fns.sh,T-1-frontend-page-coverage.sh,bundle-8-L-015-target-blank-rel-noopener.sh,bundle-8-L-019-dangerously-set-inner-html.sh,bundle-8-M-009-bare-usemutation.sh
Each script is callable locally:
bash scripts/ci-guards/G-3-env-docs-drift.sh
CI step is a single loop that auto-picks up new scripts. Adding a new
guard: drop a new <id>.sh; no ci.yml change required.
The 2 QA-doc guards (Part-count + seed-count) moved to make verify-docs
instead — they protect docs-the-operator-reads, not anything the
product depends on.
.github/coverage-thresholds.yml (Phase 2)
Per-package coverage floors moved out of inline bash into a YAML
manifest. Each entry has floor: (integer percentage) + why:
(load-bearing context — Bundle reference, HEAD measurement, gap
rationale). Adding a new gated package: one YAML entry instead of
~30 lines of bash. Floors unchanged from HEAD.
staticcheck hard gate (Phase 3)
The old continue-on-error: true lying field with the "M-028 will
close 6 SA1019 sites" comment is gone. Verified at HEAD: all live
SA1019 sites either migrated (middleware.NewAuth → NewAuthWithNamedKeys)
or suppressed inline with load-bearing rationale (csr.Attributes for
RFC 2985 challengePassword; elliptic.Marshal only in byte-equivalence
test). Gate now hard.
make verify parity + go mod tidy drift (Phase 4)
Two new steps in go-build-and-test:
- gofmt drift — closes the parity gap with
Makefile::verify(CI was running vet + lint + test but not gofmt) - go mod tidy drift —
go mod tidy && git diff --exit-code go.mod go.sum
deploy-vendor-e2e collapsed: 12 jobs → 1 job (Phase 5)
Per-vendor matrix granularity was fake signal — verified that 115/116
vendor-edge tests are t.Log placeholders. Single job brings up all
11 sidecars at once + runs the full VendorEdge_ suite + enforces
skip-count (no sidecar may silently fail to come up).
NEW scripts/ci-guards/vendor-e2e-skip-check.sh + allowlist file at
scripts/ci-guards/vendor-e2e-skip-allowlist.txt (15 windows-iis-
requiring tests legitimately skip on Linux per Phase 6).
Revises Bundle II frozen decision 0.9. Documented in
cowork/ci-pipeline-cleanup/decisions-revised.md.
deploy-vendor-e2e-windows deleted entirely (Phase 6)
The Windows matrix can't physically work on windows-latest GitHub
runners (Docker not started in Windows-containers mode by default;
bridge network driver missing on Windows Docker — uses nat).
Even if fixed, all 16 IIS + WinCertStore tests are t.Log placeholders.
NEW docs/connector-iis.md::Operator validation playbook documents
the manual-on-Windows-host procedure operators run pre-release. The
windows-iis-test sidecar stays in deploy/docker-compose.test.yml
under profiles: [deploy-e2e-windows] for operator local use.
docs/deployment-vendor-matrix.md IIS + WinCertStore rows status
updated pending → operator-playbook.
Revises Bundle II frozen decision 0.4. Documented in
cowork/ci-pipeline-cleanup/decisions-revised.md.
NEW image-and-supply-chain job (Phases 7-9)
Top-level Ubuntu job (~3 min, parallel to go-build-and-test). Three
steps:
- Digest validity — every
@sha256:<digest>ref indeploy/**/*.{yml,Dockerfile*}must resolve on its registry. Closes the H-001 lying-field gap (H-001 verifies digest presence only — Bundle II shipped 11 fabricated digests that passed H-001 and faileddocker pullin CI). - Docker build smoke — all 4 Dockerfiles in the repo must build
(
Dockerfile,Dockerfile.agent,deploy/test/f5-mock-icontrol/Dockerfile,deploy/test/libest/Dockerfile). - OpenAPI ↔ handler operationId parity — every router route has
a matching
operationIdinapi/openapi.yamlor is documented in the newapi/openapi-handler-exceptions.yaml(8 documented exceptions at HEAD: SCEP + SCEP-mTLS wire-protocol endpoints).
Coverage PR-comment action (Phase 10)
Self-hosted alternative to Codecov / Coveralls. Posts per-package coverage table as a PR comment; updates in place on subsequent pushes. No paid SaaS dependency.
make verify-docs + make verify-deploy (Phase 11)
Three-tier convention now:
make verify— required pre-commit (gofmt + vet + lint + test)make verify-deploy— optional pre-push (digest validity + OpenAPI parity + Docker build smoke for server + agent)make verify-docs— required pre-tag (QA-doc Part-count + seed-count)
NEW docs/ci-pipeline.md (Phase 12)
Operator-facing guide to the on-push pipeline. Per-job deep-dive, guard inventory, threshold management, troubleshooting matrix, branch protection list to update.
Operator action required
After merge:
-
Update GitHub branch protection rule for
masterbranch. Required-checks list changes from 19 entries → 7:Go Build & TestFrontend BuildHelm Chart Validationdeploy-vendor-e2eimage-and-supply-chainAnalyze (go)Analyze (javascript-typescript)
-
(Optional) RAM-headroom verification on a test branch with the collapsed
deploy-vendor-e2ejob. If peak RSS > 12 GB on ubuntu-latest, fall back to bucketed matrix percowork/ci-pipeline-cleanup/decisions-revised.md.
Rollback
If RAM headroom proves insufficient or a guard misbehaves:
- Vendor matrix collapse (Phase 5): revert that one commit; fall back to the bucketed-matrix design (3 jobs × ~4 sidecars).
- staticcheck hard gate (Phase 3): revert that one commit; flip
continue-on-error: trueback temporarily until the new SA1019 site is closed. - All other phases are pure-additive or pure-extraction; reverting any single Phase commit restores the prior behavior.
Verification
make verify # pre-commit gate (existing)
make verify-deploy # optional pre-push (new)
make verify-docs # pre-tag (new)
bash scripts/ci-guards/*.sh # all 20 guards locally
bash scripts/check-coverage-thresholds.sh # only after coverage.out exists
All passing on HEAD.
Tag
Operator picks the exact v2.X.0 value. Bundle ships ~13 commits
on master after the prior bundle's closing commit (HEAD 1de61e91).