Repository navigation
feat: make Firewall the shared approval authority - #336
Conversation
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Independent full-phase review remains pending; resource execution retains its existing atomic gate. Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
- route production resource contacts through per-hop authorization\n- begin canonical base64 url/urls wire migration\n\nCo-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
48 focused proxy/server tests and Paja type checks pass. Resource group consumer migration and full combined gates remain outstanding. Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
- use url/urls with padded base64 resource envelopes\n- authorize resolver destinations and proxy each Paja HTTP hop\n\nCo-Authored-By: Codex <noreply@openai.com>
Preserve Blossom fallback order, byte integrity, settings isolation, and compatibility warning assertions with canonical resource wire fields. Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Regression currently fails: the network approval ends before body consumption, leaving its signal live after grant revocation. Resource execution must close this lifecycle gap before its combined gate. Co-Authored-By: Codex <noreply@openai.com>
Both HTTPS and Blossom correctly prevent transport but currently misreport network approval denial as network-error instead of blocked-by-policy. Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Retained network approval must allow a second hop within the same request while keeping revocation effective. The current held-operation implementation queues the second hop behind itself. Co-Authored-By: Codex <noreply@openai.com>
Preserve current catalog intent notifications and all released host fixes. Keep exact upload ownership and stale-source suppression while isolating backend cancellation failures; migrate upstream regressions to prepared asynchronous uploads and retain the private unknown-status boundary. Co-Authored-By: Codex <noreply@openai.com>
Declare the fixture filesystem domain as optional and approve session access before exercising OPFS and host-activated native pickers. Keep the missing-OPFS case runnable without advertising an unavailable domain. Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
|
Note: This is just a slop review after I understood it on a high level. I haven't had the bandwidth to fully wrap my head around it. Day job :/. I will do it asap. |
|
@nrahulpub had some useful bits in it still |
Integrate current main while retaining both principal-bound admission and the released snapshot identity and reliable sharing behavior. Preserve both task histories in the planning state. Confidence: high Scope-risk: moderate Tested: pnpm build; Paja runtime tab unit tests Not-tested: Combined review fixes are validated in subsequent commits Co-Authored-By: Codex <noreply@openai.com>
Route one-shot relay reads through the same frozen destination plans as subscriptions and hold approval cancellation through completion. Scope persisted revocations to matching principals and restore shared temporal budgets at runtime-owned storage, INC and CONFIG dispatch. Constraint: NAP-RELAY query results retain correlated events or error responses Rejected: Add approval without retaining query lifetime | would leave transport alive after revocation Confidence: high Scope-risk: moderate Tested: Runtime type-check; 430 runtime tests; NIP-5D static conformance guard and query regressions Co-Authored-By: Codex <noreply@openai.com>
Single-event OUTBOX reads now share planned authorization with queries, and configured authorization fails closed when a router cannot bind relay destinations. Relay service publishes require destination-aware transport. Theme and identity denial paths settle once using their canonical result shapes. Planned read cancellation closes all transport handles, including when one cleanup throws. Constraint: NAP-IDENTITY getPublicKey results must not carry errors. Rejected: Warn and execute an unplannable authorized router | relay destinations would remain unenforced. Confidence: high Scope-risk: moderate Tested: 579 service tests, services type-check, 32 focused review regressions, pinned AI-slop 100/100, diff checks. Not-tested: Live external relays and physical serial or BLE devices. Co-Authored-By: Codex <noreply@openai.com>
Canonicalize Paja HTML aliases before issuing proxy capabilities, retain aborted resource signals across delayed network approval, and explain CSP scheme upgrades in shared prompts. Browser regressions distinguish default-port upgrades from Chromium’s stricter non-default-port matching. Constraint: Browser CSP matching is not literal origin equality Confidence: high Scope-risk: narrow Tested: 73 focused unit tests; shell, Paja and playground type-checks; 3 real Chromium CSP cases with ephemeral TLS fixture Not-tested: Other browser engines Co-Authored-By: Codex <noreply@openai.com>
Completing a previously silent denial must not send an old correlation id into a replacement frame. Track the source generation through pending theme authorization and retire it on window destruction or service unregistration. Confidence: high Scope-risk: narrow Tested: Two lifecycle regressions reproduced before fix; 41 theme/review tests, services type-check, pinned AI-slop 100/100 and diff checks passed. Co-Authored-By: Codex <noreply@openai.com>
Record bounded compatibility diagnostics and their actual regression suites, link the resource proxy policy, and disclose CSP scheme matching and the verified Chromium port distinction. Breaking relay/WebRTC changes need 0.x minor releases. Keep test adapters on the explicit destination contract. Confidence: high Scope-risk: narrow Tested: 2717 unit tests; build and type-check; docs:check; changeset status; AI-slop 100/100; git diff --check Not-tested: Full browser gate still requires relay receipt integration follow-up Co-Authored-By: Codex <noreply@openai.com>
Paja social-cache and Blossom decorators dropped the optional plan methods, so enforcing OUTBOX approval correctly denied otherwise supported host reads. Preserve the original plans and cancellation signals while retaining source-scoped cache augmentation and resource observation. Exercise fallback receipts with a separate approved authorless query instead of relying on speculative pre-approval traffic. Constraint: Execute only relay destinations frozen before approval Confidence: high Scope-risk: narrow Tested: 32 social-cache and Blossom unit tests; Paja type-check/build; all 18 paja-single-window Chromium tests Related: #336 Co-Authored-By: Codex <noreply@openai.com>
Project throttled STORAGE and INC requests onto their sanctioned error results, keep cleanup available, and reject stale replies after source replacement. Observe CONFIG snapshots/schema registration and INC channel lists without dropping their required responses where the checked drafts define no rate-denial contract. Constraint: NAP-STORAGE 4f4cf0ca and NAP-INC 19de5ce1 require correlated replies; NAP-CONFIG bed9cb5b has no budget-denial code Rejected: Invent a CONFIG error code or empty snapshot | violates the checked protocol contract Directive: CONFIG get/subscribe/registerSchema floods remain diagnostic-only until upstream defines denial or backpressure; registration can still validate and save repeatedly Confidence: high Scope-risk: narrow Tested: Runtime type-check; 444 runtime tests in 27 files; diff checks Co-Authored-By: Codex <noreply@openai.com>
CONFIG snapshots and schema acknowledgments, and INC channel listings, have mandatory response contracts without a sanctioned temporal-denial envelope. Preserve those responses and report excess budget use while enforcing the other local-domain operations and leaving cleanup available. Constraint: NAP-CONFIG bed9cb5b and NAP-INC 19de5ce1 require these replies Rejected: Invent a rate-limit schema code or return empty snapshots | contradicts the checked NAP contracts Confidence: high Scope-risk: narrow Directive: Repeated CONFIG registration still validates and saves; full throttling requires an upstream denial or backpressure contract Tested: 2733 unit tests; build/type-check; docs:check; pinned AI-slop 100/100 Not-tested: Final combined Chromium suite is running Co-Authored-By: Codex <noreply@openai.com>
Record each finding, its resolution, the exact protocol authority, and final combined verification. Retain the CONFIG denial/backpressure gap and Chromium CSP qualification so review completion cannot imply broader enforcement. Confidence: high Scope-risk: narrow Tested: 2733 unit tests; 159 Chromium tests; build; type-check; docs; changesets; diff; pinned AI-slop 100/100 Not-tested: Firefox/WebKit; physical devices; production relay infrastructure Co-Authored-By: Codex <noreply@openai.com>
|
Thanks for the thorough pass. Addressed the numbered findings and actionable low items, including the main conflicts. The follow-up also covers cancellation/cleanup and duplicate or stale terminal replies. Two qualifications:
Keeping the planning records here so the assessment and verification remain with the implementation. Validation: 2,733 unit tests, 159 Chromium tests, build/type-check/docs/changesets/diff checks, and pinned AI-slop 100/100. Checked NAP-RELAY Pushed |
…ment Main's playground retirement wins over every playground edit on this branch. Firewall approvals move onto the code main rewrote: the NAP-MEDIA registry, host-only openStream, and Paja's window-scoped services. Paja admission now composes with port-bound identity, the frame-src lock, and the experimental nested-context lock, and main's LLM denial and capability revocation move into the modules this branch extracted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g together The runtime plans relay work without handleMessage, so publishes skipped the window-scoped service and lost their source context. Route selected planning and execution through it. Playback now decodes the canonical base64 that resource.bytes carries instead of expecting a Blob. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixtures declare only the domains they use and answer approvals. Atomic media sources use a public URL through the proxy endpoint, since the proxy blocks loopback by design. The visible error row is asserted on a mediated target. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep the Firewall README sections alongside main's NAP-LLM ref bump, and keep this branch's planning position. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in the host firewall and dispatch controls from #404. Keeps the canonical NAP-RESOURCE wire over main's servers line in the shell docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#404's setters and firewall hooks act on the legacy gate, which never runs with RuntimeAdapter.permissions set. Add runtime.permissions.setRateLimit, relax budget validation to the contract #400 shipped, and warn once with FW-RUNTIME-LEGACY-IGNORED-001 when legacy inputs do nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cover aclDefaultPolicy as an approval ceiling, and filterNappletMessage release against budgets, revoked grants and retired sources. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register FW-RUNTIME-LEGACY-IGNORED-001 and add #404's setters to the legacy gate's retirement scope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rewall approvals Resolves conflicts from main (#376, #409, #411, #412): - runtime.ts: keep main's createServiceRuntimeContext split and custom-domain push routing (pushCapabilities), and keep this branch's per-service lifetimes and authorizeOperation binding plus the permissions runtime. - types.ts / service-types.ts: ServiceHandler lives in service-types.ts on this branch; carry main's pushCapabilities field over to it. - relay-handler.ts: a planning relay service owns publish fan-out (main's ring-buffer skip); legacy relay services stay denied, so buffer fan-out still runs whenever the runtime coordinates the publish via the pool. - STATE.md: keep both quick-task rows. Port the new @kehto/mocks relay mock and main's relay delivery test to the planned-execution relay contract (local-only plans, abort-aware execute), since this branch denies legacy relay services (FW-RELAY-SERVICE-LEGACY-001). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem and result
Kehto's Firewall was effectively a rate limiter. This change makes Firewall the shared approval policy for NAP interfaces, scoped resources, scoped network destinations, and registered future categories. Rate limiting is an independent runtime budget. A manifest/interface grant no longer confers unrestricted resource or network access.
The runtime now coordinates prompts, trusted principals, lifetimes, pending-work bounds, persistence, revocation, cancellation, and request revalidation. Service handlers keep protocol validation and authorize the actual side effect or destination. Paja admits frames before executing bytes, shows the shared grant UI, and retires the exact source on revocation. Paja supports reviewed development origins through an exact closed CSP. The old Paja firewall simulation controls are rejected because they could not enforce these approvals.
Coverage and release
The change includes package/app consumers, NAP conformance guards, unit and real Chromium regression tests, package/host documentation, compatibility records, and changesets for shipped Firewall, runtime, shell, Paja, and services output.
pnpm buildandpnpm type-checkpassed.pnpm test:unit: 207 files, 2,625 tests passed.KEHTO_HARNESS_PORT=43173 pnpm test:e2e: 133 Chromium tests passed. An unrelated local process occupied the default harness port.pnpm docs:check,pnpm changeset status,git diff --check, andnpx --yes aislop@0.12.0 scan -dpassed; AI-slop score 100/100.Protocol authority and bounded gaps
Checked the exact NIP-5D draft PR #2303 head
5560820fa4f37f45b8ab742a11aeb3001b17dc67; NAP-SHELL master19de5ce1cea40cd4c76089cdd8126e9f87648049; NAP-RESOURCE PR #80ae5b9c64ab8a4d8909f288829a01e99d6bd713bc; NAP-LINK PR #5350a2cd45e76f06e87b87e93842badf4c61f17bde; NAP-CONNECT PR #19ec81a3a4a1fc4da1ad2601215353b7f822e44b8f; NAP-NOTIFY PR #1167877ef6c31ec8acee3125c1d8b4c781010e37dc; and NAP-CVM PR #52b1ecaa529971ade6d5bc806bc0a990db0dc2356f. Other service refs and the consumer matrix are recorded in.planning/research/firewall-approvals.md.The NIP-5D/NAP admission and service wire behavior is conformant to those checked refs. Kehto's directive-specific development CSP and approval UI are bounded host policy where the drafts do not prescribe one.
Review focus
Please examine exact principal binding and source retirement, once/session/persistent grant behavior, resource redirect and selected relay authorization, and CSP source matching. The browser tests cover required/optional admission, grant revocation, and approved and blocked network effects.
CI timeout follow-up
The isolation test completed its assertions but hung in HTTP fixture teardown on Node 20. Chromium can retain a speculative TCP connection without sending an HTTP request;
server.close()then waits indefinitely. The fixture now stops listening and closes all remaining connections explicitly. CSP and network-denial assertions are unchanged.Reproduced the original 90-second timeout on Node 20.20.2. The fix passed nine focused browser runs with tracing and all 133 Chromium tests under Node 20.20.2 (2.5 minutes, harness port 43373). Build, type-check, 2,625 unit tests, docs, diff checks, and pinned AI-slop 100/100 passed. Rechecked NIP-5D
5560820fa4f37f45b8ab742a11aeb3001b17dc67and NAP-RESOURCEae5b9c64ab8a4d8909f288829a01e99d6bd713bc; behavior remains conformant. This test-only fix changes no shipped package output.The branch also incorporates main
47b2f1c8to clear merge conflicts that prevented CI from starting. Conflict resolution preserves the released Paja catalog notifications, controller/title/FS diagnostics, and upload lifetime fixes alongside Firewall ownership. Upload cancellation exceptions cannot interrupt sibling cleanup; upstream upload regressions now wait for prepared uploads and preserve the unowned-status denial. New FS browser fixtures declare optional FS and use the shared session-approval driver. NAP-FS was checked atbd1b9e912f05203bf38f7a1b04f920744fe6d625, NAP-UPLOAD atf5cc981e527e2cc1572793a7a6e5082e5271ac49, and NAP-INTENT at19de5ce1cea40cd4c76089cdd8126e9f87648049; behavior remains conformant.Combined validation: build, type-check, 2,637 unit tests, docs, changesets, and AI-slop 100/100 passed. The complete 141-test Chromium run under Node 20.20.2 with CI settings passed (140 passed directly; one playground profile-loading test passed on its second retry). Earlier local runs encountered other playground page-load timeouts; no assertions or timeout thresholds were weakened.
Merging main again (playground retirement)
This merge brings in main at
1758524e, which clears the conflicts. Main retired@kehto/playground, so every playground edit on this branch is gone, along with the playground parts of this PR's description, docs, and tests. Earlier test counts above come from before this merge.The rest needed real porting, not just conflict picking:
media.commandis now approved too, since it's a napplet-to-shell effect on shell-owned sessions.openStream: it relied on the origin-grant options this PR retired. It now goes through the same resource and network approvals as atomic requests.handleMessage, so publishes were skipping main's window-scoped service and losing their source context. Planning and revocation now reach it.Blobfromresource.bytes, but this PR's wire carries base64, so playback now decodes it.admitBrowserDocument, and LLM denials andonCapabilityRevokedmoved into the extracted modules.A heads up on test fixtures: main's specs relied on undeclared domains, and each declared domain costs a prompt per load against the 12-per-minute budget, so they now declare only what they use. A signer change reloads the frame and asks again, which could get noisy for real apps that declare many domains. Might be worth a look.
Checked NAP-MEDIA PR #10 at
7806f438formedia.commanddirection and thepolicyend reason, and it's conformant. NAP-LLM at3e10939only got a read of its consent text; main has since moved its docs to5e93bdf, and I didn't review that draft separately. NIP-5D draft #2303 has moved toc041f846; I didn't re-chase it here, so the refs above still stand.Verification:
pnpm build,pnpm type-check, 2,786 unit tests, andpnpm docs:checkpass. All 122 Chromium tests pass with 1 skipped underCI=1; an earlier run had two tests pass only on retry, and they didn't recur in the final run. That was local Node, not a re-run on 20.20.2.Known gaps:
installPajaLlmPanellength, unchanged from main.createLlmServicekeeps NAP-LLM host consent and doesn't callauthorizeOperation, so LLM generation isn't under the shared per-operation approval.nrahulpub, and I didn't re-verify them against this head.Merging main again (NAP-LLM chase)
This also brings in main at
8490d72c. The conflicts were onlySTATE.mdand the NAP-LLM ref line in two READMEs, so no code needed porting. After this merge: build, type-check, docs, and 2,855 unit tests pass, and Chromium is 124 passed with 1 skipped underCI=1, with no retries needed. AI-slop stays at 99/100 with the sameinstallPajaLlmPanelwarning, in a file that matches main. The tool-use work main added also stays on NAP-LLM host consent, not the shared per-operation approval.Merging main again (host firewall controls from #404)
This brings in main at
6eb1ea4f. Only three files conflicted, but #404 needed more than a merge, because most of it acts on the legacy gate and that gate never runs oncepermissionsis set.firewallState.setUnfocusedMultiplierandsetBurstGuarddid nothing on a configured host. There's nowruntime.permissions.setRateLimit(config), plusrateLimitto read the current budget.burst.windowMsorburst.maxOperations. It's also checked when the budget is set. Before, a bad budget would've failed every operation closed at charge time.getFocusContextalready worked and now has a test through the shell.onFirewallEventandfirewallPersistencestay legacy-only, since the permission path deliberately keeps payloads out of its diagnostics.FW-RUNTIME-LEGACY-IGNORED-001: this warns once per runtime when those hooks or afirewallStatemutator are used on a configured host. It's in the compatibility register, and it retires withFW-RUNTIME-LEGACY-GATE-001.aclDefaultPolicy(runtime: let the host choose the ACL default policy #398): it needed no code. It's a ceiling: admission can still approve an interface, but an operation the ACL denies is refused with no prompt until the host grants the capability. That's now tested and documented.filterNappletMessage(shell: pre-dispatch hook for port traffic (onNappletMessage is observe-only) #399): it also needed no code. Held envelopes meet approvals and budgets at release. A revoked grant prompts again, and a retired source runs nothing.A couple of things you might want to weigh in on:
aclDefaultPolicy: 'restrictive'means a user can approve an interface at admission and then see every operation refused, with no prompt to explain it. It matches "nothing granted", but is that what we want, or should admission refuse sooner?setRateLimittakes a whole config rather than mirroring runtime: setters for the firewall unfocusedMultiplier and burst guard #400's two setters, so hosts spreadrateLimitto change one field. Either works if you'd prefer the two names.Checked NAP-SHELL at
napplet/naps@43cb3a4(still master) forshell.readyand session binding, and it's conformant. No wire behavior changes here. I didn't re-chase the NIP-5D draft or the other refs above.Verification:
pnpm build,pnpm type-check, 2,952 unit tests, andpnpm docs:checkpass. Chromium is 124 passed with 1 skipped underCI=1, with no retries. That was local Node, not 20.20.2. AI-slop stays at 99/100 with the sameinstallPajaLlmPanelwarning.Known gaps:
onRateLimitonly covers budgets, so this part of shell: forward getFocusContext, onFirewallEvent and firewallPersistence through ShellAdapter #397's "show the user what was refused" isn't carried over.focused, somsSinceFocusGainfromgetFocusContextis ignored on configured hosts.filterNappletMessage, so the filter on a configured host is proven by unit tests, not in a browser.nrahulpub's open review findings aren't re-verified against this head.🤖 Generated with Claude Code