machine-bridge-mcp 2.0.0 → 3.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/CONTRIBUTING.md +20 -25
  3. package/README.md +21 -14
  4. package/SECURITY.md +147 -123
  5. package/browser-extension/manifest.json +3 -2
  6. package/browser-extension/service-worker.js +31 -12
  7. package/docs/ARCHITECTURE.md +27 -13
  8. package/docs/AUDIT.md +85 -2
  9. package/docs/CLIENTS.md +2 -2
  10. package/docs/ENGINEERING.md +9 -3
  11. package/docs/GETTING_STARTED.md +10 -9
  12. package/docs/LOCAL_AUTHORIZATION.md +115 -72
  13. package/docs/LOGGING.md +12 -3
  14. package/docs/MANAGED_JOBS.md +24 -29
  15. package/docs/MULTI_ACCOUNT.md +98 -37
  16. package/docs/OPERATIONS.md +33 -22
  17. package/docs/OVERVIEW.md +7 -7
  18. package/docs/PROJECT_STANDARDS.md +9 -5
  19. package/docs/RELEASING.md +171 -64
  20. package/docs/TESTING.md +19 -7
  21. package/docs/THREAT_MODEL.md +138 -67
  22. package/docs/TOOL_REFERENCE.md +2 -2
  23. package/docs/UPGRADING.md +102 -18
  24. package/native/macos/MachineBridgeTrustBroker.swift +233 -0
  25. package/package.json +36 -5
  26. package/scripts/candidate-runtime-store.mjs +38 -0
  27. package/scripts/check-plan.mjs +19 -0
  28. package/scripts/check-runner.mjs +4 -1
  29. package/scripts/commit-message-check.mjs +5 -2
  30. package/scripts/coverage-check.mjs +30 -2
  31. package/scripts/github-push.mjs +11 -0
  32. package/scripts/github-release.mjs +38 -7
  33. package/scripts/install-published-prerelease.mjs +167 -0
  34. package/scripts/local-release-acceptance.mjs +23 -12
  35. package/scripts/npm-publication-policy.mjs +16 -0
  36. package/scripts/prerelease-activation.mjs +79 -0
  37. package/scripts/privacy-check.mjs +7 -5
  38. package/scripts/promotion-digest.mjs +121 -0
  39. package/scripts/publish-npm.mjs +51 -0
  40. package/scripts/published-release.mjs +87 -0
  41. package/scripts/release-acceptance.mjs +30 -1
  42. package/scripts/release-candidate-manifest.mjs +40 -0
  43. package/scripts/release-channel.mjs +106 -0
  44. package/scripts/release-impact-check.mjs +12 -22
  45. package/scripts/release-soak.mjs +237 -0
  46. package/scripts/start-release-candidate.mjs +113 -7
  47. package/src/local/account-access.mjs +6 -0
  48. package/src/local/account-admin.mjs +34 -16
  49. package/src/local/agent-context.mjs +45 -42
  50. package/src/local/app-automation.mjs +9 -4
  51. package/src/local/authority-context.mjs +106 -0
  52. package/src/local/browser-bridge-http.mjs +4 -1
  53. package/src/local/browser-bridge.mjs +14 -9
  54. package/src/local/browser-broker-routes.mjs +4 -0
  55. package/src/local/browser-broker-server.mjs +5 -4
  56. package/src/local/browser-extension-identity.mjs +50 -0
  57. package/src/local/browser-extension-protocol.mjs +9 -4
  58. package/src/local/browser-operation-service.mjs +7 -0
  59. package/src/local/browser-pairing-http.mjs +36 -0
  60. package/src/local/browser-pairing-store.mjs +56 -47
  61. package/src/local/cli-account-admin.mjs +41 -7
  62. package/src/local/cli-activate.mjs +90 -0
  63. package/src/local/cli-approval.mjs +14 -58
  64. package/src/local/cli-local-admin.mjs +5 -15
  65. package/src/local/cli-options.mjs +11 -7
  66. package/src/local/cli-service.mjs +35 -5
  67. package/src/local/cli.mjs +112 -58
  68. package/src/local/daemon-process.mjs +6 -0
  69. package/src/local/delegated-process-sandbox.mjs +147 -0
  70. package/src/local/device-identity.mjs +157 -48
  71. package/src/local/device-root-provider.mjs +87 -0
  72. package/src/local/errors.mjs +25 -3
  73. package/src/local/git-service.mjs +16 -15
  74. package/src/local/job-runner.mjs +35 -27
  75. package/src/local/log.mjs +14 -1
  76. package/src/local/macos-trust-broker.mjs +320 -0
  77. package/src/local/managed-job-lock.mjs +18 -0
  78. package/src/local/managed-job-projection.mjs +9 -1
  79. package/src/local/managed-job-runner.mjs +13 -1
  80. package/src/local/managed-job-storage.mjs +2 -1
  81. package/src/local/managed-job-terminal.mjs +138 -0
  82. package/src/local/managed-jobs.mjs +88 -32
  83. package/src/local/operation-authorization.mjs +75 -239
  84. package/src/local/operation-risk.mjs +28 -0
  85. package/src/local/operation-state-lock.mjs +7 -86
  86. package/src/local/owner-state-lock.mjs +104 -0
  87. package/src/local/policy.mjs +19 -0
  88. package/src/local/process-execution.mjs +21 -9
  89. package/src/local/process-sessions.mjs +27 -17
  90. package/src/local/process-tracker.mjs +30 -6
  91. package/src/local/process-tree-ownership.mjs +59 -0
  92. package/src/local/process-tree.mjs +22 -18
  93. package/src/local/relay-connection.mjs +47 -35
  94. package/src/local/relay-diagnostics.mjs +65 -0
  95. package/src/local/remote-configuration.mjs +48 -0
  96. package/src/local/runtime-activation.mjs +141 -0
  97. package/src/local/runtime-diagnostics.mjs +21 -0
  98. package/src/local/runtime-relay.mjs +9 -8
  99. package/src/local/runtime-reporting.mjs +8 -3
  100. package/src/local/runtime-tool-handlers.mjs +8 -8
  101. package/src/local/runtime.mjs +73 -39
  102. package/src/local/secure-file.mjs +5 -1
  103. package/src/local/security-audit-log.mjs +204 -0
  104. package/src/local/service-convergence.mjs +17 -1
  105. package/src/local/service-ownership.mjs +17 -0
  106. package/src/local/service-restart-handoff.mjs +50 -0
  107. package/src/local/service-restart-scheduler.mjs +49 -0
  108. package/src/local/service-status.mjs +47 -0
  109. package/src/local/service.mjs +142 -43
  110. package/src/local/state-inventory.mjs +21 -3
  111. package/src/local/state.mjs +155 -17
  112. package/src/local/stdio.mjs +5 -0
  113. package/src/local/tool-executor.mjs +39 -6
  114. package/src/local/tool-result-boundary.mjs +51 -0
  115. package/src/local/tools.mjs +1 -0
  116. package/src/local/trusted-executable.mjs +53 -0
  117. package/src/local/trusted-git-executable.mjs +34 -0
  118. package/src/local/trusted-github-cli.mjs +24 -0
  119. package/src/local/windows-service.mjs +20 -0
  120. package/src/local/worker-deployment.mjs +3 -4
  121. package/src/local/worker-secret-file.mjs +2 -2
  122. package/src/local/workspace-file-service.mjs +34 -31
  123. package/src/shared/admin-auth.d.mts +2 -1
  124. package/src/shared/admin-auth.mjs +3 -3
  125. package/src/shared/device-session-auth.d.mts +20 -0
  126. package/src/shared/device-session-auth.mjs +51 -0
  127. package/src/shared/server-metadata.json +1 -1
  128. package/src/shared/tool-catalog.json +2 -2
  129. package/src/worker/account-admin.ts +23 -22
  130. package/src/worker/authority.ts +9 -2
  131. package/src/worker/daemon-auth.ts +45 -67
  132. package/src/worker/daemon-sockets.ts +12 -2
  133. package/src/worker/device-session-verifier.ts +129 -0
  134. package/src/worker/dpop.ts +151 -0
  135. package/src/worker/http.ts +47 -16
  136. package/src/worker/index.ts +53 -16
  137. package/src/worker/nonce-store.ts +1 -5
  138. package/src/worker/oauth-client-admin.ts +45 -0
  139. package/src/worker/oauth-controller.ts +55 -6
  140. package/src/worker/oauth-refresh-families.ts +21 -7
  141. package/src/worker/oauth-state.ts +6 -0
  142. package/src/worker/oauth-tokens.ts +28 -8
  143. package/src/worker/websocket-protocol.ts +8 -2
