Count the direct-path interop harness in security-local.md's loopback inventory - #635
Count the direct-path interop harness in security-local.md's loopback inventory#635dormouse-bot wants to merge 2 commits into
Conversation
…opback inventory scripts/direct-interop/run.mjs binds a loopback HTTP server at :214 and has since it landed, so loopback-lint reports four listeners while the spec's "Loopback Listeners" section still says "Today the set is three". The harness is guarded — it imports isOwnOrigin from lib/src/host/loopback-guard.ts and isAuthorized from standalone/scripts/dev-host-guard.mjs — so the lint is green and only the spec's own inventory is stale. Nothing else changes: the rule, the FAIL IF, and the lint are all untouched. Found by the 2026-09-13 nightly security audit (W1, refs #598).
Deploying mouseterm with
|
| Latest commit: |
6fa9f90
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://92d0bc65.mouseterm.pages.dev |
| Branch Preview URL: | https://fix-loopback-inventory-fourt.mouseterm.pages.dev |
dormouse-bot
left a comment
There was a problem hiding this comment.
Feedback on work in progress, not a merge verdict — mark the PR ready when you want the full review.
The correction itself checks out: scripts/direct-interop/run.mjs binds server.listen(0, '127.0.0.1', …), imports both isOwnOrigin and isAuthorized, and gates on them at the top of the handler, so it passes the lint by reference rather than by allowlist. loopback-lint reports 4 loopback listeners, 1 allowlisted and its self-test stays green at 7 load-bearing checks; the two spec-lint path misses are the standalone/sidecar/node_modules artifacts of an un-installed checkout, not this diff.
One thing keeps the fix from holding: the sentence's derivation instruction still says "shipped trees", which is a narrower scope than the four it now counts, and .github/audit/application-security.md repeats that instruction to the very domain that raised W1. Inline suggestion below.
One case the wider scope surfaces and this bullet doesn't address either way: relay/scripts/dev.mjs defaults DORMOUSE_BIND_HOST to 127.0.0.1 and calls server.listen(port, env.DORMOUSE_BIND_HOST), a loopback HTTP-and-WebSocket bind the regex can't see because the host is a runtime value — the case the lint's header names as its own ceiling. The front matter defers the network boundary to docs/specs/security-remote.md, so it may well be out of scope here, but nothing in the bullet says so, and an auditor deriving mechanically lands on it. Saying once why the relay is not in this set would stop the next derivation re-opening it.
…e set it names The bullet said to derive the set by searching the "shipped trees", but two of the four listeners it now names — the browser-dev bridge and the direct-path interop harness — are in neither shipped tree; loopback-lint reaches both only because it scans git ls-files for tracked, non-test source files. An auditor following the old instruction derives two and re-files the same miscount. .github/audit/application-security.md repeated the instruction verbatim to the domain that raised it, so both lines move together. Also state once why the Relay is out of this set. It binds from config rather than to render a surface, and the front matter already defers the network boundary to docs/specs/security-remote.md — but nothing in the bullet said so, and the wider derivation scope now lands a mechanical search on relay/scripts/dev.mjs. docs/specs/security-local.md: 2533 / 2550 words, no re-baseline.
docs/specs/security-local.md-> "Loopback Listeners" says "Today the set is three" and names the iframe proxy, the VS Code agent-browser stream relay, and the browser-dev bridge.pnpm lint:loopbackprints4 loopback listeners. The fourth isscripts/direct-interop/run.mjs:214—server.listen(0, '127.0.0.1', …)— which the inventory has never counted. This PR corrects the count and the derivation instruction that let it drift.No privilege gap. The harness is guarded on its own merits: it imports
isOwnOriginfromlib/src/host/loopback-guard.tsandisAuthorizedfromstandalone/scripts/dev-host-guard.mjs, and calls both before routing, so it passes the lint by reference rather than by allowlist. The rule, theFAIL IF,scripts/loopback-lint.mjsand its self-test are all untouched.Three edits, one concern:
loopback-lintreaches them only because it scansgit ls-filesfor tracked, non-test source files — so the old instruction derives two and re-files the same miscount next time..github/audit/application-security.md:45repeated it verbatim to the domain that raised this, so both lines move together and the prompt now names the lint as the reference implementation.docs/specs/security-remote.md— but nothing in the bullet said so, and the wider derivation now lands a mechanical search onrelay/scripts/dev.mjs:41.The count is the one part of that bullet nothing mechanical pins, which is why it drifted and why an auditor reading the spec instead of the tree undercounts.
docs/specs/security-local.mdis at 2533 / 2550 words, so no re-baseline.Verification
Enumerated the lint's own
BIND_FORMSagainstgit ls-files:scripts/spec-lint.mjsreports two pre-existingstandalone/sidecar/node_modulespath misses in this checkout; both are artifacts of running withoutpnpm install, andci.ymlis green on6ee13512.CI's first attempt on
7c16f6b6went red onlib/src/host/remote/native-direct-peer.test.ts—libdatachannel error while adding remote description: Got a remote candidate without ICE transport, an ICE race in a WebRTC test a one-line Markdown edit cannot reach. The rerun passed with no other change. Flagging it as one observation, not a pattern: no otherci.ymlrun in the last week failed this way.Found by the 2026-09-13 nightly security audit's
application-securitydomain (warning W1), whose report never reachedaudit-report.md— see #598.Refs #598