mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-12 22:18:55 +00:00
Bundle 0.7 (Coverage Audit Closure): cmd/agent key-handling regression coverage — C-008 closed
Phase 0 of the 2026-04-27 coverage-audit closure plan surfaced cmd/agent/keymem.go with two security-critical functions at 0.0% / 11.1% line coverage: - marshalAgentKeyAndZeroize: zeros the DER backing buffer after PEM encode - ensureAgentKeyDirSecure: locks the agent key directory to 0o700 Both ship as defense-in-depth for agent private-key memory hygiene per Bundle 9 / Audit L-002 + L-003 (agent edition), but had ZERO regression tests. This commit adds cmd/agent/keymem_test.go (~510 LoC, 17 top-level test funcs): marshalAgentKeyAndZeroize coverage: - happy path (DER decodes, callback invoked once) - nil key (asserts onDER NEVER invoked) - onDER returns error (errors.Is propagation) - DER backing buffer zeroized after return INVARIANT (the critical assertion) - DER buffer zeroized even on onDER-error path - contract-violator defense (caller retains slice -> reads zeros) ensureAgentKeyDirSecure coverage (13-row table-driven): - empty/dot/root refused with documented error wrap - creates with 0700 (incl. nested ancestors) - existing 0700 noop short-circuit - tighten 0750/0755/0777 -> 0700 - accept existing 0500/0400 (mode&0o077==0 branch, no chmod) - filepath.Clean normalization (trailing slash + dot prefix) - PathIsAFile (documents current behavior; not a bug per call sites) - Idempotent - Concurrent (-race clean across 8 goroutines) - Stat error propagated (root-skips cleanly on non-root CI) - Mkdir error propagated (root-skips cleanly on non-root CI) - Chmod error propagated (linux-only via /sys read-only fs) - Format-includes-cleaned-path debuggability assertion Plus end-to-end smoke replaying cmd/agent/main.go's composition flow. Coverage delta: cmd/agent/keymem.go::marshalAgentKeyAndZeroize 0.0% -> 85.7% (>=85% gate met) cmd/agent/keymem.go::ensureAgentKeyDirSecure 11.1% -> 94.4% (>=85% gate met) cmd/agent overall 54.3% -> 57.7% (+3.4pp) The cmd/agent overall >=75% stretch target is unachievable from a keymem-only test file because the package's bulk (Run, main, executeCSRJob, executeDeploymentJob, verifyAndReportDeployment) is unrelated to key-handling and dominates the denominator. Tracked as a follow-on cmd/agent flow-test bundle. Verification: go test -short ./cmd/agent/... PASS go test -race -count=3 ./cmd/agent/... PASS, 0 races gofmt -l cmd/agent/keymem_test.go clean go vet ./cmd/agent/... clean staticcheck ./cmd/agent/... clean Audit deliverables: coverage-audit-2026-04-27/findings.yaml: C-008 status open -> closed coverage-audit-2026-04-27/gap-backlog.md: closure log entry + H-006 partial coverage-audit-2026-04-27/coverage-report.md: Bundle 0.7 closure block appended coverage-audit-2026-04-27/coverage-matrix.md: cmd/agent row 'NOT MEASURED' -> 57.7% coverage-audit-closure-plan.md: Bundle 0.7 checklist ticked CHANGELOG.md: [unreleased] Bundle 0.7 entry Bundle J (ACME failure-mode coverage) unblocked.
This commit is contained in:
+23
-1
@@ -2,7 +2,29 @@
|
||||
|
||||
All notable changes to certctl are documented in this file. Dates use ISO 8601. Versions follow [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [unreleased] — 2026-04-26
|
||||
## [unreleased] — 2026-04-27
|
||||
|
||||
### Bundle 0.7 (Coverage Audit Closure): cmd/agent key-handling regression coverage — C-008 closed
|
||||
|
||||
> Phase 0 of the 2026-04-27 coverage audit's closure plan triggered a halt-condition: `cmd/agent/keymem.go`'s two security-critical functions were at 0.0% / 11.1% line coverage despite being defense-in-depth for agent private-key memory hygiene (Bundle 9 / Audit L-002 + L-003 — agent edition). Bundle 0.7 was inserted before Bundle J as mandatory; this entry closes finding **C-008** (`CRTCTL-COVAUDIT-2026-04-27-0034`).
|
||||
|
||||
`cmd/agent/keymem_test.go` (~510 LoC, 17 top-level test functions) ships:
|
||||
|
||||
- **`marshalAgentKeyAndZeroize` regression coverage** — happy path, nil-key guard (asserts `onDER` is NOT invoked), upstream error propagation via `errors.Is`, and the **DER-buffer-zeroized-after-return invariant** verified observably: capture the slice header inside `onDER` (sharing the backing array, NOT a deep copy), then assert every byte reads `0x00` after the function returns. Pinned for both the happy path AND the `onDER`-error path. A future refactor that drops the `defer clear(der)` line would break the test even if the simpler assertions still pass. Also adds a "contract violator" defense test: a buggy caller that retains the slice past `onDER` reads zeros, not the private scalar.
|
||||
- **`ensureAgentKeyDirSecure` regression coverage** — 13-row table-driven matrix covering empty/dot/root refuse with documented error wrap, create-with-0700, create-nested-0700, accept-existing-0700 (no-op short-circuit), tighten 0750/0755/0777 to 0700, accept-existing-0500/0400 (owner-only-no-write `mode&0o077 == 0` branch, no chmod), `filepath.Clean` normalization (trailing slash + dot prefix). Plus PathIsAFile (documents current behavior — function chmod's a file path silently, not a correctness bug per current call sites but a hardening candidate filed against any future refactor), Idempotent, Concurrent (`-race` clean across 8 goroutines), Stat/Mkdir/Chmod error-propagation paths (root-required ones `t.Skip` cleanly on non-root CI rather than being absent), and Format-includes-cleaned-path debuggability assertion.
|
||||
- **End-to-end smoke** (`TestKeymem_AgentMainFlowSmoke`) replaying `cmd/agent/main.go`'s composition: `ensureAgentKeyDirSecure` → `marshalAgentKeyAndZeroize`.
|
||||
|
||||
Coverage delta:
|
||||
|
||||
| | Pre-Bundle-0.7 | Post-Bundle-0.7 | Gate | Met? |
|
||||
|---|---|---|---|---|
|
||||
| `cmd/agent/keymem.go::marshalAgentKeyAndZeroize` | 0.0% | **85.7%** | ≥85% | ✓ |
|
||||
| `cmd/agent/keymem.go::ensureAgentKeyDirSecure` | 11.1% | **94.4%** | ≥85% | ✓ |
|
||||
| `cmd/agent` overall | 54.3% | **57.7%** (+3.4pp) | (≥75% stretch) | △ partial |
|
||||
|
||||
Verification: `go test -race -count=3 ./cmd/agent/...` clean (0 races); `gofmt -l` clean; `go vet ./cmd/agent/...` clean; `staticcheck ./cmd/agent/...` clean. The cmd/agent overall ≥75% stretch target is unachievable from a keymem-only test file (the package's bulk — `Run`, `main`, `executeCSRJob`, `executeDeploymentJob`, `verifyAndReportDeployment` — is unrelated to key-handling and dominates the denominator); the remaining lift is tracked as a follow-on cmd/agent flow-test bundle.
|
||||
|
||||
Audit deliverable updates: `coverage-audit-2026-04-27/findings.yaml` flips C-008 `open` → `closed` with closure note + post-Bundle coverage numbers; `gap-backlog.md` adds a closure log entry and partial-closure note on H-006; `coverage-matrix.md` updates the cmd/agent row from "NOT MEASURED" to 57.7%; `coverage-report.md::Phase 0 Results` appends a Bundle 0.7 closure block with the coverage delta table and pinned-invariant list; `coverage-audit-closure-plan.md` checklist ticks Bundle 0.7. **Bundle J (ACME failure-mode coverage) unblocked.**
|
||||
|
||||
### Bundle H (M-029 Drain — AUDIT FULLY CLOSED): 1 audit finding closed across 3 passes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user