package/docs/TESTING.md CHANGED
@@ -23,6 +23,10 @@ The suite includes:
23
23
  - one-shot process output preview/continuation, completed-session paging, bounded nonzero-exit details, UTF-8-safe head/tail diagnostics, compact local/Worker MCP text mirrors, and quiet-success/bounded-failure verification-runner behavior;
24
24
  - GitHub backlog enforcement that paginates all open issues and pull requests, permits only the current branch PR, and requires standard closing keywords for every open issue before a guarded push;
25
25
  - release-impact enforcement requiring a new package version and CHANGELOG section for release-relevant changes;
26
+ - strict dev/beta/rc/stable channel parsing and npm dist-tag enforcement;
27
+ - persistent candidate relay/service handoff ordering and fault cleanup;
28
+ - owner-only local and registry prerelease activation records;
29
+ - npm/GitHub prerelease metadata validation, minimum soak timing, blocking-issue rejection, and stable-promotion content/file-mode identity;
26
30
  - release-state diagnostics distinguishing missing local/remote version tags from tags that point to the wrong commit, plus a release-CI gate that rejects missing, pending, failed, pull-request-only, stale, or wrong-commit runs;
27
31
  - generated Cloudflare Worker types under ignored `.wrangler/` state and strict TypeScript checking, including unused-local and unused-parameter rejection; packaging rejects generated declarations;
28
32
  - Conventional Commit title validation, shared Markdown escaping regression coverage, and generated MCP tool-reference drift detection;
@@ -32,7 +36,7 @@ The suite includes:
32
36
  - default working-agreement injection without user files, bounded automatic project metadata, script-body non-disclosure, user-global opt-out, repository opt-out rejection, global `model_instructions_file` injection in stdio/remote initialization, hierarchical precedence, `.agents/skills` and `.codex/skills` compatibility discovery, live project/skill rescanning and fingerprints, automatic task ranking/loading with English inflection normalization, bounded Chinese/English intent aliases, capability-name weighting, and selected-skill instruction loading; automatic `package.*` commands with English/Chinese workflow-intent matching and Windows command-shim execution, explicit command override/removal, direct argv handling, timeout ceilings, runtime-keyed routing-telemetry privacy, and execution-profile denial;
33
37
  - concurrent complete-before-visible lock claims, atomic replacement under active readers, malformed-lock grace, snapshot/token-safe reclamation, absolute-age expiry, PID-reuse detection, bounded startup-lock waiting, and wall-clock rollback injection proving duration deadlines remain monotonic;
34
38
  - foreground takeover of active and orphaned background daemons with current service-lock metadata, foreground-process protection, bounded final lock-handoff retry, actual-PID exit waiting, POSIX non-escalating timeout behavior, Windows verified-daemon stop semantics, daemon lock mode/version/process-start metadata, launchd service-target semantics, and silent idempotent duplicate service starts; daemon fixture subprocesses intentionally do not inherit V8 coverage because their purpose is ownership timing rather than code measurement;
35
- - fail-closed service lifecycle ordering for provider-stop, all-workspace daemon-stop, and definition removal, including platform/daemon/removal failure injection and normalized macOS/systemd/Windows results; Windows coverage reproduces an inline `/TR` command above 262 characters, proves the short launcher action remains bounded, verifies least-privilege logon registration, restart/log routing, language-independent `Ready`/`Running` observation, and state-observed stop/removal despite localized nonzero command output;
39
+ - fail-closed service lifecycle ordering for provider-stop, all-workspace daemon-stop, and definition removal, including platform/daemon/removal failure injection and normalized macOS/systemd/Windows results; service-PATH coverage reproduces two nested npm run-script prefixes plus a stale prior candidate runtime and proves the current Node/runtime and inherited user tools remain while npm-private and inactive-runtime entries are removed; Windows coverage reproduces an inline `/TR` command above 262 characters, proves the short launcher action remains bounded, verifies least-privilege logon registration, restart/log routing, language-independent `Ready`/`Running` observation, and state-observed stop/removal despite localized nonzero command output;
36
40
  - private service-environment capture/load coverage for exact allowlisting, value bounds and control-character rejection, non-proxy secret exclusion, runtime-value precedence, Windows case-insensitive replacement, explicit empty-value clearing, and preservation across a later environment-free startup;
37
41
  - machine-level browser-broker ownership/client proxying, authenticated extension origin/subprotocol, non-cacheable local pairing, pairing-token non-disclosure, resource-backed upload routing, broker result redaction, pre-registered runtime-handshake listeners, bounded socket/HTTP waits, direct loopback health despite hostile environment-proxy settings, stop-during-start generation invalidation, frozen-wall-clock browser deadline coverage, installed-application discovery caching, and name-based task matching;
38
42
  - Worker health direct/proxy routing through a real local HTTP CONNECT proxy, `NO_PROXY` bypass, exact `workers.dev` origin/name validation, redirect rejection, body/deadline bounds, error classification, bounded propagation retry, and invalid proxy fail-fast behavior without endpoint or credential disclosure;
@@ -45,6 +49,8 @@ The suite includes:
45
49
  - UTF-8 and binary handling;
46
50
  - image content formatting;
47
51
  - nested Git repository detection and helper suppression;
52
+ - explicit effective-policy versus daemon-ceiling fields in local/remote `project_overview`, reviewer/editor Git metadata through the fixed internal command boundary, and compatibility fallback for older daemon snapshots;
53
+ - fixed internal command execution with validated argv, no shell, isolated HOME/temp/cache, bounded output/deadlines, and ordinary cancellation/process tracking while arbitrary delegated process tools remain sandbox-gated;
48
54
  - author-email privacy in `git_log`;
49
55
  - isolated command HOME/temp/cache behavior;
50
56
  - one-shot timeout, descendant process-group/tree termination including descendants that ignore graceful shutdown after the direct child has already exited, cancellation, and process-session interaction;
@@ -54,11 +60,11 @@ The suite includes:
54
60
  - real-machine canonical-full sandbox acceptance for outside-workspace I/O, direct/shell execution, full environment inheritance, SSH prerequisites, temporary authorized-key writing, and detached cleanup without external state changes;
55
61
  - deterministic injected atomic-replace failures, sustained transient Windows sharing contention beyond the old retry budget, bounded exponential delay selection, and repeated Windows full-sandbox runs;
56
62
  - canonical named-profile repair and full-only tool exposure parity between local and Worker policy filters;
57
- - managed-job staging/local approval/cancel-before-start, detachment, job-scoped temporary files, resource hash verification/redaction, discard capture, finally execution, descendant-tree escalation, token/snapshot-safe transition locks, runner process identity, spawn-without-PID rejection, asynchronous runner-error observability, plan scrubbing, PID-reuse-safe dead-runner recovery, and rejection of numeric-only runner records;
63
+ - managed-job non-executing staging, rejection of the removed terminal promotion path, cancel-before-start, trusted direct start, detachment, job-scoped temporary files, resource hash verification/redaction, discard capture, finally execution, descendant-tree escalation, token/snapshot-safe transition locks, runner process identity, spawn-without-PID rejection, asynchronous runner-error observability, plan scrubbing, PID-reuse-safe dead-runner recovery, and rejection of numeric-only runner records;
58
64
  - daemon/startup locking, successfully-read corrupt-JSON recovery, and explicit propagation/preservation of oversized, symbolic-link, permission, and I/O failures;
59
65
  - guarded state-root removal, unsafe state-root/workspace overlap rejection before creation, all-profile lock/daemon scanning, strict current-schema validation, corrupt-JSON isolation, and policy-origin persistence;
60
66
  - no filename-based sensitive-file denial under unrestricted policy;
