Repository navigation
fix(guard): cover the host's allocated OmniRoute gateway ports - #1244
Merged
seathatflowsinourveins merged 2 commits intoOct 17, 2026
Merged
Conversation
The secret-path guard refused gateway management requests only on the fixed ports 20128, 20129, 21128 and 21129. A host's port allocation (#1180) can move the gateway: this host's gitignored adoption/hosts file sets NS_PORT_GATEWAY=23128, NS_PORT_GATEWAY_WS=23129 and NS_PORT_GATEWAY_EMBED_WS=23131, so management requests to 23128 passed unchecked. The guard now reads the allocation once at start from the maps the port tooling reads (observability_config.py load_service_ports()): every adoption/hosts/*.json under CLAUDE_PROJECT_DIR and the guard's own checkout, NS2604_HOST_FILE, and the installed new-wsl-native-stack/.service-ports.json. Every NS_PORT_GATEWAY* port is covered; NS_PORT_GATEWAY takes the rows of 21128, the other gateway keys none, and a fixed port keeps its own rows (a host file never adds a row to it). It fails closed: sources only add ports, a non-JSON file still covers its "NS_PORT_GATEWAY*": "D" pairs, and an unreadable, non-regular or absent file leaves the fixed ports covered. docs/secret-storage.md names the source; the shifted upstream-surface-dispositions locators, SHA256SUMS and the evidence manifest are updated. Regression tests fail on caf9ad7. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Folds the CC verdict CHANGES_REQUESTED at 3dd235c (B1-B3, C-G). - B1: test_each_allocation_source_covers_its_port shows each source alone (CLAUDE_PROJECT_DIR, the guard's own checkout, NS2604_HOST_FILE, XDG_CONFIG_HOME, the HOME/.config fallback), each with its own port and config root, with every other source's port uncovered, then removed. - B2: the docs and guard comment state both read caps (first 64 *.json per directory in sorted order, first 1 MiB per file) and that what lies past them covers nothing; test_read_caps_are_the_documented_ones. - B3: test_allocated_gateway_port_has_exactly_21128s_rows checks an allocated port against every frozen policy row, including the 20129-only preview and the provider-limits and call-logs <id> rows. - C: the docs and comment describe the tooling's one-file-per-run order and why the guard reads all candidates; the table note names the other-key caveat. - D: each source has its own try, so a failing source drops no later one (test_a_failing_source_drops_no_later_source fails on 3dd235c). - E: the bound (130 files, 65,535 ports) and the import-time fail-closed path under onFailure: block are recorded; no hardening. - F: the in-process import with the runner's environment is recorded and pinned (test_import_state_is_the_runners_allocation). - G: the docs say every checkout covers the committed example.json's ports (21131 added, serving no row); a real-import test in an isolated process pins it. Each new test is shown failing with the line it pins deleted (11 of 11 mutants killed). Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins
deleted the
claude/guard-nhny-gateway-ports-20261017
branch
October 17, 2026 18:47
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 17, 2026
# Conflicts: # adoption/hooks/claude/SHA256SUMS # manifests/evidence.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
adoption/hosts/<host>.jsonmoves the gateway let management requests to the new port pass unchecked, including the provider connection routes. This host's file setsNS_PORT_GATEWAY=23128,NS_PORT_GATEWAY_WS=23129andNS_PORT_GATEWAY_EMBED_WS=23131.caf9ad7cd23a90d5dbe6fde1234011a7787fc0c6. The head is the original commit 3dd235c plus one fold commit for the CC verdict CHANGES_REQUESTED at 3dd235c (B1-B3, C-G).lane:foundationscripts/hooks/secret_path_guard.pytests/test_secret_path_guard.pydocs/secret-storage.mdadoption/hooks/claude/SHA256SUMSmanifests/evidence.jsoncatalogs/foundation/upstream-surface-dispositions.json: fivedocs/secret-storage.mdline locators re-pointed after the docs insert; the line text is unchanged.Design
Where the ports come from. The port tooling (
evidence/artifacts/new-wsl-install-plan-20261002/config/observability_config.pyat caf9ad7,load_service_ports():182-194 anddefault_config_root():197-198) reads ONE flatNS_PORT_*map per run. It takes the--host-fileit is given (adoption/hosts/<host>.jsonin the allocation addendum's commands), else the fileNS2604_HOST_FILEnames, else the installed allocation. The guard cannot tell which file a run was given, so it reads all of these once when it starts:adoption/hosts/*.jsonunderCLAUDE_PROJECT_DIR;adoption/hosts/*.jsonunder the guard's own checkout;NS2604_HOST_FILEnames;${XDG_CONFIG_HOME:-$HOME/.config}/new-wsl-native-stack/.service-ports.json. This source also covers sessions in other projects that run the~/.claude/hookscopy.The tooling reads no
NS_PORT_GATEWAY*environment variables, so the guard reads none either.The committed template. Every checkout, CI's included, holds the committed
adoption/hosts/example.json, so its ports are covered wherever the guard runs from a checkout. 21128 and 21129 are fixed ports. ItsNS_PORT_GATEWAY_EMBED_WSport, 21131, is added and has no allowed routes (G).Which routes are allowed. Every
NS_PORT_GATEWAY*key is a covered port.NS_PORT_GATEWAYport that is not a fixed port gets exactly 21128's allowed routes.gpt-gatewayrows ofSERVICE_PORTS(:45-47), so the guard adds no hardcoded allocation.Fail-closed.
"NS_PORT_GATEWAY*": "D"pair in its text.try(D), so the later sources and the fixed ports stay covered.Read caps (B2).
*.jsonfiles of anadoption/hostsdirectory are read, in sorted name order. A file after the 64th covers nothing.Bound (E, recorded, no hardening).
WORK_LIMITSand outsidemain()'sguard_errorcatch.gateway_allocation()catches every exception. An import that still fails (exit 1) or outlasts the hook timeout blocks the call under the hook'sonFailure: "block"(docs/decisions/2026-10-08-guard-hook-fails-closed.md, cases B and H).Cost. Each guard start lists two directories and reads a few files of about 1 KiB each. Hook runs measured 0.08 to 0.12 s, the same as before.
In-process tests (F, recorded). The test module imports the guard in-process with the runner's environment, so the module's import state holds the runner's allocation. On a host with a moved gateway that means more covered ports, which never changes a fixed port's allowed routes.
test_import_state_is_the_runners_allocationpins this. Every test that depends on the port set either usesconfigured()or runs the hook process in an isolated environment.SOTA sources
seathatflowsinourveins/native-agent-stack@caf9ad7c:evidence/artifacts/new-wsl-install-plan-20261002/config/observability_config.py:28-51,182-198. The host-file contract isdocs/decisions/2026-10-16-new-wsl-host-allocation-addendum.md, and the committed template isadoption/hosts/example.json.CLAUDE_PROJECT_DIRis set for hook commands by Claude Code. Primary source: the hooks reference, https://code.claude.com/docs/en/hooks ("CLAUDE_PROJECT_DIR"). The repository's own hook command at.claude/settings.json:87already relies on it.onFailure: "block", measured indocs/decisions/2026-10-08-guard-hook-fails-closed.md.docs/secret-storage.md"Gateway (GW): one matrix" (contract-v2 section 5.1; wave-2 custody ruling, change 11).open(2)withO_NONBLOCKandfstatS_ISREG, through Python'sosandstatstdlib modules (https://docs.python.org/3/library/os.html#os.open).Evidence-class table
gateway_credential_route, as on 21128. On 23128, the allowlistedGET /api/settings/compressionandPOST /api/usage/provider-limitspass, and the 20129-only preview refusestest_allocated_gateway_ports_refuse_as_21128CLAUDE_PROJECT_DIR, the guard's own checkout (a copied guard in a temporary checkout),NS2604_HOST_FILE,XDG_CONFIG_HOME, and theHOME/.configfallback. Each has its own port and its own config roottest_each_allocation_source_covers_its_port; each source line deleted kills it (mutation runs below)NS_PORT_GATEWAYport passes exactly the frozen policy rows that name 21128. It refuses the 20129-only preview and has the provider-limits and call-logs<id>rowstest_allocated_gateway_port_has_exactly_21128s_rows; widening every row, or not widening<id>, kills ittest_absent_host_file_keeps_fixed_portstest_import_state_is_the_runners_allocationtest_malformed_or_unreadable_host_file_fails_closedtest_a_failing_source_drops_no_later_source(fails on 3dd235c)test_read_caps_are_the_documented_onesgpt-gatewaykeystest_gateway_keys_are_the_port_toolingsLocal commands run
At 3dd235c, the related modules (docs consistency, Claude profile install, practice ledger, upstream surface watch) had four
test_upstream_surface_watch.CachedArtifactTestsfailures. The same four fail on caf9ad7 unchanged, so they are main's, not this PR's.Decision record
No new decision. The change applies the existing gateway policy (docs/secret-storage.md, "Gateway (GW): one matrix") to the ports that #1180's host allocation,
docs/decisions/2026-10-16-new-wsl-host-allocation-addendum.md, already assigns to the gateway.Host evidence
Not applicable: no
evidence/hosts/change.Checklist
version comment (no floating tags). (none changed)
permissions: {}and grant each jobonly what it needs (
contents: read, or an explicitly justified addition). (none changed)added without a documented owner.
moved or overwritten).
🤖 Generated with Claude Code