diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 1be811ea..6f4750c9 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -6238,7 +6238,7 @@ Both readings reach the same operational conclusion, which is the whole point of ## 1091. Hard-coded credential detection reads neither `.ps1` nor `.yaml`, and the entropy gate floors out on exactly the interesting secrets -> 🔢 **Re-scored 2026-08-20 -> P2.** Value **7/10** · Difficulty **3/10** · _quick win_. Both required gates remain blind to the class: .gitleaks.toml carries the default ruleset and five allowlist regexes with no low-entropy rule, bandit is a Python AST scanner, and the tracked tree still demonstrates the shape at docker/compose.yaml:158, so a first deployment could carry a defaulted database credential with both gates green. Difficulty 3 because the only lever is a declarative rules table plus an explicit reviewable allowlist and its false-positive tuning; no engine code, no store, nothing that passes through mypy. _(was 7/10 · 4/10.)_ +> ✅ **SHIPPED -- verified on main 2026-08-24 at `6e7952ff`.** PR 555 merged `04:38:46Z` and moved the check OUT of gitleaks to a tip-scoped lint: `tests/test_defaulted_credential_lint.py` walks **every tracked file** via `git ls-files` rather than a suffix list, so the `.yaml` / `.ps1` blind spot this row names is closed by construction rather than by enumerating extensions. It is wired into `tests/tooling_manifest.txt`, its allowlist is a literal one-entry `_EXEMPT_PATHS` holding only its own fixture file, and it asserts its own read count so a tree that became unreadable cannot pass as clean. The demonstrating shape at `docker/compose.yaml` is gone, replaced by a `NO DEFAULT, DELIBERATELY (BACKLOG #1091)` note carrying the reason beside it. **EXECUTED, and the gate is LIVE rather than merely green.** Run against main's tree with `--noconftest -o addopts=""` (stdlib + pytest only, so no venv is needed): **11 passed**. Planted-violation control: a `${VAR:-changeme}` line under a credential-shaped key reported `docker/compose.yaml:209 -> default 'changeme'` and turned the run **1 failed, 10 passed**; reverting returned it to 11. **Run first by the LANDER and reproduced independently here.** *Recorded because it nearly went the other way: TWO earlier plants of mine failed to trip it -- one malformed by shell quoting, one using a key name the rule deliberately does not match -- and either would have supported a false report that the gate was inert.* ***A control that cannot fire looks exactly like a gate that does not work.*** **Re-scored 2026-08-20 -> P2.** Value **7/10** · Difficulty **3/10** · _quick win_. Both required gates remain blind to the class: .gitleaks.toml carries the default ruleset and five allowlist regexes with no low-entropy rule, bandit is a Python AST scanner, and the tracked tree still demonstrates the shape at docker/compose.yaml:158, so a first deployment could carry a defaulted database credential with both gates green. Difficulty 3 because the only lever is a declarative rules table plus an explicit reviewable allowlist and its false-positive tuning; no engine code, no store, nothing that passes through mypy. _(was 7/10 · 4/10.)_ > > **Filed 2026-08-07 — not started.** The two required gates that are supposed to stop a committed credential have a **combined blind spot that covers most of the places a credential would actually live**. bandit is a Python AST scanner and does not parse `.ps1` or `.yaml` **at all**; gitleaks' operative generic rule is entropy-gated, so a **low-entropy** credential — `password`, `changeme`, a short site code — falls below the threshold and is not reported. > Verdict: build @@ -11189,7 +11189,7 @@ every worker session's handoff, which is the sentence the next session bases its ## 1232. `search_presets.owner` holds an `Identity.user_id` after #1225, so the column name is now misleading -> 🔢 **Re-scored 2026-08-20 -> P3.** Value **3/10** · Difficulty **4/10** · _fill-in_. The column is still named owner and is still the key in every preset path (store.py:1743, :8053), with 128 preset references across the four store modules. Value 3 because nothing behaves differently and the corrected comment already states which form the column holds, so the cost of leaving it is a reader's wrong inference; difficulty 4 because the rename is a cross-backend change tested on SQLite, PostgreSQL and SQL Server, which is the rubric's own rung-4 text. _(was 3/10 · 3/10.)_ +> ✅ **SHIPPED -- verified on main 2026-08-24 at `6e758a87`.** PR #544 (`a8f5d10a`, merged `2026-08-23T14:23:07Z`, ancestor of main) landed BOTH layers the amendments demand. Column: `owner_user_id` on `search_presets` across `store/store.py`, `store/postgres.py` and `store/sqlserver.py`. Parameter: `owner_user_id` on all four Protocol methods in `store/base.py` and on the sole non-test caller `api/app.py` (upsert, delete, layered get). **The required guard the row demanded BEFORE the change it guards exists** at `tests/test_search_presets.py:88`, `test_the_queue_lease_column_is_still_named_owner`, with an anti-vacuity pair so it cannot pass on a pre-change tree -- and the queue lease column IS intact, `postgres.py:275` still declaring `owner TEXT`, so the dangerous symbol-level rename this row warns about did not happen. **STATED LIMITS: no tests were executed** -- no venv in the verifying worktree, and the Postgres and SQL Server suites need real servers -- so this rests on reading merged blobs plus PR #544's CI, which was not itself inspected. The index NAME `ux_search_presets_owner_name` still contains "owner" on all three backends and was deliberately not renamed. **Re-scored 2026-08-20 -> P3.** Value **3/10** · Difficulty **4/10** · _fill-in_. The column is still named owner and is still the key in every preset path (store.py:1743, :8053), with 128 preset references across the four store modules. Value 3 because nothing behaves differently and the corrected comment already states which form the column holds, so the cost of leaving it is a reader's wrong inference; difficulty 4 because the rename is a cross-backend change tested on SQLite, PostgreSQL and SQL Server, which is the rubric's own rung-4 text. _(was 3/10 · 3/10.)_ > > **Filed 2026-08-12 -- a LEGIBILITY defect, not a correctness one, and it is filed separately on purpose.** After #1225 that column holds an `Identity.user_id`, not a username. The built branch corrected the column COMMENT (it read *"the owning username"*, which would have become a lie) and deliberately did **not** rename the column; the owner ratified deferring the rename. > **WHY IT IS ITS OWN ITEM RATHER THAN FOLDED INTO #1225, and this is the whole reason it is filable.** The two server backends carry an ADR 0064 schema hash (postgres **7** refs, sqlserver **9**) which **forces** a migration; SQLite carries **none** (**0** refs), so an existing developer database would silently NOT get it. A cosmetic rename therefore introduces a real **cross-backend asymmetry** -- and those are precisely the two backends that **skip in a local run**, so the asymmetry would first appear in CI, attributed to whoever next touched the table. @@ -14387,7 +14387,7 @@ blind window is about a day rather than open-ended. ## 1323. the crypto-inventory gate enumerates a store-only seam set, so first-party TLS seams outside it are invisible to it -> 🔢 **Filed 2026-08-22 - not started.** The required crypto-inventory gate is green while structurally unable to see a real first-party TLS seam. `pipeline/alert_sinks.py` imports `smtplib` and `config.tls_policy`, and the gate's seam set names store modules only, so no import it makes can trigger a review. +> ✅ **SHIPPED -- verified on main 2026-08-24 at `6e758a87`.** PR #537 (`df8acc95`, merged `2026-08-23T08:21:39Z`, ancestor of main) added `messagefoundry.config.tls_policy` to `CRYPTO_SEAM_MODULES` in `scripts/security/crypto_inventory_check.py`, beside the five store entries, with a comment naming this row. **CITATION TRAP, recorded so the next reader does not repeat it: PR 537's subject bundles `#1319`, `#1322`, `#1323` and `#1331`, so a subject grep for this number finds NOTHING.** It was located by `git log -S` on the seam symbol, and confirmed with `git grep "BACKLOG #1323"` against a `#1322` positive control proving the needle form works. **STATED LIMITS: the gate script was run but the two pytest pins were NOT executed, and no mutation was made to prove they would redden** -- so their must-fire direction rests on reading their assertions. The two ASVS cells whose prose this row says overclaims coverage were not checked; that record is vaulted and belongs to the tracker seat. **Filed 2026-08-22.** The required crypto-inventory gate is green while structurally unable to see a real first-party TLS seam. `pipeline/alert_sinks.py` imports `smtplib` and `config.tls_policy`, and the gate's seam set names store modules only, so no import it makes can trigger a review. > Verdict: build > Closing-act: code