61
- - log redaction, control-character handling, message/field bounds, suppression of both successful and failed per-tool events outside debug, service warning-level configuration, current-schema reset, and bounded tail trimming;
67
+ - log redaction, control-character handling, message/field bounds, suppression of both successful and failed per-tool events outside debug, service warning-level configuration, JSON-mode parity across event and direct logger methods with timestamp/stream/redaction assertions, current-schema reset, and bounded tail trimming;
62
68
  - deterministic relay connection lifecycle coverage for transport construction/error/deadline, pre-handshake `welcome` validation, separate `hello_ack` authentication and `ready_ack` end-to-end readiness, session-bound probe return, pre-ready tool rejection, premature-ready rejection, identity/version mismatch, retryable Worker hello/readiness errors, fatal protocol errors, autonomous outage-reminder backoff, handshake/readiness/heartbeat timeout, brief-outage suppression, sustained-outage escalation, recovery summaries, and supersession;
63
69
  - shared no-follow bounded-file reads for normal files, over-limit data, directories, and symbolic links;
64
70
  - owner-only directory enforcement rejecting final symlinks, failing closed on POSIX chmod errors, verifying `0700`, and retaining Windows portability; Worker temporary-secret lifecycle coverage for process-start-bound names, valid stale-owner reclamation, ambiguous-owner retention, `0600` mode, deletion failures, and simultaneous deployment/cleanup failures;
@@ -69,11 +75,12 @@ The suite includes:
69
75
  - byte-exact UTF-8 DOM-source truncation across emoji and Chinese partial-code-point boundaries, including equality between the reported byte count and the encoded returned source;
70
76
  - independently injected service CLI status/install/start/stop/uninstall/remove paths, including provider failure, no selected workspace, no deployed Worker, aliases, and default output/exit adapters;
71
77
  - CLI parsing, policy profiles, and client configuration boundaries;
78
+ - installed-package zero-argument startup with an isolated HOME/state/workspace and a service-manager trap, proving the smoke test reaches the controlled Wrangler boundary without querying, stopping, or replacing the operator's machine-global launchd/systemd/Scheduled Task service;
72
79
  - live stdio MCP initialization with session instructions, capability resolution, discovery, calls, rich content, sessions, cancellation, managed-job acceptance, and a detached job/finally phase that survives stdio shutdown;
73
- - P-256 daemon identity generation, signed WebSocket preflight, one-time transactional nonce consumption, challenge transcript binding, wrong-key/tamper/expiry/replay rejection, and prevention of unauthenticated candidate churn;
74
- - local operation-risk classification and catalog-wide review coverage; authenticated-owner direct execution; account/client-bound compound capability leases for delegated accounts; ordinary workspace automation; external-sensitive path composition; sensitive/persistence writes; symbolic-link ancestor and patch-move destination canonicalization; browser-session/application-control plus data-export composition; process/job continuation; scoped/full approval; cross-process daemon/CLI mutation serialization; expiry/revocation; owner-only persistence; and malformed-record rejection;
75
- - signed account-administration requests with origin/method/path/body/time/nonce binding, transactional one-time nonce consumption, legacy bearer rejection, nonce replay rejection, and malformed nonce-state fail-closed behavior;
76
- - live local Worker OAuth registration, the unauthenticated `resource_metadata` challenge, protected-resource and authorization-server discovery, Streamable transport metadata, consent, URL-constructed `303` callbacks including the ChatGPT and hosted Claude redirect URIs with encoded state, PKCE, `offline_access`, form-encoded authorization-code and refresh-token exchanges, fifteen-minute access tokens, refresh-family idle/absolute limits, bounded consumed-token/revoked-family replay state, record-level schema validation, access/refresh rotation, stale refresh replay rejection with whole-family access/refresh revocation, account-version refresh revocation, authorization-code replay rejection, pending-registration throttling that excludes already authorized DCR clients, exact built-in ChatGPT/Grok browser origins, additive custom origins, unrelated-origin preflight rejection, no CORS response sharing for unrelated or opaque origins, opaque-origin authorization-form routing, exact per-request redirect-origin CSP with narrowly scoped Microsoft regional-consent and final Copilot Studio handoff exceptions, accessible credential-error rendering, protocol negotiation, HMAC-bound MCP session issuance, two-session same-id concurrency, sessionless same-id independence, session-scoped cancellation isolation, same-session duplicate rejection, daemon-backed session bootstrap, dynamic tool advertisement, rich content, candidate/probing/ready transitions, invalid readiness-result rejection, incumbent preservation until verified handover, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure. The metadata/refresh contract is the path used by Claude DCR and Copilot Studio Dynamic discovery. The same integration runs an `editor` account against a canonical `full` daemon and proves that `server_info` and remote `project_overview` report effective `edit` authority while retaining the full daemon ceiling only in explicitly scoped fields.
80
+ - P-256 root generation, root-certified ephemeral session issuance, macOS trust-broker build/signature checks, signed WebSocket preflight, one-time transactional nonce consumption, challenge transcript binding, wrong-root/session/tamper/expiry/replay rejection, and prevention of unauthenticated candidate churn;
81
+ - request-scoped effective authority and catalog-wide risk review; non-escalatable reviewer/editor/operator ceilings; authenticated-owner direct execution; control-plane root denial; external and sensitive path composition; persistence-target rejection; symbolic-link ancestor and patch-move canonicalization; owner-only browser/application/data-export and persistent-plan effects; account/client/refresh-family ownership of processes, output sessions, and jobs; delegated sandbox fail-closed behavior; legacy-lease non-consumption; and malformed-record rejection;
82
+ - root-certified ephemeral P-256 account-administration requests with origin/method/path/body/key/time/nonce binding, transactional one-time nonce consumption, removal of the long-lived administration secret, certificate/signature/body tamper rejection, nonce replay rejection, and malformed nonce-state fail-closed behavior;
83
+ - live local Worker OAuth registration, the unauthenticated `resource_metadata` challenge, protected-resource and authorization-server discovery, Streamable transport metadata, consent, URL-constructed `303` callbacks including the ChatGPT and hosted Claude redirect URIs with encoded state, PKCE, `offline_access`, form-encoded authorization-code and refresh-token exchanges, fifteen-minute access tokens, trusted single-account client binding, optional DPoP proof and token-family binding, unsupported critical-header rejection, proof-verification non-consumption, post-authorization replay consumption, invalid-grant cache-exhaustion resistance, independent client revocation, refresh-family idle/absolute limits, bounded consumed-token/revoked-family replay state, record-level schema validation, access/refresh rotation, stale refresh replay rejection with whole-family access/refresh revocation, account-version refresh revocation, authorization-code replay rejection, pending-registration throttling that excludes already authorized DCR clients, exact built-in ChatGPT/Grok browser origins, additive custom origins, unrelated-origin preflight rejection, no CORS response sharing for unrelated or opaque origins, opaque-origin authorization-form routing, exact per-request redirect-origin CSP with narrowly scoped Microsoft regional-consent and final Copilot Studio handoff exceptions, accessible credential-error rendering, protocol negotiation, HMAC-bound MCP session issuance, two-session same-id concurrency, sessionless same-id independence, session-scoped cancellation isolation, same-session duplicate rejection, daemon-backed session bootstrap, dynamic tool advertisement, rich content, candidate/probing/ready transitions, invalid readiness-result rejection, incumbent preservation until verified handover, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure. The metadata/refresh contract is the path used by Claude DCR and Copilot Studio Dynamic discovery. The same integration runs an `editor` account against a canonical `full` daemon and proves that `server_info` and remote `project_overview` report effective `edit` authority while retaining the full daemon ceiling only in explicitly scoped fields.
77
84
  - local runtime proof that one blocked tool handler does not serialize an independent handler, plus relay fault injection proving an undeliverable terminal result interrupts the ambiguous socket and enters reconnect backoff.
78
85
  - a real headless-Chrome OAuth navigation regression with four cases: `form-action 'self'` blocks the first cross-origin callback, allowing only the registered callback blocks the regional redirect, allowing the registered and regional callbacks blocks the final Copilot Studio redirect, and the complete policy preserves `code` and `state` through all three cross-origin hops. Linux CI fails if Chrome is unavailable; other environments skip only this browser executable check while retaining the Worker CSP assertions.
79
86
 
