@@ -9,6 +9,76 @@ The format is based on the regulated environment requirements:
99
1010---
1111
12+ ## [ 2026-04-25 18:00] - Phase 2 of security audit: finalizer cleanup force-remove on PDB stall
13+
14+ ** Author:** Erick Bourgeois
15+
16+ ### Changed
17+ - ` src/reconcilers/helpers.rs ` (` handle_deletion ` ): refactor the timeout
18+ branch from ` tokio::time::timeout(...).await.map_err(...)?? ` (which
19+ silently propagated the ` TimeoutError ` and ** prevented** the finalizer
20+ from being removed) into an explicit 3-arm match over a new
21+ ` CleanupOutcome ` enum. The default mode now force-removes the
22+ finalizer on timeout so namespace deletion is unblocked, surfaces a
23+ ` FinalizerCleanupTimedOut ` Warning event on the SM, and increments
24+ ` fivespot_finalizer_cleanup_timeouts_total ` . A real cleanup error (as
25+ opposed to a timeout) still propagates and is retried — the finalizer
26+ is kept in place so a transient API failure does not orphan
27+ resources.
28+ - ` src/reconcilers/helpers.rs ` : new pure helpers ` run_cleanup_with_timeout `
29+ (returns ` CleanupOutcome::{Completed, Failed(err), TimedOut} ` ) and
30+ ` build_finalizer_timeout_event ` . Both are unit-testable without the
31+ kube API; the timeout test runs in microseconds via
32+ ` #[tokio::test(start_paused = true)] ` .
33+ - ` src/reconcilers/scheduled_machine.rs ` (` Context ` ): new
34+ ` force_finalizer_on_timeout: bool ` field defaulting to ` true ` , plus a
35+ ` with_force_finalizer_on_timeout(bool) ` builder for ` main.rs ` to
36+ override from CLI/env. Strict-cleanup mode (` false ` ) keeps the
37+ finalizer and propagates ` TimeoutError ` so reconciliation retries —
38+ only safe when an external sweep garbage-collects stuck SMs.
39+ - ` src/main.rs ` : new ` --force-finalizer-on-timeout ` flag (env
40+ ` FORCE_FINALIZER_ON_TIMEOUT ` , default ` true ` ) wired through ` Context ` .
41+ - ` src/metrics.rs ` : new ` FINALIZER_CLEANUP_TIMEOUTS_TOTAL ` counter +
42+ ` record_finalizer_cleanup_timeout() ` helper + label-less
43+ ` fallback_counter ` constructor. Documented as an operator-alert
44+ signal for orphan-resource detection.
45+ - ` deploy/deployment/deployment.yaml ` : added ` FORCE_FINALIZER_ON_TIMEOUT `
46+ env var with ` value: "false" ` (strict-cleanup mode) per operational
47+ preference; the binary default remains ` true ` . Block-comment in the
48+ manifest documents the trade-off and references the troubleshooting
49+ runbook.
50+ - ` docs/src/operations/troubleshooting.md ` : new "Orphan resources after
51+ finalizer timeout" section with the runbook (find orphan Machines via
52+ ownerRef walk, inspect bootstrap/infra refs, cascading delete via
53+ Machine, prevention guidance).
54+ - ` src/reconcilers/helpers_tests.rs ` / ` src/metrics_tests.rs ` : 10 new
55+ tests covering ` run_cleanup_with_timeout ` (Completed/Failed/TimedOut),
56+ ` build_finalizer_timeout_event ` (severity, reason, action,
57+ note-content invariants), ` Context.force_finalizer_on_timeout `
58+ defaulting, and the metric-increments-on-call contract.
59+
60+ ### Why
61+ Finding F-007 from the 2026-04-25 adversarial security audit (filed in
62+ ` ~/dev/roadmaps/5spot-security-audit-2026-04-25.md ` , Phase 2). A
63+ namespace-tenant with ` create pods ` + ` create poddisruptionbudgets ` —
64+ common tenant grants — could plant a ` minAvailable: 999 ` PDB on a
65+ workload they own, schedule a machine on the same node, then delete
66+ the SM. Drain blocks indefinitely on the impossible eviction; with the
67+ old code the finalizer was never removed, the SM was stuck with
68+ ` deletionTimestamp ` , and namespace deletion stalled. The fix unblocks
69+ namespace deletion in the default mode while preserving
70+ strict-cleanup-or-stall semantics for operators with an external sweep.
71+
72+ ### Impact
73+ - [ ] Breaking change
74+ - [ ] Requires cluster rollout
75+ - [x] Config change only (new env var; behaviour change for clusters
76+ that hit the timeout path — they'll now succeed at deletion
77+ where they previously stalled)
78+ - [ ] Documentation only
79+
80+ ---
81+
1282## [ 2026-04-25 06:30] - ` gitleaks-install ` now wires the local pre-commit hook
1383
1484** Author:** Erick Bourgeois
0 commit comments