Repository navigation
Permissions and trust #9
Description
Status reconciliation, 2026-10-02
Trust has two concrete unresolved items. Packaged extension caller checks, stale-document rejection, native backend auth and the Firefox optional-host refusal/grant/removal/regrant sequence are implemented and verified. The Chrome native permission sequence has not completed: its first interactive attempt granted access during the refusal step, so no passing manual receipt exists. The authority review confirms that background-owned content execution can proceed through native browser APIs without a new SDK trust policy. Page-originated privileged RPC remains unimplemented; a specific host must decide its exposed operations if that relay is introduced. Current rejection tests do not grant relay authority. Native document/frame denial and lifecycle acceptance remain required.
Current full CI passed at 52bc770bde38ecb2042aa4713a32a1c87abc4c56 for all maintained scenarios; it does not certify the unimplemented or untested cases above. Earlier dated checkpoints record their historical state.
Reconciled status, 2026-10-01
c84fcf1 adds native optional-host permission controls and maintained Chromium/Firefox trust suites. The actor/operation table, diagram, commands and receipts record the implemented boundary without changing SDK contracts, native auth or Port admission.
- Both browsers reject actual content-script Ports with forged packaged-sender message fields, as well as wrong-channel packaged callers. Actual Devframe action/state-read frames receive no replies; the attempted service-disable action has no effect and the admitted panel still works.
- Native document IDs reject a replaced top-level document; explicit current-document selection succeeds. MAIN code has no extension
runtime.connectin the fixture. - Firefox's real optional-host prompt refusal/grant, removal/regrant and permission events reaching another panel pass. Each fresh native injection checks current access. This does not promise rollback or termination of already-running work.
- Chromium proves ungranted optional-host rejection. Its extension prompt grant/refusal and post-grant removal still need a manual receipt; website permission overrides are not equivalent. The README gives the exact manual sequence.
The first full CI run caught a regression in these new controls: Firefox omits chrome.permissions in DevTools documents. ab39e95 detects the missing API, disables the controls with an options-page direction, and keeps the panel connected. The focused Firefox test now opens the real DevTools panel and asserts that unsupported case. No background permission broker or replacement API was introduced.
Local evidence: Chromium 153.0.8010.12 and focused Firefox 157.0. Type checks, strict Oxlint, Oxfmt, production builds and all 3 extension bundle tests pass. CI runs both new commands; the full Firefox suite remains pinned to 156.0.1 while its separate 157 sidebar selector is tracked under #16.
Full CI is green on ab39e95: repository builds/types/strict lint/format/unit tests; Chromium and Firefox extension suites; both new trust commands; native renderer/Vite/debugger integrations; and concurrent Chromium/Firefox development reloads. CI verifies the Firefox prompt and DevTools availability checks on its pinned 156.0.1, alongside the local focused 157.0 receipt.
Existing Port framing/codec/close, rich values, unsupported functions, disconnect, failed mounts and native server auth/origin rejection remain covered. A privileged page relay, child-frame/resource policies, private-state isolation and untrusted-recipient error disclosure remain open. CDB-specific approvals remain optional capability behavior, not a second mandatory authorization layer. Earlier checkpoint comments are historical evidence, not reopened decisions.
Accepted two-layer selection amendment, 2026-09-27
The owner chose typed command/results with native state observation, and implementation-owned applicability. Contract migration and authenticated native proof are on main. The architecture diagram and API examples supersede the earlier universal target contract and A1/A2/B mapping questions.
Client selectors choose realm/provider recipients. Selected action/service implementations inspect schema-defined domain/resource input and return their own declared result, such as applied or not-applicable. There is no SDK target envelope, target resolver, accepts hook or new topic/event bus. A not-applicable result is fulfilled; it neither makes the provider unavailable nor triggers fallback/replay. If multiple selected implementations match, all may act.
Provider incarnation, contribution activation generation, exact versions, native authorization/serialization and dispatch ownership remain unchanged. Browser/debugger capabilities still validate actual resources and permissions.
Part of Design a portable contribution SDK and WebExtension runtime.
Remote adapter prerequisite review, 2026-09-27
Updated in 4852525. The affected server package passes strict Oxlint, TypeScript and all 22 tests, including two native serialization compatibility tests.
The local router is implemented. The earlier Q4/Q5 recommendations in ffcc8f1 are superseded by the owner's upstream-first direction: ordinary native connections retain native authorization and serialization. A second mandatory SDK policy or JSON-only business payload restriction is not an implementation prerequisite.
The updated remote boundary record records native auth/session behavior, meaningful method-level authorization, the public records serializer, and the remaining cleanup/extension bridge gaps. The installed public codec preserves structured values through a JSON envelope; structuredCloneSerialize rejects a function where structuredCloneStringify can silently drop an object property. These entry points are not interchangeable for strict rejection. Real extension transport proof remains outstanding.
That dated investigation is now resolved for target-free native calls in 0c170ec: finite host/client definitions, removable adapter listeners, an authorized catalog query and payload-free invalidations. The owner accepts local cancellation without backend unary cancellation. 48 server tests include authenticated delivery, denied access, metadata guards and cleanup. The browser example runs on both hosts. Full repository CI passed at dfef733: builds, types, strict lint, formatting, packed-consumer checks and tests.
The target authority investigation separates authenticated RPC caller identity from exact-document authority. The owner removed the universal target contract. Capability implementations own resource selection, applicability and freshness; there is no generic mapping question left. Complete actors/permissions, real extension sender checks, target freshness, error disclosure and state privacy remain open. This is not the complete permission matrix.
Upstream integration boundary, 2026-09-27
Inherit native authentication and authorization for ordinary Devframe calls. Preserve authorize(methodName, session) and actual getCurrentRpcSession() ownership; custom native authorize overrides replace rather than automatically compose the default gate. Reuse devframe/utils/structured-clone for explicit bridge encoding. Page-to-extension and target authority still require checks at the boundary that gains privilege. No mandatory second SDK policy callback, JSON-only business-value restriction or new codec is introduced.
See the implementation and map review. This narrows implementation mechanisms without dropping the accepted feature or real-host coverage requirements.
Question
Which actors may invoke contribution actions, read or change shared state, inject code, transform traffic, and control debugger targets? Decide how permissions, trusted extension contexts, and authenticated server peers combine without treating page messages or rendered JSON as authority.
Context and current behavior
The SDK will compose executable contributions at build time and present shared interfaces through a JSON renderer. Those choices do not make every caller trusted. The inspected page, content script, extension background, popup, options page, DevTools page, renderer, and server peer have different privileges and lifetimes.
Chrome content scripts normally run in an isolated world, while main-world code shares the page's environment. A page can observe or interfere with main-world logic. A message relayed through a content script does not become a user decision. Chrome also provides optional permissions and temporary activeTab access, which have different lifetimes.
CDB already separates presentation intents from trusted approval, then binds authority to principals and target generations. Its architecture is useful input when the optional adapter is composed. The generic SDK must preserve that boundary without imposing an agent-grant workflow on every ordinary local contribution.
Packaged executable modules and remote JSON data also need a clear boundary. Chrome's MV3 policy permits data and configuration but restricts remote executable logic, including complex command interpreters disguised as data. Firefox requires self-contained executable code.
Requirements and scope
- Define actors, trusted entry points, target identity, permission ownership, and the actions each actor can request. Cover both extension and server adapters.
- Keep contribution composition at build time. Decide whether compiled-in modules are mutually trusted; do not imply a sandbox between modules sharing the same extension process.
- Expose native realm context only to local code in that context. Define the serializable action, state, error, and capability descriptions that may cross RPC.
- Scope operations to the correct tab, frame, document, origin, and connection where those identities matter. A stale popup or reconnecting page must not redirect an old action onto a new target.
- Define required versus optional permissions, user activation requirements, denial, revocation, and availability changes. Avoid silently requesting broader authority to satisfy an unavailable capability.
- Keep transport authentication and final action authorization separate. Renderer visibility, a disabled button, and a known action name do not authorize execution.
- Specify storage boundaries for public state and private credentials. Examples use synthetic data and must not expose credentials through shared state, logs, or error payloads.
Options and recommendation
Granting the entire extension every permission simplifies implementation but hides which module needs authority. Asking for approval on every action makes routine use cumbersome and duplicates browser or host policy. Treating all page-origin requests as trusted would cross the wrong boundary.
Preserve native host policy, explicit contribution capability declarations and browser permission requirements. Ordinary native calls inherit existing authority; introduce additional checks only for a concrete exposure or privilege transition. A trusted local operation may proceed under existing authority; a sensitive request crossing from a page or remote principal must pass the relevant authorization boundary. Prefer the existing native hooks, and preserve optional integrations’ existing grant model rather than adding a universal one.
Proposed API or experiment
Boundary pseudocode, not new SDK API declarations: native RPC supplies the trusted session and codec; a bridge validates any less-trusted source before forwarding:
ordinary native call:
native method/session authorization
-> adapter resolves registered contract and validates input
-> capability checks its domain/resource applicability and permissions
-> owned contribution validates input and executes
page request relayed through extension:
actual browser sender + document/target authority check
-> extension's existing authenticated connection
-> ordinary native call path
The host derives caller authority from its authenticated connection or actual browser sender. Resource references supplied in operation input are requests, never proof of permission; the capability checks them against native resource authority. Produce sequence diagrams for a popup action, a page-origin request, a JSON renderer action, and a server-peer action. For each, identify validation, authorization, execution, result filtering, and cancellation ownership.
Scenarios and acceptance criteria
- A forged page message naming a privileged action fails before execution, even when its JSON matches the public schema.
- An authorized popup operation succeeds; denied permission leaves the capability unavailable with a stable reason and a usable UI.
- Revocation or navigation between validation and dispatch prevents stale work where possible and documents uncertain outcomes after dispatch. Mutations are not blindly replayed.
- Main-world events cannot fabricate CDB approval. Optional CDB integration preserves its principal, generation, and final-approval rules.
- Reload, reconnect, worker shutdown, and disposal release listeners and pending requests without leaking private state into another connection.
- Every public authorization and permission API, hook, and lifecycle event has a runnable example and automatic tests on all supported hosts. The overall suite includes contributions, renderers, Devframe, DevTools, Chromium, and Firefox; unsupported and denied cases are explicit assertions.
Use real browser permissions and real adapter connections for acceptance. Mocks may supplement adversarial cases, but stubbed authorization or compile-only examples cannot satisfy the contract.
Dependencies
Depends on Contribution and realm contract to establish local context, RPC boundaries, and module lifecycle, and Browser capability audit to establish available permission mechanisms and browser limitations. Security policy must attach to actual actors and capabilities.
Definition of Ready
-
Identify each real authority transition and map SDK operations to meaningful native RPC authorization; prove the chosen public codec and registration cleanup.
-
Dependency resolutions identify supported hosts, execution contexts, and serializable contracts.
-
Every privileged capability has a proposed caller and target scope.
-
Firefox fixtures exercise real native prompt refusal/grant, removal/regrant and navigation in a disposable profile without production credentials.
-
Chromium native prompt grant/refusal and post-grant removal have a manual receipt; automated missing-grant rejection is already covered.
-
The optional CDB approval and authority boundaries are available for comparison.
Definition of Done
-
Authenticated native fixtures prove allow/deny; real extension fixtures prove packaged-page sender checks, wire values and disconnect cleanup.
-
Both browsers reject forged content callers before native RPC execution or state disclosure and reject replaced document IDs.
-
Firefox proves native optional-host refusal/grant/removal/regrant and cross-panel permission events.
-
Privileged page relays, remaining target/child-frame authority and Chrome prompt acceptance have real-host evidence.
-
An actor/operation matrix, trust-boundary diagrams, permission policy, and revocation semantics are accepted.
-
Public authorization hooks, error outcomes, and local native-context rules are specified with concrete examples.
-
Shared-state and credential storage responsibilities are assigned without coupling generic code to a downstream application.
-
Every public API and hook maps to runnable examples and automated success, denial, unsupported, spoofing, and lifecycle cases on every supported host.
-
Remaining security decisions and real-host gaps are recorded explicitly; implemented slices remain separate from acceptance of the full contract.
-
The human has confirmed the resolution through discussion; the agent has not supplied the human side of the decision.
Resolution record
Post the accepted trust model, permission matrix, interface sketches, adversarial scenarios, and rejected alternatives in the resolution comment. Link it by this issue's title from the parent map.
Activity
dvcolomban commentedon Sep 22, 2026
Research handoff and acceptance gates
Sources: Browser capability audit.
Accountable owner:
dvcol, until reassigned. These observations inform this open contract; they do not resolve it.Firefox's negative fixture omits only
webRequestFilterResponse: all three filter calls reject and original page bytes arrive. This proves missing permission, not a user refusing a prompt or revoking a grant. Chromium'sdebuggerpermission cannot be requested as an optional runtime permission.Acceptance additions:
docs(trust): record remote adapter decision frontier (#9)
dvcolomban commentedon Sep 27, 2026
Remote adapter prerequisite investigation is committed separately as ffcc8f1, following the completed local routing slice.
The deliverable contains native source evidence, a remote invocation sequence, Q4/Q5 alternatives, and readiness/completion checklists. It distinguishes three independent responsibilities: transport authentication, host authorization, and portable serialization. It also identifies public RPC cleanup/disconnect integration gaps without proposing a private-API workaround.
The owner has been asked to choose mandatory explicit remote policy versus native-trusted default access, and JSON+void versus a richer portable codec. These are pending, not assumed approvals. No remote exposure, wire codec or new upstream PR was introduced. Existing Devframe and Vite PRs remain drafts.
test(trust): reuse and verify native serialization (#9)
dvcolomban commentedon Sep 27, 2026
The earlier Q4/Q5 recommendations are superseded by the owner's explicit upstream-first direction. Devframe already provides native authorization and serialization; ordinary native calls do not require another SDK policy callback or a JSON-only payload format.
4852525 updates the boundary record and adds two public-codec compatibility tests. Date, Map, Set, BigInt, cycles and undefined survive an encoded JSON envelope; the strict records serializer rejects executable values. This is installed-package evidence, not an actual extension transport test. The string helper's observed lossy handling is documented rather than assumed equivalent.
Native authorization must remain meaningful when mapping operation names. Page/extension sender authority, target freshness, authoritative catalogs and public registration/disconnect cleanup still need real adapter evidence. These concrete boundaries remain in this issue's acceptance criteria; no parallel auth or codec framework is planned.
Server lint/type checks and all 22 tests pass. Full CI is green.
test(webext): prove native caller and permission boundaries (#9)
dvcolomban commentedon Oct 1, 2026
Implemented the next native trust slice in c84fcf1.
The example now has gesture-bound optional localhost request/removal controls. Browser-owned permission events update every open panel. No SDK authorization callback, target protocol, serializer, approval store or production Port policy was added.
Real Chromium and Firefox tests send Devframe-generated action/state requests through wrong-channel and content-script Ports with forged sender fields. Admission rejects them before replies or service mutation. Both browsers reject a stale native document ID after reload. Firefox additionally denies and grants the actual browser prompt, removes access, rejects the next operation, restores access and updates a second open panel. The tests wait for the native notification's open state and use WebDriver pointer actions; they do not alter stored grants or stub permissions.
Commands, implemented actor matrix, diagram and receipts. Local checks: strict lint/types/format, both production bundles, all 3 bundle tests, Chromium 153.0.8010.12 and focused Firefox 157.0. Both new commands are in CI.
Issue #9 stays open. Chrome native prompt grant/refusal and post-grant removal need the documented manual receipt. Privileged page relay, child-frame/resource policy, state privacy and error disclosure remain uncovered. Removing browser host access does not redefine an already-authenticated Devframe backend connection or promise cancellation of dispatched work.
fix(webext): handle unavailable DevTools permissions (#9)
dvcolomban commentedon Oct 1, 2026
The first full CI run found a regression introduced by the permission controls. Firefox DevTools documents do not expose
chrome.permissions; accessing its events interrupted panel startup.ab39e95 adds a native availability check. That context displays “Unavailable in this context. Use extension options.” and disables only those controls. Native panel RPC/rendering still starts. The focused Firefox test opens the actual DevTools panel and verifies both connection and disabled controls, alongside prompt refusal/grant/removal/regrant and cross-panel permission events.
Types, strict lint, formatting, builds, all 3 bundle tests and the expanded Firefox 157.0 trust suite pass locally. Full CI is running again. This fixes the introduced DevTools regression; it does not claim the separate Firefox 157 sidebar automation gap is resolved.
dvcolomban commentedon Oct 1, 2026
Full CI is green on ab39e95.
All repository checks, both extension browser suites, the new Chromium/Firefox trust tests, native rendering/Vite/debugger integrations and concurrent development reload checks passed. The native Firefox permission prompt and DevTools availability cases passed on CI's Firefox 156.0.1 as well as the local focused Firefox 157.0 run. Main is pushed and the local worktree is clean.
The delivered changes remain scoped to #9 in c84fcf1 and ab39e95. This issue stays open for its explicitly listed remaining acceptance work, including the manual Chrome native-prompt receipt.
dvcolomban commentedon Oct 1, 2026
The local interactive Chromium attempt stopped on its first expected outcome: the refusal step returned
Access grantedwhere the assertion expectedAccess denied. The owner's click reached Chrome. The test did not complete the later grant, removal or regrant checks, and it did not produce a passingchromium-interactive.jsonreceipt. This is an incomplete manual sequence, not evidence of an extension permission defect.The available in-app browser controls can exercise ordinary web UI, and the Vite counter examples have been checked there. They do not provide unpacked-extension loading or control of Chrome's native extension-permission dialog. The existing disposable Chrome fixture is still needed for this acceptance case; website permission overrides would test a different mechanism.
The interactive runner remains local pending completion of the actual prompt sequence. Automated Chromium caller/document checks and the separately verified Firefox native prompt sequence retain their existing evidence. No new Chrome prompt coverage or owner permission-policy decision is claimed.
dvcolomban commentedon Oct 2, 2026
Trust frontier clarification, 2026-10-02
A privileged page relay is not required to prove generic content execution. The accepted architecture already places the provider in the background and content/MAIN scripts as execution agents. Native browser operations can be composed by an ordinary capability without admitting a page or content Port into the background RPC group.
The smallest useful content example can use this existing direction:
The capability owns document selection, applicability, validation and native permission failures. The current example still rejects actual content callers before RPC attachment; page messages gain no action/state authority. A persistent agent can later use a background-initiated native
tabs.connectchannel and narrowly registered agent operations under the same ownership. Neither path requires a mandatory SDK authorizer or a generic target registry.A human policy choice becomes necessary only for an actual host exposing page-originated privileged requests: which named operations/data should that host grant? This remains unimplemented and must not be confused with authorizing all ordinary native connections. Its policy belongs to that host/capability boundary. The current deny tests do not prove a privileged relay.
Independent remaining work includes supported document/frame lifecycle and denial/disclosure assertions, plus the missing Chrome native refusal/grant/removal/regrant receipt. Chrome's prompt requires human interaction with the disposable native browser; it is a validation constraint, not a new SDK contract decision. Firefox's native sequence is verified.
This is a fact/ownership review, not a newly executed content feature or acceptance result. Relevant source: caller admission, document permission operations, placement table, and Port primitive.
dvcolomban commentedon Oct 3, 2026
The Injection and transform contract now retains a real Firefox script-permission transition in e05dd25.
A single native MAIN
document_startregistration keeps the same identity and options throughout permission grant, removal and regrant. Fresh top-level documents execute it while access is granted, omit it after removal, and execute it again after regrant. Explicit contribution disposal empties the native registry. This uses Firefox's real permission prompt and browser permission API; the SDK adds no reinstall, retry or rollback policy.The retained result covers Firefox production, MAIN, top-level
document_start. Other stages/worlds/frames, Chromium's manual permission sequence and rollback of previously executed code are not established by this receipt. Scope, command, raw observations and acceptance checks live in the linked owning ticket. Current full CI is still running.