@@ -90,6 +97,11 @@ It opens Calculator, activates it through the fixed JXA helper, verifies structu
90
97
  For deterministic release validation, perform an isolated-profile smoke test with the packaged unpacked extension; a Playwright persistent Chromium context is acceptable only as that isolated harness. When the requirement is specifically to prove control of the user's ordinary browser, the user must load the same unpacked directory into that known daily Chromium profile; status can verify the extension version/protocol and that Machine Bridge did not launch a browser, but cannot infer profile identity. Then use a localhost no-store fixture in a newly created tab. Do not enumerate, read, or mutate unrelated existing tabs. In both modes, inspect and reuse refs, exercise waits/forms/trusted input/open Shadow DOM/screenshots, verify final live DOM, and close the fixture tab.
91
98
 
92
99
 
100
+ - relay outage diagnostics and recovery: application-proxy versus OS-network scope, timestamped close/outage/recovery fields, fifteen-second maximum reconnect delay, heartbeat timeout, same-instance call continuation, Worker pong/welcome send failure, and `diagnose_runtime` relay history;
101
+ - recoverable managed-job terminal commits under injected result/status/delete/confirmation failures, result-only terminal reconstruction, private runtime/plan scrubbing, 24-hour staged-plan expiry, and minimal/full runner-environment inheritance;
102
+ - cross-process security-audit serialization, continuous hash-chain sequence, uninstall blocking for audit/authorization/job transition/recovery locks, workspace recovery-envelope validation, and symlink/multiple-hard-link rejection at owner state and operational logs;
103
+ - browser fixed identity, role-separated credentials, legacy migration, socket replacement/reconnect/timer cleanup, duplicate request rejection, response-delivery failure, and read-only broker load projection;
104
+
93
105
  ## Critical-module coverage gate
94
106
 
95
107
  `npm run coverage:test` runs selected in-process and lightweight entrypoint fixtures under V8 coverage and enforces per-module function and branch baselines. The measured set includes policy, typed errors, call registration, execution middleware, lifecycle/observability, logging, Runtime/CLI orchestration, state persistence, relay lifecycle, managed-job lifecycle/runner/storage/projection, browser broker/direct-request/runtime-client routing and loopback upgrade handling, the independently injected service CLI adapter, Agent configuration/projection/skill discovery and bounded text reads, capability ranking, runtime path redaction, browser protocol/operation boundaries, runtime reporting/diagnostics/capability composition, and Worker OAuth state/authorization-page/pending/policy/error/JSON-RPC/WebSocket protocol modules. The full stdio and workerd OAuth/MCP integration still runs separately.
@@ -1,142 +1,213 @@
1
1
  # Threat model
2
2
 
3
- This document defines the security claims Machine Bridge is designed to make and the claims it explicitly does not make. It complements [SECURITY.md](../SECURITY.md) and the implementation detail in [ARCHITECTURE.md](ARCHITECTURE.md).
3
+ This document defines the security claims Machine Bridge is designed to make and the claims it explicitly does not make. It complements [SECURITY.md](../SECURITY.md), [LOCAL_AUTHORIZATION.md](LOCAL_AUTHORIZATION.md), and [ARCHITECTURE.md](ARCHITECTURE.md).
4
4
 
5
5
  ## Scope
6
6
 
7
- Machine Bridge combines a remote OAuth relay, a high-authority local runtime, optional local stdio transport, persistent managed jobs, and a browser extension. The primary security objective is to ensure that only explicitly authorized, policy-permitted operations cross those boundaries, with bounded inputs, fail-closed state transitions, and minimal sensitive observability.
7
+ Machine Bridge combines:
8
8
 
9
- The local runtime executes as the current OS user. Policy profiles restrict Machine Bridge behavior; they do not replace kernel, account, VM, container, browser-profile, or endpoint-security isolation.
9
+ - a public OAuth and MCP endpoint on a Cloudflare Worker;
10
+ - an authenticated relay to a high-authority local daemon;
11
+ - optional local stdio transport;
12
+ - filesystem, Git, process, browser, and application automation;
13
+ - persistent managed jobs and registered local resources;
14
+ - a browser extension operating in an existing user profile.
15
+
16
+ The local runtime executes as the current OS user. Application policies restrict Machine Bridge behavior, but they do not replace kernel, account, VM, container, browser-profile, or endpoint-security isolation.
10
17
 
11
18
  ## Assets
12
19
 
13
- The main protected assets are:
20
+ Protected assets include:
14
21
 
15
- - workspace and local-user-accessible files;
16
- - process execution authority and inherited environment values;
17
- - daemon device private key, account-administration HMAC key, account password verifiers, OAuth authorization codes, access tokens, refresh tokens, and local capability leases;
18
- - Worker and Durable Object routing state;
19
- - owner-only profile, lock, resource, service, and managed-job state;
20
- - registered local resource contents and paths;
21
- - browser pairing token, browser cookies, authenticated sessions, tabs, page content, and file-upload authority;
22
- - release candidate hashes, observed-verification acceptance records, package contents, and source-release integrity;
23
- - logs and diagnostics that could reveal paths, credentials, arguments, results, or user content.
22
+ - workspace files and other files reachable by the local OS user;
23
+ - process execution authority, process sessions, retained output, and inherited environment values;
24
+ - the device root, root-certified ephemeral session keys, OAuth account password verifiers, authorization codes, access tokens, refresh-token families, DPoP bindings, and trusted-client records;
25
+ - Machine Bridge state, locks, service metadata, native broker files, audit-chain state, registered-resource metadata, and managed-job plans/output;
26
+ - browser pairing state, cookies, authenticated sessions, tabs, page content, form values, screenshots, and upload authority;
27
+ - Worker and Durable Object routing, nonce, account, client, token, and pending-call state;
28
+ - release candidate hashes, package contents, acceptance records, and source-release integrity;
29
+ - logs and diagnostics that could reveal paths, credentials, arguments, output, or user content.
24
30
 
25
31
  ## Trust boundaries
26
32
 
27
33
  ### Hosted client to Worker
28
34
 
29
- The hosted client and its prompts, tools, extensions, and retrieved content are not automatically trusted. The Worker must validate OAuth state, PKCE, redirect and resource binding, account role/version, token expiry/rotation, MCP session state, request shape, body bounds, and allowed tool exposure.
35
+ The hosted MCP client, its prompts, tools, extensions, and retrieved content are not automatically trusted. The Worker validates:
36
+
37
+ - OAuth state, PKCE, redirect URI, resource binding, and request size;
38
+ - account status, account version, account role, trusted client binding, token expiry, and refresh-family state;
39
+ - DPoP proof method, target URL, timestamp, unique identifier, access-token hash, and key thumbprint when DPoP is used;
40
+ - MCP session state, protocol version, method shape, request IDs, cancellation, and allowed tool exposure.
41
+
42
+ A client registration is not authority. Authority begins only after successful account authorization binds the client to one account and role version.
30
43
 
31
44
  ### Worker to local daemon
32
45
 
33
- The Worker is a relay and authorization layer, not a source of local authority. The daemon accepts only a version-compatible relay that proves possession of the enrolled P-256 device key in both a signed upgrade preflight and a Worker challenge. End-to-end readiness requires a local probe result through the active session. Every remote tool call carries bounded account and OAuth-client identity that is rechecked locally, followed by effect-level local transaction authorization.
46
+ The Worker is a relay and authorization layer, not the source of local OS authority.
47
+
48
+ The daemon connection requires:
49
+
50
+ 1. a root-signed ephemeral device-session certificate;
51
+ 2. a signed, nonce-bound WebSocket preflight using that session key;
52
+ 3. a fresh Worker challenge bound to the daemon instance;
53
+ 4. version compatibility;
54
+ 5. an end-to-end readiness probe delivered through the same result path as real calls.
55
+
56
+ A replacement candidate does not displace a healthy daemon until those checks complete.
57
+
58
+ Each remote tool call carries account ID, account version, OAuth client ID, refresh-family ID, and role. The local runtime recomputes effective authority and applies object ownership and operation classification before dispatch.
34
59
 
35
60
  ### MCP host to local stdio process
36
61
 
37
- A local MCP host can invoke every tool allowed by the selected daemon policy. The host, model output, repository instructions, and retrieved content may be malicious or prompt-injected. A permissive policy therefore grants meaningful local-user authority.
62
+ Stdio is a local-owner transport. It does not use remote OAuth accounts or the relay device root. The local MCP host can invoke every tool allowed by the selected local policy.
63
+
64
+ The host, model output, repository instructions, and retrieved content may be malicious or prompt-injected. A permissive local policy therefore grants meaningful local-user authority.
38
65
 
