Skip to content

fix(startup): the TLS-floor refusal named a config key the loader rejects (BACKLOG #1026) - #593

Open
wshallwshall wants to merge 2 commits into
mainfrom
claude/builder-1-1026-refusal-key
Open

fix(startup): the TLS-floor refusal named a config key the loader rejects (BACKLOG #1026)#593
wshallwshall wants to merge 2 commits into
mainfrom
claude/builder-1-1026-refusal-key

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

The ASVS 12.1.1 startup refusal told operators to set [api].public_origin -- a key ADR 0118 relocated, and the loader rejects it. So the remediation the gate hands out fails on the operator's next start. Now names [security].web_console_public_address, with the assertion pinned against _RELOCATED_TO_SECURITY itself rather than a string literal, so a future relocation can't drift the two apart silently.

Item #1026 stays OPEN -- this is one code limb of a multi-limb row, not a closure. Ledger progress note in a companion PR.

A second instance found by the branch's own test, fixed alongside: the console-on arm hits an earlier serve_ui-gated refusal carrying the identical defect.

Deliberately incomplete: the matching docs/CONFIGURATION.md paragraph is not in this branch -- the collision gate correctly refused it (Builder 2 holds uncommitted changes to that file), so it was asked for rather than overridden. Follows separately, or lands with Builder 2's work if that's cleaner.

Verification: 70 passed in test_api_tls. ruff/mypy strict clean, each run separately. Message mutation-proved: reverting it reds two tests; restored, hash-verified. Full suite not run.

…ects (BACKLOG #1026)

The ASVS 12.1.1 refusal told the operator to set `[api].public_origin`. ADR 0118 relocated that key
to `[security].web_console_public_address` and REJECTS the old spelling as file or env input
(`_RELOCATED_TO_SECURITY` in config/settings.py). So the gate handed out a remediation that fails:
do what it says, and the next start dies on "unrecognized config key(s)".

A HARD REFUSAL NAMING AN UNUSABLE FIX IS WORSE THAN ONE NAMING NONE. It costs a restart cycle to
discover, and it reads as authoritative because it comes from the gate itself. The security limb of
this row landed already -- the control is no longer inert -- and this is the actionability limb that
did not.

PINNED AGAINST THE RELOCATION MAP, NOT AGAINST A STRING. Asserting the message contains some
remembered spelling would pass just as well after a future relocation moved the key again, and the
two would drift apart silently -- which is the defect this test exists to stop. The expected key is
READ FROM `_RELOCATED_TO_SECURITY[("api", "public_origin")]`, and the refusal block is located by the
control it names rather than by a line number, because the row's own coordinates had already drifted
(it cites settings.py:4096-4099; the map is at :4117).

A SECOND REFUSAL HAD THE SAME DEFECT AND MY OWN TEST FOUND IT. The console-ON arm hits an EARLIER,
`serve_ui`-gated refusal that also instructed "Set [api].public_origin". It is fixed here too: an
operator with the console on would otherwise still be handed the unusable key, and #1026 is
specifically about actionability.

DELIBERATELY NOT WIDENED, and named rather than left silent. Six messages in `__main__.py` mention
`[api].public_origin` to an operator. I fixed the two that give an INSTRUCTION. The other four only
DESCRIBE a value (`:1906`, `:1919`, `:1931`, `:2066`) -- an operator still cannot act on them, and
`:1931` also names `[api].serve_ui`, a second relocated key. That is the same class and a wider
sweep than this row scopes, so it is reported rather than folded in.

TWO EXISTING ASSERTIONS DELIBERATELY FLIPPED. `test_phi_behind_a_declared_terminator_refuses_...`
and `test_the_refusal_does_not_depend_on_the_console` asserted `"public_origin" in err` -- they
pinned the BROKEN remediation, so a correct message would have failed them. Both now assert the key
the loader accepts. Same payloads, same postures, opposite expectation on one string; no case
stopped being driven.

MUTATION: revert the message to the relocated spelling -> the pin test AND the console-OFF test both
fail. Restored from a byte copy, hash-verified identical.

DOC LIMB NOT DONE, AND NOT FORGOTTEN. docs/CONFIGURATION.md still describes the setting as
console-scoped ("with the console served, serve exits 2 until ..."), which is now incomplete: a PHI
instance behind a declared terminator under `enforce` exits 2 with the console OFF as well. THE
COLLISION GATE REFUSED THE EDIT -- Builder 2 holds uncommitted changes to that file in
builder-2-58aee2 -- so I asked them rather than overriding, offering to take it, hand it over, or
wait. The valuable half lands here; the doc paragraph follows once that file is free.

VERIFIED, scope named:
  pytest 70 passed, tests/test_api_tls.py
  ruff format --check, ruff check, mypy -- run separately, each with its own exit code, all clean
  NOT a full-suite run

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant