@@ -9,6 +9,117 @@ The format is based on the regulated environment requirements:
99
1010---
1111
12+ ## [ 2026-04-25 06:30] - ` gitleaks-install ` now wires the local pre-commit hook
13+
14+ ** Author:** Erick Bourgeois
15+
16+ ### Changed
17+ - ` Makefile ` (` gitleaks-install ` ): after installing the binary, invokes
18+ ` install-git-hooks ` so a single ` make gitleaks-install ` leaves the
19+ developer with both the tool AND the local secret-scanning hook in
20+ place. Previously the two targets were independent and the hook had
21+ to be set up via a second command.
22+ - ` Makefile ` (` install-git-hooks ` ): no longer depends on
23+ ` gitleaks-install ` (would create a circular dependency now that
24+ ` gitleaks-install ` calls it). The hook only invokes gitleaks at
25+ * commit* time, so install-time independence is correct.
26+ - ` Makefile ` (` install-git-hooks ` ): now idempotent and non-destructive.
27+ A ` 5spot-managed-gitleaks-hook ` sentinel embedded in the hook lets
28+ re-runs detect "already installed" and leave the file alone. If a
29+ custom pre-commit hook is found (no sentinel), it is preserved at
30+ ` .git/hooks/pre-commit.bak ` rather than overwritten silently.
31+ - ` Makefile ` (hook content): the generated hook now checks for
32+ gitleaks on PATH and emits a clear "run make gitleaks-install"
33+ message if it is missing, instead of failing with a cryptic
34+ "command not found".
35+
36+ ### Why
37+ Onboarding friction: developers ran ` make gitleaks-install ` expecting
38+ the secret scan to fire on commit, then committed secrets because the
39+ hook had never been wired. Banking-environment requirement (no
40+ secrets in commits) was therefore enforced only by CI — too late.
41+ Wiring hook setup into the install target makes the local guard the
42+ default for every dev, while idempotency + backup keeps re-runs safe.
43+
44+ ### Impact
45+ - [ ] Breaking change
46+ - [ ] Requires cluster rollout
47+ - [x] Config change only (developer tooling)
48+ - [ ] Documentation only
49+
50+ ---
51+
52+ ## [ 2026-04-24 15:00] - Security audit remediation: grace period, retry-count poisoning, input bounds
53+
54+ ** Author:** Erick Bourgeois
55+
56+ ### Changed
57+ - ` src/reconcilers/helpers.rs ` (` check_grace_period_elapsed ` ): guard
58+ against negative ` elapsed ` durations produced by clock-skew (NTP step,
59+ VM freeze-thaw, backward wall-clock adjustment). The prior comparison
60+ ` elapsed.num_seconds() >= timeout.as_secs() as i64 ` silently returned
61+ ` false ` when ` elapsed ` was negative, potentially bypassing the
62+ graceful-drain window entirely. Negative elapsed is now treated as
63+ "timeout reached" so the reconciler forces progress rather than
64+ stalling on a misbehaving clock.
65+ - ` src/reconcilers/helpers.rs ` (` error_policy ` ): replace
66+ ` ctx.retry_counts.lock().unwrap_or_else(PoisonError::into_inner) `
67+ with an explicit ` match ` that aborts the error-policy pass and
68+ requeues after ` ERROR_REQUEUE_SECS ` on poison. The prior pattern
69+ silently recovered a potentially-inconsistent map and continued
70+ mutating it, corrupting the exponential-backoff schedule for every
71+ subsequent error.
72+ - ` src/reconcilers/helpers.rs ` : new ` validate_cluster_name() ` and
73+ ` validate_kill_if_commands() ` with bounds from ` src/constants.rs ` .
74+ Called early in ` reconcile_inner ` (defence-in-depth against clusters
75+ that have not enabled the ValidatingAdmissionPolicy) and re-called in
76+ ` add_machine_to_cluster ` before touching CAPI.
77+ - ` src/constants.rs ` : new ` MAX_CLUSTER_NAME_LEN = 63 ` (RFC-1123 DNS
78+ label — the effective CAPI cluster-name cap), plus
79+ ` MAX_KILL_IF_COMMANDS_COUNT = 100 ` and ` MAX_KILL_IF_COMMAND_LEN = 256 ` .
80+ - ` src/crd.rs ` : attach bounded JSON-schema generators
81+ (` cluster_name_schema ` , ` kill_if_commands_schema ` ) so the generated
82+ CRD enforces the same limits at the kube API level.
83+ - ` src/metrics.rs ` : replace ` unreachable!() ` in the metric-registration
84+ fallback constructors with ` panic!() ` carrying
85+ ` FALLBACK_METRIC_BUG_MSG ` — a pointed diagnostic that identifies the
86+ offending metric name instead of a generic "entered unreachable code"
87+ message.
88+ - ` deploy/admission/validatingadmissionpolicy.yaml ` : add CEL expressions
89+ 1b/1c/1d/1e mirroring the new runtime validators — ` clusterName `
90+ length/charset, ` killIfCommands ` count/per-entry-length — so invalid
91+ specs are rejected at admission instead of only at reconciliation
92+ time.
93+ - ` src/reconcilers/helpers_tests.rs ` : 20 new tests covering the grace-
94+ period clock-skew fix, ` validate_cluster_name ` (happy path, empty,
95+ over-cap, control chars, non-ASCII), and ` validate_kill_if_commands `
96+ (None/empty/typical/cap-boundary/over-cap/empty-entry).
97+ - ` deploy/crds/scheduledmachine.yaml ` : regenerated via `cargo run --bin
98+ crdgen` to pick up the new schema constraints.
99+ - ` docs/src/reference/api.md ` : regenerated via ` make crddoc ` .
100+
101+ ### Why
102+ Findings from the deep security audit of the codebase (see
103+ conversation transcript 2026-04-24). Three issues were actionable: a
104+ clock-skew bypass of the graceful-drain window (critical; violates the
105+ contract of graceful shutdown under SOX §404 / NIST AC-3), an
106+ unbounded ` killIfCommands ` that could balloon Prometheus label
107+ cardinality and pin reclaim-agent CPU (high; DoS vector), and
108+ silent recovery from a poisoned retry-count mutex (medium; corrupts
109+ the exponential-backoff schedule). Cluster-name was also unbounded;
110+ the 63-char cap matches the effective CAPI constraint (cluster names
111+ flow into DNS labels downstream). Metric ` unreachable!() ` is a
112+ cosmetic bug-diagnostic improvement.
113+
114+ ### Impact
115+ - [ ] Breaking change
116+ - [x] Requires cluster rollout (new CRD schema constraints; existing
117+ CRs that violate them will be rejected on next ` kubectl apply ` )
118+ - [ ] Config change only
119+ - [ ] Documentation only
120+
121+ ---
122+
12123## [ 2026-04-23 08:00] - Fix vexctl-install Linux path (wrong asset filename)
13124
14125** Author:** Erick Bourgeois
0 commit comments