39
66
  ### Local runtime to operating system
40
67
 
41
- The runtime relies on the OS account, filesystem permissions, macOS TCC/SIP, Windows ACLs, container/VM boundaries, and endpoint controls. Canonical workspace checks prevent path escape only when unrestricted paths are disabled. They do not protect against a malicious process already running with the same OS-user authority.
68
+ The runtime relies on OS-user identity, filesystem permissions, process controls, macOS TCC/SIP, Windows ACLs, endpoint controls, and any VM/container boundary.
69
+
70
+ For delegated process execution, Machine Bridge requires a behaviorally verified OS sandbox. If the negative boundary cannot be demonstrated, delegated execution fails closed. Owner execution is not sandboxed by Machine Bridge. Fixed implementation-owned Git metadata probes are not caller-selected process authority: they use code-constructed argv, no shell, an isolated minimal environment, bounded deadlines/output, and ordinary cancellation/process tracking.
42
71
 
43
72
  ### Local runtime to browser extension
44
73
 
45
- The broker is loopback-only and pairing-token protected. The extension origin, protocol version, build version, capabilities, and handshake state are validated. The extension still runs inside a real browser profile and can reach the tabs, sessions, and origins granted by browser permissions.
74
+ The broker is loopback-only and pairing-token protected. Extension origin, protocol/build version, capabilities, owner/client route, and handshake state are validated.
75
+
76
+ The extension still operates inside a real browser profile. It can reach tabs, authenticated sessions, and origins granted by browser permissions. Only the `owner` role may use browser-session control or export local data into it.
46
77
 
47
78
  ### Local runtime to persistent state
48
79
 
49
- State paths, locks, plans, resources, and service definitions are security-sensitive. Reads are bounded and symlink-aware; writes use owner-only modes where supported and atomic replacement; locks bind tokens to process identity and start time; destructive removal validates ownership and expected layout.
80
+ State paths, roots, locks, plans, resources, native broker files, and service definitions are security-sensitive.
81
+
82
+ Machine Bridge uses bounded reads, canonical path resolution, owner-only modes where supported, atomic replacement, process-identity locks, schema validation, and explicit lifecycle transitions. Generic path-based tools cannot target Machine Bridge control-plane roots, even under `owner/full`. An authorized owner shell remains equivalent to same-user code execution and is outside that path boundary.
83
+
84
+ ### Device root to ephemeral session
85
+
86
+ The default root is portable owner-only P-256 material, including on macOS, and is therefore readable by a determined same-user process. A non-exportable Secure Enclave root is available only through an explicitly configured app-like broker with provisioning-profile-validated Keychain access, a strict Apple code signature, stable Team ID, canonical non-symlink path with no group/other write access, and a successful real key probe. Either root signs one bounded ephemeral session certificate at daemon startup. WebSocket reconnect and account-administration requests use the in-memory session key, not the root.
87
+
88
+ The portable provider stores an exportable private JWK in owner-only state and therefore provides weaker theft resistance. `server_info` reports the provider and exportability.
89
+
90
+ Broker binding detects path, identifier, Team ID, signature, and capability drift. It does not protect against a malicious replacement signed by the same trusted Apple team and identifier. Production broker installations should therefore be root-owned or otherwise non-writable by the daemon user, with signing-key protection and update governance treated as external trust dependencies.
50
91
 
51
92
  ### Maintainer to release infrastructure
52
93
 
53
- Repository checks reduce accidental or malicious package drift, but source hosting, npm ownership, protected environments, maintainer accounts, and human review remain external trust dependencies. Repository automation cannot manufacture independent review or claim live candidate success without observing the explicitly owner-authorized candidate. It may record acceptance after that observed verification.
94
+ Repository checks reduce package drift and accidental release mistakes. Source hosting, npm ownership, Apple signing identities, protected environments, maintainer accounts, and independent review remain external trust dependencies.
95
+
96
+ The local signature binds the self-hosted broker bytes used by this installation. Public third-party binary distribution would be a separate trust model and is outside the current package workflow.
54
97
 
55
98
  ## Attacker models
56
99
 
57
- Machine Bridge considers the following attackers and failure sources:
100
+ Machine Bridge considers:
58
101
 
59
- 1. **Malicious or compromised hosted MCP client** attempting unauthorized tools, token replay, OAuth redirect abuse, request smuggling, duplicate IDs, cancellation races, or excessive resource use.
60
- 2. **Malicious local MCP host or model output** attempting to use allowed tools for destructive actions, credential discovery, shell injection, or persistence.
61
- 3. **Malicious repository content** including instructions, package scripts, Git configuration, paths, symlinks, generated metadata, or files designed to influence an agent or execution boundary.
62
- 4. **Malicious webpage or browser content** attempting prompt injection, deceptive selectors, sensitive-field disclosure, unsafe navigation, replay after ambiguous input dispatch, or extension-protocol abuse.
63
- 5. **Local same-user process** attempting to race locks, replace files, impersonate stale processes, read local state, or interfere with loopback services.
64
- 6. **Network attacker or misconfigured proxy** attempting interception, redirect manipulation, credential disclosure, stale deployment evidence, or ambiguous timeout outcomes.
65
- 7. **Compromised dependency or build input** attempting package substitution, mutable workflow execution, install-script abuse, release drift, or sensitive artifact inclusion.
66
- 8. **Operational failure** such as abrupt termination, PID reuse, clock rollback, partial writes, disk/permission errors, service-manager races, stale browser builds, or daemon replacement during active calls.
102
+ 1. **A malicious or compromised hosted MCP client** attempting unauthorized tools, account switching, token theft/replay, OAuth redirect abuse, request duplication, cancellation races, or resource exhaustion.
103
+ 2. **A malicious local MCP host or model output** attempting destructive operations, credential access, shell injection, persistence, or data export through an allowed local-owner policy.
104
+ 3. **Malicious repository content** including instructions, package scripts, Git hooks/configuration, symlinks, generated metadata, or files designed to influence an agent or execution boundary.
105
+ 4. **Malicious web or browser content** attempting prompt injection, deceptive selectors, sensitive-field disclosure, unsafe navigation, ambiguous input dispatch, or extension-protocol abuse.
106
+ 5. **A local same-user process** attempting to read state, race locks, replace files, inspect memory, impersonate stale processes, or interfere with loopback services.
107
+ 6. **A network attacker or misconfigured proxy** attempting interception, redirect manipulation, stale deployment evidence, connection truncation, replay, or ambiguous timeout outcomes.
108
+ 7. **A compromised dependency or build input** attempting package substitution, install-script abuse, workflow mutation, release drift, or sensitive artifact inclusion.
109
+ 8. **Operational faults** including abrupt termination, PID reuse, clock anomalies, partial writes, permission errors, Keychain failures, service-manager races, stale extension builds, and daemon replacement during active calls.
67
110
 
68
111
  ## Security objectives
69
112
 
70
113
  The implementation aims to preserve these invariants:
71
114
 
