key-gaps: the key regex was blind to digits, inventing missing secrets #69

Merged
admin_emi merged 2 commits from fix/key-gaps-digit-regex into dev 2026-07-24 22:59:13 +00:00
Owner

grep -oE "^[A-Z_]+=" cannot match a key name containing a digit.

This estate has exactly six such names — all the *_S3_* keys. So a prod audit returned 26 keys against 32 real ones, and reported the S3 and lake credentials as missing from both live hosts.

They were present the whole time. The phantom was independently reproduced twice by re-running the same pattern, which is precisely what made it convincing, and it was briefly recorded as one of two root causes of the ERA5 lake being unqueryable (#56). That issue has one cause: the missing duckdb-lake image.

An audit that under-reports is worse than no audit. A missing-secret finding sends someone to provision a credential that already exists — and in a rotation tool, it would justify writing over one.

Fixed to ^[A-Z][A-Z0-9_]*= in both the skill and key_gaps.py's docstring. The match still stops at the =, so no value is read — that property is the entire reason this is a grep rather than a parser, and it is preserved.

Centralis's secrets_gaps carried the same bug and is fixed separately in emi/centralis#8, with a regression test.

Also ignores .claude/worktrees/, after the first commit here swept in two other sessions' live checkouts as embedded git repositories. This repo already has a documented history of parallel sessions colliding through shared checkouts; this is the same hazard wearing a different hat.

`grep -oE "^[A-Z_]+="` cannot match a key name containing a digit. This estate has exactly six such names — all the `*_S3_*` keys. So a prod audit returned **26 keys against 32 real ones**, and reported the S3 and lake credentials as missing from both live hosts. **They were present the whole time.** The phantom was independently reproduced twice by re-running the same pattern, which is precisely what made it convincing, and it was briefly recorded as one of two root causes of the ERA5 lake being unqueryable (#56). That issue has **one** cause: the missing `duckdb-lake` image. An audit that under-reports is worse than no audit. A missing-secret finding sends someone to provision a credential that already exists — and in a rotation tool, it would justify writing over one. Fixed to `^[A-Z][A-Z0-9_]*=` in both the skill and `key_gaps.py`'s docstring. The match still stops at the `=`, so no value is read — that property is the entire reason this is a grep rather than a parser, and it is preserved. Centralis's `secrets_gaps` carried the same bug and is fixed separately in `emi/centralis#8`, with a regression test. Also ignores `.claude/worktrees/`, after the first commit here swept in two other sessions' live checkouts as embedded git repositories. This repo already has a documented history of parallel sessions colliding through shared checkouts; this is the same hazard wearing a different hat.
admin_emi added 2 commits 2026-07-24 22:57:55 +00:00
`grep -oE "^[A-Z_]+="` cannot match a key name containing a digit. This estate
has exactly six such names — all the *_S3_* keys — so a prod audit returned 26
keys against 32 real ones, and reported the S3 and lake credentials as missing
from both live hosts.

They were present the whole time. The phantom was independently reproduced
twice by re-running the same pattern, which is what made it convincing, and it
was briefly recorded as one of two root causes of the lake being unqueryable
(#56). That issue has one cause: the missing duckdb-lake image.

An audit that under-reports is worse than no audit. A missing-secret finding
sends someone to provision a credential that already exists, and in a rotation
tool it would justify writing over one.

Fixed to `^[A-Z][A-Z0-9_]*=` in both the skill and key_gaps.py's docstring. The
match still stops at the `=`, so no value is read — that property is the reason
this grep exists rather than a parser.

Centralis's secrets_gaps carried the same bug and is fixed separately, with a
regression test.

Claude-Session: https://claude.ai/code/session_0182KTMrsTHJc3TcewCatJFY
Drop accidentally-committed worktrees; ignore .claude/worktrees
All checks were successful
PR build (required check) / changes (pull_request) Successful in 7s
secrets-guard / encrypted (pull_request) Successful in 6s
shell-lint / shellcheck (pull_request) Successful in 9s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-backend (pull_request) Successful in 44s
PR build (required check) / gate (pull_request) Successful in 3s
f4313b5d87
The previous commit swept in .claude/worktrees/city-resolver and
.claude/worktrees/thermograph-mentions as embedded git repositories. Those are
other Claude sessions' live checkouts and have no business in this tree.

Ignoring the directory so `git add -A` cannot do it again — the repo already
has a documented history of parallel sessions colliding through shared
checkouts, and this is the same hazard wearing a different hat.

Claude-Session: https://claude.ai/code/session_0182KTMrsTHJc3TcewCatJFY
admin_emi merged commit 1c763a61c5 into dev 2026-07-24 22:59:13 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Jinemi/thermograph#69
No description provided.