Commit 6046c0f
authored
fix(config): replace TOKEN_SIGNING_SECRET entropy heuristic (#30)
* fix(config): replace TOKEN_SIGNING_SECRET entropy heuristic
The previous distinct-byte check was structurally broken in two
directions:
- False positive: a real `openssl rand -hex 32` value is drawn
from a 16-symbol alphabet; the expected number of distinct
chars in 64 draws is ~15.75, so a genuinely random secret
intermittently fell below the < 16 threshold and was rejected
at startup under PROD_MODE=true.
- False negative: literals like
`0123456789abcdef0123456789abcdef` have exactly 16 distinct
chars and passed the gate despite trivially repeating with
period 16. A patterned secret with no actual entropy past the
first 16 bytes would clear the check.
Replaced with a three-part shape check on the raw secret bytes:
1. All-same byte (period 1) → "is N copies of a single byte".
2. Repeating period < len(b) → "repeats with period P". Catches
both the period-16 false-pass above and shorter shapes like
`abcabc…`.
3. Tiny alphabet (< 8 distinct values) → catches the
`aaaa…b`-shaped near-miss and uneven-run-length shapes
(`aaaaabbbbbcccccddddd…`) that defeat both the period and
all-same checks. Threshold of 8 is the most defensive floor
with zero practical false-positive rate on real random
output: 32 hex chars over a 16-symbol alphabet expect ~14
distinct, base64 / raw expect more.
The new check fires at the same two sites as the old one — the
warn path during secret parsing, and the hard-fail path under
PROD_MODE — so dev / single-replica deployments that intentionally
use a weak secret keep working under PROD_MODE=false with a
startup warning.
Tests:
- TestLoad_SecretWeaknessWarning_PeriodicRepeat is the headline
regression for the famous false-pass: rejects
`0123456789abcdef0123456789abcdef`.
- TestLoad_SecretWeaknessWarning_TinyAlphabet is a 4-case
boundary table: 2-distinct rejects, 7-distinct rejects (just
below the floor), 8-distinct passes (at the floor, true
8-symbol non-periodic fixture), 15-distinct passes.
- TestLoad_SecretWeaknessWarning_NonPeriodic covers the
false-positive direction with frozen `openssl rand -hex 32`,
base64-shaped, and alphanumeric-32 samples.
- TestWeakSecretReason_FreshRandomNeverFlags is a 9000-sample
experiment per CI run (1000 iterations × 3 encodings × 3
raw-byte lengths) demonstrating zero false-positives on fresh
crypto/rand output across raw, hex, and base64 shapes at
lengths 32 / 48 / 64.
- TestLoad_ProdMode_BlocksWeakSecret is now table-driven (3
shapes × 2 modes = 6 sub-tests).
- The setAllRequired test fixture's TOKEN_SIGNING_SECRET moved
from the literal famous false-pass to a non-periodic
real-random hex sample so every existing test runs against a
secret the new gate accepts.
- distinctByteCount removed entirely.
Docs aligned: specs.md, README.md, and docs/configuration.md
all describe the new semantics and point at
manifests/scripts/generate-signing-secret.sh as the canonical
generator path.
* docs: name the third weak-secret class (tiny alphabet) in prose
The validator rejects three weak-secret shapes — all-same byte,
short repeating period, AND tiny alphabet (< 8 distinct values).
The prose in README, docs/configuration.md, and specs.md
described only the first two; the tiny-alphabet floor (added in
this PR) was visible only via the inline Go code. A reader of
the docs alone now sees the full contract and the rationale for
each class.
* docs(README): correct generate-signing-secret.sh output description
The Demo stack section described the script as emitting "a 32-byte
random hex string". The script actually emits a 64-character
cryptographically-random base64 string (it pipes
`openssl rand -base64 48` through tr-d and head -c 64). Same
ballpark of bits of entropy, different encoding.1 parent 9dc12d1 commit 6046c0f
5 files changed
Lines changed: 312 additions & 102 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
136 | | - | |
| 136 | + | |
137 | 137 | | |
138 | 138 | | |
139 | 139 | | |
| |||
258 | 258 | | |
259 | 259 | | |
260 | 260 | | |
261 | | - | |
262 | | - | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
263 | 264 | | |
264 | 265 | | |
265 | 266 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
181 | 181 | | |
182 | 182 | | |
183 | 183 | | |
184 | | - | |
185 | | - | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
186 | 187 | | |
187 | 188 | | |
188 | 189 | | |
| |||
248 | 249 | | |
249 | 250 | | |
250 | 251 | | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
265 | 264 | | |
266 | 265 | | |
267 | 266 | | |
| |||
530 | 529 | | |
531 | 530 | | |
532 | 531 | | |
533 | | - | |
534 | | - | |
535 | | - | |
536 | | - | |
537 | | - | |
538 | | - | |
539 | | - | |
540 | | - | |
541 | | - | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
542 | 540 | | |
543 | 541 | | |
544 | | - | |
545 | | - | |
| 542 | + | |
| 543 | + | |
546 | 544 | | |
547 | 545 | | |
548 | 546 | | |
| |||
567 | 565 | | |
568 | 566 | | |
569 | 567 | | |
570 | | - | |
571 | | - | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
572 | 608 | | |
573 | | - | |
| 609 | + | |
574 | 610 | | |
575 | 611 | | |
576 | 612 | | |
577 | | - | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
578 | 617 | | |
579 | 618 | | |
580 | | - | |
| 619 | + | |
581 | 620 | | |
582 | 621 | | |
583 | 622 | | |
| |||
0 commit comments