72
- - deny unknown, malformed, stale, duplicated, unauthorized, or over-limit requests;
73
- - intersect remote account authority with the daemon capability ceiling in both Worker and local runtime;
74
- - permit authenticated owner automation directly within the daemon ceiling while binding delegated high-impact effects to local account/client-scoped, time-bounded capability leases;
75
- - keep transport authentication, account/tool authorization, transaction authorization, and OS authority separate;
76
- - use direct argv execution without shell interpretation unless the explicit shell tool is authorized;
77
- - canonicalize confined paths and reject symlink-based write escape;
78
- - bound request bodies, messages, files, output, logs, state, retained results, and concurrency;
79
- - ensure cancellation, timeout, disconnect, replacement, and shutdown have explicit process ownership and cleanup semantics;
80
- - prevent a candidate daemon or extension from displacing a healthy incumbent before compatibility/readiness validation;
81
- - avoid exposing secrets, arguments, results, resource contents, account credentials, or raw local paths in default logs and public metadata;
82
- - make multi-stage state and file mutations atomic or recoverable without silent partial success;
83
- - bind managed-job plans and release acceptance to cryptographic content hashes;
84
- - fail closed when state, ownership, permissions, process identity, or destructive cleanup cannot be verified;
85
- - keep supply-chain actions pinned, minimally permissioned, reviewed, and separately gated.
115
+ - unknown, malformed, stale, replayed, duplicated, unauthorized, and over-limit input is rejected;
116
+ - remote authority is the intersection of daemon policy and account role, never the union;
117
+ - no approval record, token refresh, or local migration state can elevate a delegated role;
118
+ - OAuth clients are bound to one account/version/role and can be revoked independently;
119
+ - long-lived runtime objects are bound to account, account version, OAuth client, and refresh family;
120
+ - generic path-based remote tools cannot target Machine Bridge control-plane state;
121
+ - sensitive paths, persistence targets, browser/desktop control, data export, and persistent job creation are owner-only;
122
+ - delegated process execution is accepted only when an OS sandbox is behaviorally verified;
123
+ - direct argv execution is used unless the explicit shell tool is authorized;
124
+ - confined paths are canonicalized and symbolic-link write escape is rejected;
125
+ - request bodies, files, messages, output, logs, state, retained results, and concurrency are bounded;
126
+ - cancellation, timeout, disconnect, replacement, and shutdown have explicit process ownership and cleanup semantics;
127
+ - candidate daemons and browser extensions cannot replace healthy incumbents before compatibility and readiness verification;
128
+ - default logs and audit records omit secrets, arguments, contents, raw paths, form values, and output;
129
+ - multi-stage mutations are atomic or recoverable and do not silently claim partial success;
130
+ - device-root rotation is two-phase and does not promote an undeployed key;
131
+ - supply-chain actions are pinned, minimally permissioned, reviewed, and separately gated.
86
132
 
87
133
  ## Non-goals
88
134
 
89
- Machine Bridge does **not** claim to provide:
135
+ Machine Bridge does not claim to provide:
90
136
 
91
- - kernel-enforced sandboxing, CPU/memory quotas, syscall filtering, or network isolation;
92
- - hard multi-tenant isolation between mutually untrusted users sharing one daemon and OS account;
137
+ - kernel-enforced sandboxing for `owner`, universal syscall filtering, or universal network isolation;
138
+ - OS CPU, memory, disk, or bandwidth quotas;
139
+ - hard multi-tenant isolation between mutually untrusted humans sharing one daemon and OS account;
93
140
  - protection from root, an administrator, or a fully compromised same-user account;
94
- - complete prevention of prompt injection or malicious instructions when an authorized tool can perform the requested action;
141
+ - complete prevention of prompt injection when an authorized tool can perform the requested action;
95
142
  - semantic detection of every secret, transformed credential, private document, or dangerous command;
96
- - proof that the browser extension is loaded in a safe or isolated profile;
97
- - rollback of a browser or external-system action after an ambiguous dispatch failure;
143
+ - proof that the browser extension is loaded in an isolated profile;
144
+ - rollback of a browser or external-system action after ambiguous dispatch;
145
+ - an atomic rollback transaction spanning Cloudflare Worker deployment and every local service manager;
146
+ - repair or node selection inside a third-party system VPN/TUN;
98
147
  - guaranteed cleanup after power loss, kernel failure, filesystem corruption, or an uncooperative external platform;
99
- - independent human code review while the project has only one active maintainer;
100
- - npm trusted publishing until the package owner configures external OIDC trust and a protected publication environment.
148
+ - hardware-backed key storage on every operating system;
149
+ - third-party public binary-store identity or independent distributor attestations;
150
+ - independent human review while the project has only one active maintainer.
101
151
 
102
152
  ## Residual risks
103
153
 
104
- ### Canonical `full` profile
154
+ ### Owner and canonical `full`
105
155
 
106
- `full` intentionally preserves the complete catalog, unrestricted local-user paths, shell execution, parent environment, browser/application authority, and absolute path output. Version 2.0 treats the authenticated owner role as authorization to use that ceiling without a second terminal prompt. This prioritizes uninterrupted owner automation: compromise of an active owner OAuth client can exercise the complete daemon ceiling. Delegated accounts remain lease-bound for higher-impact effects. A malicious delegated client holding both valid OAuth credentials and an active matching lease can still act destructively within that lease. A temporary `full` lease is therefore an explicit automation window, not a sandbox or an endorsement of untrusted instructions. Use a narrower profile or a separate low-privilege OS boundary for mutually untrusted workloads.
156
+ `full` intentionally preserves the complete catalog, unrestricted local-user paths, shell execution, parent environment, browser/application authority, managed jobs, and absolute path output.
107
157
 
108
- ### Application and browser automation
158
+ A compromised active owner client can exercise the daemon ceiling without a second per-operation prompt. The design reduces prompt fatigue and avoids insecure copy-and-retry approval ceremonies, but it makes client trust, token protection, DPoP support, account revocation, and endpoint isolation critical.
109
159
 
110
- UI state can change between inspection and action. Pages can present deceptive content, and an authenticated browser profile may contain high-value sessions. Trusted input and replay controls reduce specific failure modes but do not make arbitrary web content trustworthy.
160
+ Use a narrower profile, separate OS account, container, or VM when prompts, repositories, clients, or workloads are mutually untrusted.
111
161
 
112
- ### Package scripts and registered commands
162
+ ### Bearer clients
113
163
 
114
- Automatic command discovery does not inject script bodies into prompts, but invoking a package script still executes repository-controlled code. The active policy and human approval remain decisive.
164
+ DPoP is optional for interoperability. A Bearer token can be used by whoever possesses it until expiry or revocation. Short access-token lifetime, rotating refresh families, client binding, account versioning, and replay-family revocation reduce but do not eliminate token theft risk.
115
165
 
116
166
  ### Same-user interference
117
167
 
118
- Owner-only permissions and process-identity locks reduce accidental and cross-account interference. They cannot reliably defend against a determined process running as the same OS user with equivalent filesystem and process rights.
168
+ Owner-only permissions, optional provisioned Secure Enclave roots, control-plane path denial, process-identity locks, and audit chains reduce several attacks. They cannot prevent a determined same-user process from reading portable credentials, inspecting process memory, changing source before execution, or interfering with local services.
169
+
170
+ ### Delegated sandbox availability
171
+
172
+ Delegated execution is unavailable when the platform sandbox cannot pass the negative-boundary probe. This is an intentional availability trade-off. Replacing fail-closed behavior with an unverified path blacklist would create false isolation.
173
+
174
+ ### Browser and application automation
175
+
176
+ UI state can change between inspection and action. Pages can present deceptive content, and authenticated profiles may contain high-value sessions. Protocol checks and trusted-input handling do not make arbitrary web content trustworthy.
177
+
178
+ ### Managed jobs
179
+
180
+ Managed jobs outlive MCP calls and daemon reconnects. Plans and resources are validated and ownership-bound, but an authorized owner plan can still consume resources or perform destructive work. Finally steps must be idempotent because recovery may retry them.
119
181
 
120
182
  ### Availability and resource exhaustion
121
183
 
122
- Concurrency, message, output, and timeout limits bound many application-level resources. The daemon does not enforce OS CPU, memory, disk, or network quotas, so an authorized process can still consume host resources.
184
+ Application-level limits bound many requests and outputs. An authorized owner process can still exhaust CPU, memory, disk, network, or external service quotas.
185
+
186
+ ### System VPN/TUN and distributed activation
187
+
188
+ A system VPN/TUN can remain administratively connected while its selected upstream route, synthetic DNS mapping, or transport path is temporarily unusable. Machine Bridge can detect missing inbound relay traffic, classify the socket close, bound retry delay, and report outage history, but it cannot select or repair a third-party VPN node. `system-network-stack` is therefore not a claim of direct routing.
189
+
190
+ Candidate activation verifies the foreground candidate before service handoff and records exact package/deployment evidence. It does not provide an atomic transaction spanning Cloudflare deployment and every local service manager. If the Worker changes and the local handoff later fails, the operator may need the recorded previous runtime/deployment evidence to complete rollback. Local cleanup errors are aggregated rather than hidden, but remote rollback is not fabricated.
123
191
 
124
192
  ### External governance and publication
125
193
 
126
- Code cannot create a second independent reviewer, npm OIDC trust relationship, protected environment, or OpenSSF Best Practices registration. Those controls remain explicit external work rather than simulated repository compliance.
194
+ Code cannot create a second independent reviewer, npm OIDC trust relationship, protected publication environment, Apple Developer identity, or external certification. These remain explicit operational requirements.
127
195
 
128
196
  ## Validation map
129
197
 
130
- The main regression suites cover:
198
+ Regression suites cover:
131
199
 
132
- - OAuth, refresh-family replay revocation, signed administration requests, account, policy, device-authenticated daemon readiness, relay replacement, and local capability leases;
133
- - path confinement, atomic writes, state locks, service lifecycle, managed-job recovery, and destructive cleanup;
134
- - direct process boundaries, shell separation, process-tree termination, timeout, cancellation, and disconnect;
135
- - browser pairing, version/capability handshake, owner/client broker routing, sensitive-field handling, trusted input, and CSP navigation;
136
- - privacy redaction, package contents, release impact, interactive candidate acceptance, dependency integrity, CodeQL, and Scorecard findings;
200
+ - account roles, trusted clients, account-version revocation, refresh-family rotation/replay, DPoP proofs, and non-escalatable effective authority;
201
+ - root-certified ephemeral sessions, preflight nonce replay, daemon challenge binding, readiness, reconnect, and candidate replacement;
202
+ - signed account administration, client revocation, and removal of the long-lived administration secret;
203
+ - control-plane path denial, path canonicalization, symlink handling, sensitive/persistence targets, and object ownership;
204
+ - delegated sandbox behavior and fail-closed platform detection;
205
+ - process/session cleanup, managed-job lifecycle and recovery, state locks, atomic persistence, and destructive removal;
206
+ - browser pairing, version/capability handshake, broker routing, sensitive input, and navigation controls;
207
+ - audit-chain integrity, privacy redaction, package contents, installation, release impact, dependency integrity, CodeQL, and Scorecard findings;
137
208
  - malformed, over-limit, concurrent, replayed, stale, and fault-injected inputs.
138
209
 
139
- See [TESTING.md](TESTING.md) for the complete test inventory and [AUDIT.md](AUDIT.md) for reviewed failures and residual limitations.
210
+ See [TESTING.md](TESTING.md) for the test inventory and [AUDIT.md](AUDIT.md) for historical findings and residual limitations.
140
211
 
141
212
  ## Reporting
142
213
 
@@ -2293,9 +2293,9 @@ Generate or reuse an Ed25519 SSH key pair on the local machine and register the
2293
2293
 
2294
2294
  ## `stage_job`
2295
2295
 
2296
- **Stage managed job for local approval**
2296
+ **Stage managed job draft**
2297
2297
 
2298
- Validate and persist a managed-job plan without starting any process. Use this when execution tools are unavailable or local operator review is required; launch later with machine-mcp job approve JOB_ID.
2298
+ Validate and persist a durable managed-job draft without starting any process. This is a non-executing record only; a trusted owner client starts work with start_job after reviewing or reconstructing the plan.
2299
2299
 
2300
2300
  | Contract field | Value |
2301
2301
  |---|---|
package/docs/UPGRADING.md CHANGED
@@ -2,37 +2,121 @@
2
2
 
3
3
  ## Supported upgrade contract
4
4
 
5
- Machine Bridge does not retain parallel implementations for obsolete MCP protocol dates, policy revisions, state schemas, lock formats, or browser-extension protocols. The supported path is a direct upgrade from the immediately preceding published package while its state already uses the current schema.
5
+ Machine Bridge supports direct upgrade from the immediately preceding published release. Obsolete transport, state, lock, browser-extension, and authorization implementations are not retained as hidden compatibility paths.
6
6
 
7
- Version 2.0.0 is a coordinated Worker/daemon security-protocol upgrade. It replaces the long-lived daemon bearer with a P-256 device identity, replaces network account-administration bearer requests with per-request HMAC signatures, shortens OAuth access tokens, introduces refresh-token families and replay revocation, and adds local capability leases for high-impact remote effects. The Worker and daemon must converge on 2.0.0 together; the removed daemon bearer protocol is not retained as a fallback.
7
+ Version 3.0.0 is a coordinated Worker, daemon, CLI, and browser-extension security upgrade. Mixed 2.x and 3.x components are intentionally unavailable.
8
8
 
9
- On the first 2.0.0 state load, a workspace without a device identity generates one locally, removes the legacy daemon secret, and rotates the deployment-wide OAuth token version. Existing pre-2.0 access and refresh credentials therefore fail closed and every client must authorize again. The device private JWK remains in owner-only local state; only the public JWK is deployed to the Worker. Subsequent ordinary starts preserve both the device identity and token version.
9
+ The major changes are:
10
10
 
11
- The canonical `full` profile is unchanged as a capability ceiling. Authenticated owner operations use that ceiling directly without terminal approval. High-impact operations from delegated non-owner accounts require a local account/client-bound lease, while their normal workspace-contained reads and edits and project inspection remain automatic. Because the packaged extension controls an existing browser profile, one `browser-session` lease covers profile reads and actions; registered-resource input or file upload uses the separate `data-export` scope. An operator may approve the requested scope or explicitly open a temporary `full` window for at most eight hours. Lease state is independent of the policy profile and does not migrate into OAuth credentials.
11
+ - account roles become non-escalatable hard ceilings;
12
+ - terminal approval IDs and runtime capability leases are removed from authorization;
13
+ - OAuth clients become persistently bound to one account and role version;
14
+ - process sessions, retained output, and managed jobs bind to account, client, and refresh-token family;
15
+ - account administration moves from a long-lived symmetric secret to root-certified ephemeral P-256 session signatures;
16
+ - daemon connections use a root-certified 24-hour in-memory session key;
17
+ - macOS can use a non-exportable Secure Enclave root only through an explicitly configured, provisioning-profile-validated broker; otherwise it retains the portable owner-only root;
18
+ - supported OAuth clients may use DPoP-bound access and refresh tokens;
19
+ - generic path-based remote file access to Machine Bridge control-plane state is denied even to `owner`; arbitrary owner shell execution remains local-user authority;
20
+ - delegated process execution requires a behaviorally verified OS sandbox and otherwise fails closed;
21
+ - local security events form a bounded, privacy-preserving hash chain.
12
22
 
13
- Version 1.2.0 could accept prototype-shaped account roles through malformed administration input. On the first 1.2.1 or later Worker access, such an account is preserved for recovery but repaired fail-closed: its role becomes `reviewer`, it is disabled, its account version advances, and its authorization codes and tokens are removed. An operator can then assign a valid role, enable the account, and rotate its password through the normal account administration flow. A local policy record with an unknown profile label is normalized to `custom` while retaining its explicit capability fields; an invalid explicit `--profile` is rejected.
23
+ ## Version 2 to version 3
14
24
 
15
- A state file from an older unsupported schema is rejected rather than guessed or silently rewritten. Upgrade an old installation through the last release that understands its schema, or initialize a new workspace and re-register resources. Do not edit schema numbers by hand.
25
+ ### Device-root migration
26
+
27
+ `3.0.0-beta.1`, `3.0.0-beta.2`, `3.0.0-beta.3`, `3.0.0-beta.4`, `3.0.0-beta.5`, and `3.0.0-beta.6` are blocked and must not be activated, accepted, published, or promoted. Beta.1 changed the canonical JWK member order used by version 2 device identifiers. Beta.2 repaired that compatibility issue but attempted to create a persistent Secure Enclave key from an ad-hoc-signed runtime helper, which macOS rejected with `errSecMissingEntitlement` (`-34018`). Beta.3 completed owner activation but exposed delegated project/Git authority defects. Beta.4 corrected those defects, yet continued owner-machine auditing found service-control self-termination, timestamp-less mixed-format logs, system-VPN relay outages amplified by a sixty-second reconnect cap, and additional state/browser/job/process boundaries. Beta.5 corrected those findings and passed live Worker/daemon/start/restart verification, but its launchd definition captured npm lifecycle PATH injection and the prior candidate runtime that activation then removed. Beta.6 removed stale candidate paths but selected only the first npm marker; nested npm activation retained an inner project-bin prefix. None of the blocked candidates intentionally rotated or invalidated the existing portable device root.
28
+
29
+ `3.0.0-beta.7` retains the portable P-256 root by default and is the next supported candidate path. It includes the beta.5 authority, relay, state, browser, managed-job, process-tree, audit-lock, hard-link, and service-lifecycle corrections, then makes the persistent service PATH independent of nested npm lifecycle injection and inactive candidate runtimes. Normal startup performs no Keychain operation and requests no user presence unless an explicitly provisioned broker is configured.
30
+
31
+ Secure Enclave enrollment is optional and explicit. Set `MBM_MACOS_TRUST_BROKER` to the absolute executable path inside an app-like broker that is signed by an Apple development or distribution identity and whose data-protection Keychain entitlements are validated by an embedded provisioning profile. Machine Bridge then verifies that the path is a non-symlink regular executable, rejects group/other-writable files, verifies the strict code signature, records the signing identifier and Team ID, and performs an end-to-end create/delete probe with a temporary Secure Enclave key. A source-built or ad-hoc-signed helper is intentionally rejected.
32
+
33
+ When a provisioned broker is configured, migration remains two-phase:
34
+
35
+ 1. the broker creates the non-exportable key and Machine Bridge stores only its canonical broker binding, public JWK, key ID, and Keychain tag as `pendingDeviceIdentity`;
36
+ 2. the Worker is deployed with that pending public key;
37
+ 3. Worker health and exact-version convergence are verified;
38
+ 4. only then is the pending root promoted to active state.
39
+
40
+ A failed probe, upload, interrupted process, or failed health check leaves the old active root intact. `--daemon-only` refuses to activate an undeployed pending root. Every later public-key check and signature revalidates the canonical broker path, code-signing identifier, and Team ID.
41
+
42
+ Other platforms, and macOS installations without a provisioned broker, use the portable P-256 provider. Its private JWK remains owner-only local state and is explicitly reported as exportable.
43
+
44
+ ### OAuth clients and tokens
45
+
46
+ Existing clients may need to authorize again so the Worker can record the new trusted account binding. A refresh token whose client record is not bound to the current account version and role fails closed.
47
+
48
+ Access tokens remain short-lived. Refresh tokens remain one-time rotating and family-bound. Reuse of an already-rotated refresh token revokes the complete family, including active access tokens.
49
+
50
+ DPoP is optional. A client that supports DPoP may bind its token family to a P-256 key; clients without DPoP continue with Bearer tokens under the same account, client, role, and family checks.
51
+
52
+ ### Removed authorization workflows
53
+
54
+ Version 3 does not create or consume pending approval IDs. The following workflows are obsolete:
55
+
56
+ ```text
57
+ machine-mcp approval approve ...
58
+ machine-mcp approval grant ...
59
+ machine-mcp job approve ...
60
+ ```
61
+
62
+ Legacy version 2 lease state may be listed, revoked, or cleared for cleanup, but it has no effect on runtime authority.
63
+
64
+ `stage_job` is a non-executing draft and cannot be promoted by a terminal approval command. A trusted owner uses `start_job`; a local machine operator may submit a reviewed plan with `machine-mcp job submit PLAN.json`.
65
+
66
+ ### Removed administration secret
67
+
68
+ `ACCOUNT_ADMIN_SECRET` is deleted from local state and is no longer deployed to the Worker. Account and OAuth-client administration uses the same root-certified ephemeral session established for daemon startup or an independently authorized local administration command.
16
69
 
17
70
  ## Normal upgrade
18
71
 
19
- 1. Finish or cancel ordinary interactive process sessions. Accepted managed jobs may continue independently, but inspect them before replacing the daemon.
20
- 2. Install the new package with the pinned npm procedure in [Getting started](GETTING_STARTED.md).
21
- 3. Run `machine-mcp doctor`.
22
- 4. Start `machine-mcp` normally in the foreground for each workspace. Startup generates the device identity if needed, rotates the old deployment token version, deploys the matching public key and 2.0.0 Worker, verifies end-to-end readiness, and only then may replace the prior service daemon.
23
- 5. Reauthorize every remote MCP client. Pre-2.0 access and refresh tokens are intentionally invalid.
24
- 6. Reload the unpacked browser extension. Protocol and packaged-version equality are mandatory; an old extension cannot replace a working compatible connection.
25
- 7. Exercise one safe read and one high-impact operation. Approve the resulting scope or an explicit temporary `--full` window through the local CLI, then retry the operation.
26
- 8. Restore or reinstall background service operation only after the foreground path is healthy.
72
+ 1. Inspect or cancel interactive processes and managed jobs that should not survive daemon replacement.
73
+ 2. Back up the owner-only state directory with an operating-system tool that preserves permissions. Do not upload or publish the backup.
74
+ 3. Install the version 3 package.
75
+ 4. Run `machine-mcp doctor`.
76
+ 5. Start each workspace normally in the foreground. Without a provisioned broker, macOS reuses the portable root and does not prompt.
77
+ 6. When `MBM_MACOS_TRUST_BROKER` is intentionally configured, verify the broker deployment first and complete the single user-presence request used to sign the daemon session certificate. Do not start with `--daemon-only` during this optional root migration.
78
+ 7. Allow Machine Bridge to deploy and verify the matching version 3 Worker. A pending root is promoted only after health convergence.
79
+ 8. Reconnect each hosted MCP client and complete OAuth authorization when requested.
80
+ 9. Inspect trusted clients with `machine-mcp account clients` and revoke stale or duplicate records.
81
+ 10. Reload the version 3 browser extension.
82
+ 11. Verify one safe workspace read, one ordinary edit, and one owner-only action appropriate for the deployment.
83
+ 12. Restore background service operation only after the foreground path is healthy.
84
+
85
+ ## Verification
86
+
87
+ After upgrade, `server_info` should report:
88
+
89
+ - matching Worker and daemon version;
90
+ - end-to-end relay readiness;
91
+ - the authenticated account role and effective policy;
92
+ - a current OAuth client and refresh family;
93
+ - device-root provider and exportability;
94
+ - ephemeral session use for reconnect signing;
95
+ - delegated sandbox status;
96
+ - security-audit chain health.
97
+
98
+ A full daemon policy is not proof that a delegated account has full authority. Use `authorization.effective_policy` and `authorization.effective_tools` for the current request.
27
99
 
28
100
  ## Upgrade safety
29
101
 
30
- Before replacing live software, copy the owner-only state directory using operating-system tools that preserve permissions. Do not publish or attach that backup: it contains credentials and private resource metadata.
102
+ Machine Bridge rejects unreadable, malformed, foreign-schema, or ambiguous state rather than silently initializing replacement state.
103
+
104
+ Worker deployment records upload success separately from health convergence. A post-upload network failure does not trigger an uncontrolled repeated write, and a pending root is not promoted merely because Wrangler returned success.
31
105
 
32
- Machine Bridge never treats an unreadable or foreign-schema state file as empty state. It also records a successful Worker upload before secondary health verification, so a network or proxy failure after deployment does not trigger an uncontrolled repeated write.
106
+ The packaged Swift broker source is a development and protocol-conformance fixture only. The local build is ad-hoc signed and is deliberately rejected by the production validator because it cannot obtain a provisioning-profile-validated data-protection Keychain access group. A production Secure Enclave broker must be shipped as an app-like, correctly signed and provisioned component outside the npm runtime build.
33
107
 
34
108
  ## Rollback
35
109
 
36
- Rollback is supported only from a complete pre-upgrade backup. Version 2.0.0 changes Worker/daemon authentication, OAuth refresh state, administration authentication, and local credential material. An older package cannot use the new device protocol or refresh-family state. Rolling back package files alone therefore produces an unavailable or incorrectly authenticated mixed system. Restore the complete owner-only profile backup, prior Worker secret set/build, package version, service definition, and browser extension as one unit, or fix forward.
110
+ Rollback is supported only as a complete unit from a verified pre-upgrade backup.
111
+
112
+ Version 3 changes daemon authentication, account administration, OAuth client trust, object ownership, local authorization, and device-root storage. Copying an older package over version 3 state produces a mixed system that should fail closed.
113
+
114
+ A rollback must restore together:
115
+
116
+ - the complete prior owner-only state root;
117
+ - the prior package;
118
+ - the prior Worker build and secrets;
119
+ - the prior service definition;
120
+ - the prior browser extension.
37
121
 
38
- Never roll back by copying only selected state files or changing version fields. Restore one complete verified state backup, package version, Worker build, and browser extension as a single operational unit.
122
+ Do not roll back by editing version or schema fields, copying selected credential files, or restoring only the Worker. Prefer fixing forward when a complete backup is unavailable.