machine-bridge-mcp 2.0.0 → 3.0.0-beta.9
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.
- package/CHANGELOG.md +101 -0
- package/CONTRIBUTING.md +20 -25
- package/README.md +21 -14
- package/SECURITY.md +147 -123
- package/browser-extension/manifest.json +3 -2
- package/browser-extension/service-worker.js +31 -12
- package/docs/ARCHITECTURE.md +27 -13
- package/docs/AUDIT.md +85 -2
- package/docs/CLIENTS.md +2 -2
- package/docs/ENGINEERING.md +9 -3
- package/docs/GETTING_STARTED.md +10 -9
- package/docs/LOCAL_AUTHORIZATION.md +115 -72
- package/docs/LOGGING.md +12 -3
- package/docs/MANAGED_JOBS.md +24 -29
- package/docs/MULTI_ACCOUNT.md +98 -37
- package/docs/OPERATIONS.md +33 -22
- package/docs/OVERVIEW.md +7 -7
- package/docs/PROJECT_STANDARDS.md +9 -5
- package/docs/RELEASING.md +171 -64
- package/docs/TESTING.md +19 -7
- package/docs/THREAT_MODEL.md +138 -67
- package/docs/TOOL_REFERENCE.md +2 -2
- package/docs/UPGRADING.md +102 -18
- package/native/macos/MachineBridgeTrustBroker.swift +233 -0
- package/package.json +36 -5
- package/scripts/candidate-runtime-store.mjs +38 -0
- package/scripts/check-plan.mjs +19 -0
- package/scripts/check-runner.mjs +4 -1
- package/scripts/commit-message-check.mjs +5 -2
- package/scripts/coverage-check.mjs +30 -2
- package/scripts/github-push.mjs +11 -0
- package/scripts/github-release.mjs +38 -7
- package/scripts/install-published-prerelease.mjs +167 -0
- package/scripts/local-release-acceptance.mjs +23 -12
- package/scripts/npm-publication-policy.mjs +16 -0
- package/scripts/prerelease-activation.mjs +79 -0
- package/scripts/privacy-check.mjs +7 -5
- package/scripts/promotion-digest.mjs +121 -0
- package/scripts/publish-npm.mjs +51 -0
- package/scripts/published-release.mjs +80 -0
- package/scripts/release-acceptance.mjs +30 -1
- package/scripts/release-candidate-manifest.mjs +40 -0
- package/scripts/release-channel.mjs +106 -0
- package/scripts/release-impact-check.mjs +12 -22
- package/scripts/release-soak.mjs +237 -0
- package/scripts/start-release-candidate.mjs +113 -7
- package/src/local/account-access.mjs +6 -0
- package/src/local/account-admin.mjs +34 -16
- package/src/local/agent-context.mjs +45 -42
- package/src/local/app-automation.mjs +9 -4
- package/src/local/authority-context.mjs +106 -0
- package/src/local/browser-bridge-http.mjs +4 -1
- package/src/local/browser-bridge.mjs +14 -9
- package/src/local/browser-broker-routes.mjs +4 -0
- package/src/local/browser-broker-server.mjs +5 -4
- package/src/local/browser-extension-identity.mjs +50 -0
- package/src/local/browser-extension-protocol.mjs +9 -4
- package/src/local/browser-operation-service.mjs +7 -0
- package/src/local/browser-pairing-http.mjs +36 -0
- package/src/local/browser-pairing-store.mjs +56 -47
- package/src/local/cli-account-admin.mjs +41 -7
- package/src/local/cli-activate.mjs +90 -0
- package/src/local/cli-approval.mjs +14 -58
- package/src/local/cli-local-admin.mjs +5 -15
- package/src/local/cli-options.mjs +11 -7
- package/src/local/cli-service.mjs +35 -5
- package/src/local/cli.mjs +112 -58
- package/src/local/daemon-process.mjs +6 -0
- package/src/local/delegated-process-sandbox.mjs +147 -0
- package/src/local/device-identity.mjs +157 -48
- package/src/local/device-root-provider.mjs +87 -0
- package/src/local/errors.mjs +25 -3
- package/src/local/git-service.mjs +16 -15
- package/src/local/job-runner.mjs +35 -27
- package/src/local/log.mjs +14 -1
- package/src/local/macos-trust-broker.mjs +320 -0
- package/src/local/managed-job-lock.mjs +18 -0
- package/src/local/managed-job-projection.mjs +9 -1
- package/src/local/managed-job-runner.mjs +13 -1
- package/src/local/managed-job-storage.mjs +2 -1
- package/src/local/managed-job-terminal.mjs +138 -0
- package/src/local/managed-jobs.mjs +88 -32
- package/src/local/operation-authorization.mjs +75 -239
- package/src/local/operation-risk.mjs +28 -0
- package/src/local/operation-state-lock.mjs +7 -86
- package/src/local/owner-state-lock.mjs +104 -0
- package/src/local/policy.mjs +19 -0
- package/src/local/process-execution.mjs +21 -9
- package/src/local/process-sessions.mjs +27 -17
- package/src/local/process-tracker.mjs +30 -6
- package/src/local/process-tree-ownership.mjs +59 -0
- package/src/local/process-tree.mjs +22 -18
- package/src/local/relay-connection.mjs +47 -35
- package/src/local/relay-diagnostics.mjs +65 -0
- package/src/local/remote-configuration.mjs +48 -0
- package/src/local/runtime-activation.mjs +141 -0
- package/src/local/runtime-diagnostics.mjs +21 -0
- package/src/local/runtime-relay.mjs +9 -8
- package/src/local/runtime-reporting.mjs +8 -3
- package/src/local/runtime-tool-handlers.mjs +8 -8
- package/src/local/runtime.mjs +73 -39
- package/src/local/secure-file.mjs +5 -1
- package/src/local/security-audit-log.mjs +204 -0
- package/src/local/service-convergence.mjs +17 -1
- package/src/local/service-ownership.mjs +17 -0
- package/src/local/service-restart-handoff.mjs +50 -0
- package/src/local/service-restart-scheduler.mjs +49 -0
- package/src/local/service-status.mjs +47 -0
- package/src/local/service.mjs +142 -43
- package/src/local/state-inventory.mjs +21 -3
- package/src/local/state.mjs +155 -17
- package/src/local/stdio.mjs +5 -0
- package/src/local/tool-executor.mjs +39 -6
- package/src/local/tool-result-boundary.mjs +51 -0
- package/src/local/tools.mjs +1 -0
- package/src/local/trusted-executable.mjs +53 -0
- package/src/local/trusted-git-executable.mjs +34 -0
- package/src/local/trusted-github-cli.mjs +24 -0
- package/src/local/windows-service.mjs +20 -0
- package/src/local/worker-deployment.mjs +3 -4
- package/src/local/worker-secret-file.mjs +2 -2
- package/src/local/workspace-file-service.mjs +34 -31
- package/src/shared/admin-auth.d.mts +2 -1
- package/src/shared/admin-auth.mjs +3 -3
- package/src/shared/device-session-auth.d.mts +20 -0
- package/src/shared/device-session-auth.mjs +51 -0
- package/src/shared/server-metadata.json +1 -1
- package/src/shared/tool-catalog.json +2 -2
- package/src/worker/account-admin.ts +23 -22
- package/src/worker/authority.ts +9 -2
- package/src/worker/daemon-auth.ts +45 -67
- package/src/worker/daemon-sockets.ts +12 -2
- package/src/worker/device-session-verifier.ts +129 -0
- package/src/worker/dpop.ts +151 -0
- package/src/worker/http.ts +47 -16
- package/src/worker/index.ts +53 -16
- package/src/worker/nonce-store.ts +1 -5
- package/src/worker/oauth-client-admin.ts +45 -0
- package/src/worker/oauth-controller.ts +55 -6
- package/src/worker/oauth-refresh-families.ts +21 -7
- package/src/worker/oauth-state.ts +6 -0
- package/src/worker/oauth-tokens.ts +28 -8
- package/src/worker/websocket-protocol.ts +8 -2
|
@@ -1,111 +1,154 @@
|
|
|
1
|
-
# Local
|
|
1
|
+
# Local authorization model
|
|
2
2
|
|
|
3
|
-
Machine Bridge
|
|
3
|
+
Machine Bridge treats **capability**, **identity**, and **object ownership** as separate controls. A tool is executable only when every control permits it.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
For a remote request, effective authority is:
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Remote calls do not require a lease for:
|
|
7
|
+
```text
|
|
8
|
+
daemon capability ceiling
|
|
9
|
+
∩ authenticated account role
|
|
10
|
+
∩ trusted OAuth client binding
|
|
11
|
+
∩ current account version and refresh-token family
|
|
12
|
+
∩ per-object ownership checks
|
|
13
|
+
```
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
- reads inside the selected workspace, except credential-sensitive paths;
|
|
19
|
-
- ordinary source and configuration writes inside the selected workspace, excluding credential- and persistence-sensitive targets;
|
|
20
|
-
- transactional patches whose source, destination, and move targets remain inside the selected workspace and outside sensitive targets;
|
|
21
|
-
- Git inspection;
|
|
22
|
-
- browser broker status without reading profile content;
|
|
23
|
-
- installed-application discovery without inspecting an application UI;
|
|
24
|
-
- registered-resource metadata inspection.
|
|
15
|
+
No approval record, token refresh, client reconnect, or local command can expand the account role. A narrower layer always wins.
|
|
25
16
|
|
|
26
|
-
|
|
17
|
+
Local stdio does not use remote OAuth accounts. It runs as the local owner under the selected local policy and remains subject to the MCP host and operating-system controls.
|
|
27
18
|
|
|
28
|
-
##
|
|
19
|
+
## Account roles
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
| Role | Effective purpose | Important limits |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `reviewer` | Read-only inspection of the selected workspace | No mutation or process execution |
|
|
24
|
+
| `editor` | Workspace reads and deterministic file mutation | No process execution |
|
|
25
|
+
| `operator` | Workspace-confined editing and direct process execution | No unrestricted paths, credentials, browser/desktop control, or persistent job creation |
|
|
26
|
+
| `owner` | Complete bridge authority within the daemon policy ceiling | Generic path-based tools cannot target Machine Bridge control-plane state; owner shell remains OS-user authority |
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|---|---|
|
|
34
|
-
| `shell` | shell commands, direct process launch, process output continuation, interactive process input or termination, registered local commands |
|
|
35
|
-
| `external-read` | reading, searching, imaging, or inspecting a path outside the selected workspace |
|
|
36
|
-
| `sensitive-read` | reading credential-sensitive locations or names such as SSH/AWS/Keychain state, `.env`, tokens, secrets, or private keys |
|
|
37
|
-
| `external-write` | writing, editing, patching, or moving a patch target outside the selected workspace |
|
|
38
|
-
| `sensitive-write` | writing credentials, live `.env` files, SSH/privilege files, shell startup files, Git hooks, LaunchAgents/LaunchDaemons, or other persistence-sensitive paths even when they are inside the selected workspace |
|
|
39
|
-
| `browser-session` | listing or reading tabs, source, screenshots, waits, navigation, form input, clicks, submission, tab management, or extension pairing in the existing browser profile |
|
|
40
|
-
| `data-export` | uploading a file, inserting a registered local resource into a browser or desktop application, or filling an explicitly sensitive browser field |
|
|
41
|
-
| `persistent-job` | staging, starting, listing, reading output from, or cancelling a managed job |
|
|
42
|
-
| `application-control` | opening, inspecting, or operating a desktop application |
|
|
43
|
-
| `credential-operation` | generating an SSH key resource |
|
|
44
|
-
| `full` | all of the above for one explicit temporary automation window |
|
|
28
|
+
The daemon may advertise the complete catalog as its capability ceiling. The Worker filters `tools/list` by account role, and the local runtime independently recomputes and validates the same role boundary before dispatch.
|
|
45
29
|
|
|
46
|
-
|
|
30
|
+
## Trusted OAuth clients
|
|
47
31
|
|
|
48
|
-
|
|
32
|
+
Dynamic OAuth registration creates an untrusted client record. The first successful account authorization binds that client to:
|
|
49
33
|
|
|
50
|
-
|
|
34
|
+
- one account ID;
|
|
35
|
+
- the account version at authorization time;
|
|
36
|
+
- the account role;
|
|
37
|
+
- the OAuth client ID.
|
|
51
38
|
|
|
52
|
-
|
|
39
|
+
A client cannot silently switch to another account. Account disablement, role changes, password rotation, client revocation, token-version rotation, and refresh-token replay invalidate the relevant credentials.
|
|
53
40
|
|
|
54
|
-
|
|
41
|
+
Inspect trusted clients locally:
|
|
55
42
|
|
|
56
43
|
```sh
|
|
57
|
-
machine-mcp --workspace /path/to/project
|
|
44
|
+
machine-mcp account clients --workspace /path/to/project
|
|
58
45
|
```
|
|
59
46
|
|
|
60
|
-
|
|
47
|
+
Revoke one client and all of its authorization codes, access tokens, and refresh tokens:
|
|
61
48
|
|
|
62
49
|
```sh
|
|
63
|
-
machine-mcp --workspace /path/to/project
|
|
50
|
+
machine-mcp account revoke-client CLIENT_ID --workspace /path/to/project
|
|
64
51
|
```
|
|
65
52
|
|
|
66
|
-
|
|
53
|
+
Account-management requests are signed by a root-certified ephemeral device session. Machine Bridge does not deploy or retain a long-lived account-administration bearer or HMAC secret.
|
|
67
54
|
|
|
68
|
-
|
|
55
|
+
## Automatic execution
|
|
69
56
|
|
|
70
|
-
|
|
71
|
-
machine-mcp --workspace /path/to/project approval approve APPROVAL_ID --full
|
|
72
|
-
```
|
|
57
|
+
There is no per-operation approval prompt in the current runtime.
|
|
73
58
|
|
|
74
|
-
|
|
59
|
+
Within the effective role and daemon ceiling, calls execute automatically. Outside that intersection, calls fail immediately with `authorization_denied`; the response does not contain an approval ID or a command to retry.
|
|
75
60
|
|
|
76
|
-
|
|
61
|
+
Examples:
|
|
77
62
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
63
|
+
- a reviewer may inspect files inside the selected workspace;
|
|
64
|
+
- an editor may update ordinary workspace files;
|
|
65
|
+
- an operator may run a workspace-confined process only when the delegated process sandbox is behaviorally verified;
|
|
66
|
+
- an owner may use shell, unrestricted paths, browser/application automation, resources, and managed jobs when enabled by the daemon policy.
|
|
82
67
|
|
|
83
|
-
|
|
68
|
+
Risk classification still runs for every consequential request. It supplies structured audit metadata and enforces hard boundaries; it is not a mechanism for temporary privilege escalation.
|
|
84
69
|
|
|
85
|
-
|
|
70
|
+
## Hard boundaries
|
|
86
71
|
|
|
87
|
-
|
|
88
|
-
machine-mcp --workspace /path/to/project approval revoke LEASE_ID
|
|
89
|
-
```
|
|
72
|
+
### Machine Bridge control plane
|
|
90
73
|
|
|
91
|
-
|
|
74
|
+
Generic path-based file, image, search, and patch tools cannot target Machine Bridge state, device-root metadata, account-management state, audit-chain state, service metadata, or other protected roots. This applies to `owner` as well as delegated accounts.
|
|
92
75
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
76
|
+
This is an application-level path boundary, not an arbitrary-code sandbox. An authorized `owner` shell or interpreter has the daemon OS user's ambient filesystem authority. Control-plane administration uses local CLI interfaces; mutually untrusted owner execution requires external OS isolation.
|
|
77
|
+
|
|
78
|
+
### Sensitive and persistent targets
|
|
79
|
+
|
|
80
|
+
Non-owner accounts cannot access credential- or persistence-sensitive targets, including live environment files, private keys, token stores, shell startup files, Git hooks, privilege configuration, LaunchAgents, LaunchDaemons, and equivalent persistence locations.
|
|
81
|
+
|
|
82
|
+
Final symbolic-link overwrites are rejected. Existing ancestors and patch move destinations are canonicalized before classification so a workspace alias cannot conceal an external or sensitive destination.
|
|
83
|
+
|
|
84
|
+
### Browser, desktop, and data export
|
|
85
|
+
|
|
86
|
+
Only `owner` may control the existing browser profile or desktop applications, upload local files, or inject registered resources into an interactive session. Browser and application actions operate on the user's logged-in session and therefore are not delegated to lower roles.
|
|
87
|
+
|
|
88
|
+
### Persistent jobs
|
|
96
89
|
|
|
97
|
-
|
|
90
|
+
Only `owner` may create persistent execution plans with `start_job` or non-executing drafts with `stage_job`.
|
|
98
91
|
|
|
99
|
-
|
|
92
|
+
`stage_job` does not execute and is not an approval workflow. The removed `machine-mcp job approve` path cannot turn a draft into a running job. Execution requires a trusted owner request through `start_job`, or an explicit local `job submit` operation performed by the machine operator.
|
|
100
93
|
|
|
101
|
-
|
|
94
|
+
## Delegated process isolation
|
|
95
|
+
|
|
96
|
+
An `operator` process is not accepted merely because its current directory and environment are restricted. Machine Bridge requires a behaviorally verified OS sandbox that:
|
|
97
|
+
|
|
98
|
+
- exposes the selected workspace and an isolated runtime directory;
|
|
99
|
+
- blocks the real user home and Machine Bridge state;
|
|
100
|
+
- blocks Keychain and desktop automation access;
|
|
101
|
+
- preserves the minimum system runtime needed by ordinary tools.
|
|
102
|
+
|
|
103
|
+
The probe is fail-closed. The presence of a sandbox executable is not sufficient.
|
|
104
|
+
|
|
105
|
+
On platforms where the negative security boundary cannot be verified, delegated process execution is unavailable. Owner execution remains governed by the selected daemon policy. For mutually untrusted workloads, use a separate OS account, container, or VM.
|
|
106
|
+
|
|
107
|
+
Implementation-owned metadata probes are a separate boundary from delegated arbitrary execution. `project_overview` and the read-only Git tools use fixed argv selected by Machine Bridge, never a caller-provided executable or shell string. Those probes run with a minimal isolated environment, bounded output and deadlines, cancellation/process-tree tracking, and the request’s path-visibility rules. They do not grant `run_process`, registered-command, or shell authority to reviewer/editor accounts.
|
|
108
|
+
|
|
109
|
+
## Object ownership
|
|
110
|
+
|
|
111
|
+
Long-lived runtime objects bind to the principal that created them:
|
|
102
112
|
|
|
103
113
|
- account ID;
|
|
114
|
+
- account version;
|
|
104
115
|
- OAuth client ID;
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
- refresh-token family ID.
|
|
117
|
+
|
|
118
|
+
The binding applies to interactive processes, retained command-output sessions, and managed jobs. Another account, client, or refresh family cannot read, continue, send input to, cancel, or terminate those objects.
|
|
119
|
+
|
|
120
|
+
## Device-root authorization
|
|
121
|
+
|
|
122
|
+
The default root on every platform is a portable owner-only P-256 key. It signs the 24-hour ephemeral session certificate without Keychain access or a user-presence prompt. On macOS, `MBM_MACOS_TRUST_BROKER` may explicitly select a separately provisioned app-like broker; only after its code signature, Team ID, canonical non-symlink path with no group/other write access, and real Secure Enclave key probe validate does a non-exportable root replace the portable provider. That provider requests user presence once when signing the daemon session certificate. The private session key remains in memory and handles WebSocket preflight, challenge authentication, reconnects, and local account administration for that daemon lifetime.
|
|
123
|
+
|
|
124
|
+
Expected interaction frequency:
|
|
125
|
+
|
|
126
|
+
- ordinary tool calls: no local prompt;
|
|
127
|
+
- portable-root daemon startup: no prompt;
|
|
128
|
+
- provisioned Secure Enclave daemon startup: one user-presence prompt;
|
|
129
|
+
- network reconnect: no prompt;
|
|
130
|
+
- an independent account-management command: no prompt with a portable root, or one prompt with a provisioned Secure Enclave root;
|
|
131
|
+
- root rotation: one explicit operation, with user presence only when the provisioned broker requires it.
|
|
132
|
+
|
|
133
|
+
Every platform uses the portable P-256 provider unless an explicitly configured non-exportable platform provider has been installed and validated. `server_info.security.device_root` reports the active provider and whether the root key is exportable.
|
|
134
|
+
|
|
135
|
+
## DPoP
|
|
136
|
+
|
|
137
|
+
OAuth clients that support DPoP may bind access and refresh tokens to their own P-256 key. The Worker validates the proof method, URL, timestamp, nonce identifier, access-token hash, and key thumbprint. A copied token is insufficient without the client private key.
|
|
138
|
+
|
|
139
|
+
Bearer remains available for MCP hosts that do not implement DPoP. Client trust, account versioning, refresh-family rotation, and role ceilings still apply.
|
|
140
|
+
|
|
141
|
+
## Audit and incident response
|
|
142
|
+
|
|
143
|
+
The local security audit is a bounded SHA-256 hash chain. It records operation class, outcome, duration, byte counts, target digest, and salted principal references. It does not record command text, file paths, file contents, form values, or tool output.
|
|
144
|
+
|
|
145
|
+
For incident response:
|
|
108
146
|
|
|
109
|
-
|
|
147
|
+
1. stop the daemon;
|
|
148
|
+
2. revoke the affected OAuth client or disable the account;
|
|
149
|
+
3. rotate the account password or global token version when appropriate;
|
|
150
|
+
4. rotate the device root when device identity may be compromised;
|
|
151
|
+
5. inspect the audit-chain health and local endpoint logs;
|
|
152
|
+
6. restart and reconnect only trusted clients.
|
|
110
153
|
|
|
111
|
-
|
|
154
|
+
Legacy capability-lease files from version 2 may still be listed, revoked, or cleared by the local CLI for migration cleanup. The version 3 runtime never consumes them and never creates pending approval IDs.
|
package/docs/LOGGING.md
CHANGED
|
@@ -12,7 +12,7 @@ Logs should answer:
|
|
|
12
12
|
4. Is an infrastructure, protocol, deployment, or local service problem requiring action?
|
|
13
13
|
5. When debug logging is explicitly enabled, which bounded implementation event should be correlated?
|
|
14
14
|
|
|
15
|
-
Logs are not a command history or content audit
|
|
15
|
+
Logs are not a command history or content transcript. The local security audit provides a bounded SHA-256 hash chain over coarse operation metadata without recording command text, paths, contents, form values, or output. It detects local alteration but is not a remote immutable ledger and is not a substitute for OS isolation.
|
|
16
16
|
|
|
17
17
|
## Levels
|
|
18
18
|
|
|
@@ -25,6 +25,7 @@ The CLI accepts:
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Foreground mode defaults to `info` and human-readable text. Platform autostart services use `warn` with newline-delimited JSON. Foreground operators can select JSON explicitly with `--log-format json`.
|
|
28
|
+
In JSON mode, every logger entry point—including direct level methods and the persistent daemon-ready transition—emits exactly one timestamped JSON object per line. No operational method may silently fall back to the human formatter.
|
|
28
29
|
|
|
29
30
|
Human mode treats the message as the primary interface: it uses a natural-language explanation and includes only bounded diagnostic fields that add meaning. It does not repeat the machine event key. JSON mode retains the stable `event` field for ingestion and correlation. Event identifiers such as `relay.tool_result.discarded` are implementation contracts for structured logs, not text that should be shown as the warning itself.
|
|
30
31
|
|
|
@@ -93,7 +94,7 @@ The implementation omits:
|
|
|
93
94
|
- stdin, stdout, and stderr;
|
|
94
95
|
- file, patch, image, and temporary-file content;
|
|
95
96
|
- OAuth request bodies;
|
|
96
|
-
- account passwords,
|
|
97
|
+
- account passwords, root/session signatures, device private keys, authorization codes, access tokens, refresh tokens, DPoP proofs, and legacy-lease target material;
|
|
97
98
|
- registered resource values and source paths;
|
|
98
99
|
- browser pairing tokens, page URLs/source, DOM metadata, form values, uploaded file bytes, and screenshots;
|
|
99
100
|
- application names, Accessibility trees, selectors, and entered values;
|
|
@@ -136,9 +137,17 @@ The log format has an explicit schema marker. If the marker differs from the cur
|
|
|
136
137
|
|
|
137
138
|
Each managed job has owner-only runner diagnostic logs. Child-step output is retained only in bounded, redacted job results according to `capture_output`; it is not copied into daemon or runner operational logs.
|
|
138
139
|
|
|
140
|
+
## Relay outage records
|
|
141
|
+
|
|
142
|
+
`network_route` describes only Machine Bridge's application-level proxy decision. `system-network-stack` does **not** mean a direct physical path: an operating-system VPN, TUN, packet tunnel, DNS interceptor, or endpoint-security product may still carry the connection. `network_route_scope` therefore remains `application-proxy-selection-only`.
|
|
143
|
+
|
|
144
|
+
During an outage, `server_info.runtime.relay` and `diagnose_runtime` expose bounded operational fields: outage count/start/duration, last close category/code, coarse transport error class, last disconnect/ready time, prior ready duration, and next retry timing. `relay.outage.active` and `relay.outage.recovered` carry the same safe fields. Raw WebSocket close reasons, IP addresses, proxy endpoints/credentials, DNS answers, tool arguments, and results are not promoted to default logs.
|
|
145
|
+
|
|
146
|
+
Schema 4 is strict NDJSON. Before daemon startup, both active log files are opened as owner-only regular single-link files. A schema change clears both only after validation and commits the marker only after the transition succeeds. A symlink, multiple-hard-link inode, permission error, or marker-write failure blocks startup rather than mixing formats or repeatedly erasing evidence.
|
|
147
|
+
|
|
139
148
|
## MCP host boundary
|
|
140
149
|
|
|
141
|
-
Canonical `full` does not remove tools based on filenames. For remote execution, the
|
|
150
|
+
Canonical `full` does not remove tools based on filenames. For remote execution, the operation classifier treats credential-sensitive paths and persistence targets as hard authorization boundaries: delegated roles are denied, while owner requests remain risk-classified and audited. An MCP host, connector, model provider, desktop application, operating system, or endpoint-security layer may independently reject a request before it reaches Machine Bridge.
|
|
142
151
|
|
|
143
152
|
Use `server_info`, `project_overview`, `machine-mcp status`, `machine-mcp doctor`, and `diagnose_runtime` to distinguish local policy from host-side enforcement. Capability-routing status is returned on demand rather than written as task logs; it stores a runtime-keyed task fingerprint, not raw task text. Changing the Machine Bridge profile cannot override another layer.
|
|
144
153
|
|
package/docs/MANAGED_JOBS.md
CHANGED
|
@@ -113,6 +113,14 @@ Environment injection is convenient but may expose a value to same-user process
|
|
|
113
113
|
|
|
114
114
|
At job acceptance, referenced resources are reopened, bounded, hashed, and recorded in the owner-only active plan. The runner reopens and verifies the hash before copying. A changed resource causes the job to fail rather than silently using different content.
|
|
115
115
|
|
|
116
|
+
## Terminal persistence and sensitive-plan cleanup
|
|
117
|
+
|
|
118
|
+
A job terminal transition is not a single best-effort write. The runner first attempts the bounded `result.json`, then persists a conservative terminal `status.json` with cleanup pending, then removes the private runtime directory, active plan, PID claim, cancellation marker, and transition/recovery artifacts, and finally confirms cleanup state. A result-write failure is visible as `result_persisted=false`; a status-write failure leaves every recovery artifact intact. Artifact removal failures remain visible as `artifact_cleanup_pending` and are retried by later read/list/prune operations.
|
|
119
|
+
|
|
120
|
+
If the runner writes a valid terminal result but exits before terminal status is committed, the manager reconstructs status from that result before considering recovery. This prevents a completed finally sequence from being replayed merely because the status write was interrupted. If no valid terminal result exists, recovery may still repeat finally work, so finally steps must remain idempotent.
|
|
121
|
+
|
|
122
|
+
Unexecuted staged plans can contain stdin, environment values, and temporary scripts. They expire after 24 hours and are converted to a non-executing terminal record; ordinary completed-job metadata may remain under the separate seven-day retention policy. A minimal-environment plan also launches its detached runner with a minimal control environment. Full parent-environment inheritance occurs only when the accepted plan explicitly captured that policy.
|
|
123
|
+
|
|
116
124
|
## Job-scoped temporary files
|
|
117
125
|
|
|
118
126
|
Do not create ad hoc helpers in the workspace when the file exists only for one operation. Include it in the job:
|
|
@@ -191,35 +199,26 @@ Finally steps are attempted after success, failure, timeout, or cancellation. Ca
|
|
|
191
199
|
|
|
192
200
|
Automatic dead-runner recovery is attempted at most three times; persistent failure becomes `recovery_exhausted` to avoid an endless restart loop. Cleanup is best effort, not mathematically guaranteed. Power loss, disk failure, permanent account loss, or a local security product that denies the cleanup executable can still prevent it. Finally steps should therefore be idempotent and safe to run more than once.
|
|
193
201
|
|
|
194
|
-
##
|
|
202
|
+
## Non-executing staged drafts
|
|
195
203
|
|
|
196
|
-
|
|
204
|
+
`stage_job` performs the same schema, cwd, resource, size, and permission validation as `start_job`, but records status `staged` and launches no process.
|
|
197
205
|
|
|
198
|
-
|
|
199
|
-
stage_job
|
|
200
|
-
```
|
|
206
|
+
A staged record is a review artifact, not an authorization request:
|
|
201
207
|
|
|
202
|
-
|
|
208
|
+
- it contains no executable approval token;
|
|
209
|
+
- it cannot be promoted by `machine-mcp job approve`;
|
|
210
|
+
- no main or finally step runs;
|
|
211
|
+
- no registered resource is copied into a runtime directory;
|
|
212
|
+
- cancellation produces `cancelled_before_start` and removes the plan.
|
|
203
213
|
|
|
204
|
-
|
|
205
|
-
machine-mcp job inspect JOB_ID
|
|
206
|
-
machine-mcp job approve JOB_ID
|
|
207
|
-
# or after a separate review, non-interactively:
|
|
208
|
-
machine-mcp job approve JOB_ID --yes
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
`job inspect` displays the reviewable plan, including argv, ordinary environment overrides, stdin, temporary helper content, and finally steps, while omitting registered resource source paths and per-resource hashes. The overall `plan_sha256` is displayed for review and is revalidated atomically during approval and again by the runner before execution. A modified staged plan is rejected.
|
|
214
|
+
Use `machine-mcp job inspect JOB_ID` to review the stored plan. The projection includes argv, ordinary environment overrides, stdin, temporary helper content, and finally steps while omitting registered resource source paths and per-resource hashes. The overall `plan_sha256` is displayed and remains integrity-checked.
|
|
212
215
|
|
|
213
|
-
|
|
216
|
+
Execution requires a separate authority-bearing action:
|
|
214
217
|
|
|
215
|
-
|
|
218
|
+
- a trusted owner submits the plan through `start_job`; or
|
|
219
|
+
- the local machine operator submits a reviewed JSON plan with `machine-mcp job submit PLAN.json`.
|
|
216
220
|
|
|
217
|
-
-
|
|
218
|
-
- no finally step runs;
|
|
219
|
-
- no resource is copied into a runtime directory;
|
|
220
|
-
- cancelling produces `cancelled_before_start` and deletes the plan.
|
|
221
|
-
|
|
222
|
-
Staged plans count toward the 50-item retention limit and expire with the seven-day job retention policy. They are not considered active processes and do not independently block uninstall after the normal uninstall confirmation.
|
|
221
|
+
The current runtime does not implement copy-an-ID, approve, and retry workflows. Staged drafts count toward the 50-item retention limit and expire with the seven-day retention policy. They are not active processes and do not independently block uninstall after normal confirmation.
|
|
223
222
|
|
|
224
223
|
## Submit and inspect
|
|
225
224
|
|
|
@@ -233,21 +232,17 @@ read_job
|
|
|
233
232
|
cancel_job
|
|
234
233
|
```
|
|
235
234
|
|
|
236
|
-
From the local terminal
|
|
235
|
+
From the local terminal:
|
|
237
236
|
|
|
238
237
|
```sh
|
|
239
238
|
machine-mcp job list
|
|
240
239
|
machine-mcp job inspect JOB_ID
|
|
241
|
-
machine-mcp job approve JOB_ID [--yes]
|
|
242
240
|
machine-mcp job cancel JOB_ID
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
A local JSON fallback is also available:
|
|
246
|
-
|
|
247
|
-
```sh
|
|
248
241
|
machine-mcp job submit plan.json
|
|
249
242
|
```
|
|
250
243
|
|
|
244
|
+
`job submit` is an explicit local operator action; it does not consume or promote a staged MCP draft.
|
|
245
|
+
|
|
251
246
|
The plan format is the same object accepted by `start_job`.
|
|
252
247
|
|
|
253
248
|
## Output and secret handling
|
package/docs/MULTI_ACCOUNT.md
CHANGED
|
@@ -2,30 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## What isolation means
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Remote mode supports several named accounts on one workspace Worker. Each account has an independent password verifier, role, active state, version, authorization codes, access tokens, and refresh-token families.
|
|
6
6
|
|
|
7
|
-
This is application-level authorization, not operating-system
|
|
7
|
+
This is application-level authorization, not operating-system multi-tenancy. All accounts ultimately reach one daemon running as one OS user. Roles do not create separate filesystems, browser profiles, process namespaces, Keychains, network identities, or kernel boundaries.
|
|
8
8
|
|
|
9
|
-
Use separate OS accounts, containers, VMs, state roots, Workers, and workspaces when users are mutually untrusted or require hard isolation.
|
|
9
|
+
Use separate OS accounts, containers, VMs, state roots, Workers, and workspaces when users are mutually untrusted or require hard tenant isolation.
|
|
10
10
|
|
|
11
11
|
## Roles
|
|
12
12
|
|
|
13
|
-
| Role | Effective local profile |
|
|
13
|
+
| Role | Effective local profile | Purpose |
|
|
14
14
|
|---|---|---|
|
|
15
|
-
| `reviewer` | `review` | Read-only workspace
|
|
16
|
-
| `editor` | `edit` | Reviewer access plus deterministic file mutation |
|
|
17
|
-
| `operator` | `agent` | Editor access plus workspace-confined direct
|
|
18
|
-
| `owner` | `full` | Complete
|
|
15
|
+
| `reviewer` | `review` | Read-only selected-workspace inspection |
|
|
16
|
+
| `editor` | `edit` | Reviewer access plus deterministic workspace file mutation |
|
|
17
|
+
| `operator` | `agent` | Editor access plus behaviorally sandboxed workspace-confined direct execution |
|
|
18
|
+
| `owner` | `full` | Complete bridge authority within the daemon capability ceiling |
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Effective authority is the intersection of:
|
|
21
21
|
|
|
22
|
-
1. the
|
|
23
|
-
2. the
|
|
24
|
-
3. the
|
|
22
|
+
1. the daemon policy and available tools;
|
|
23
|
+
2. the account role;
|
|
24
|
+
3. the trusted OAuth client binding;
|
|
25
|
+
4. the current account version and refresh-token family;
|
|
26
|
+
5. ownership of any long-lived process, output session, or job.
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
There is no temporary elevation path. A `reviewer`, `editor`, or `operator` cannot acquire `owner` capability through a local lease, approval ID, token refresh, or reconnect.
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
The Worker filters `tools/list` and rejects unauthorized calls before relay. Every accepted call carries account ID, account version, OAuth client ID, refresh-family ID, and role. The local runtime validates those values again before dispatch.
|
|
31
|
+
|
|
32
|
+
Authenticated `server_info.authorization.effective_policy` and `effective_tools` describe the current account. `daemon.policy` and `daemon.tools` describe only the local capability ceiling; a `full` daemon does not make an `editor` account full.
|
|
29
33
|
|
|
30
34
|
## Account lifecycle
|
|
31
35
|
|
|
@@ -35,7 +39,7 @@ List accounts:
|
|
|
35
39
|
machine-mcp account list
|
|
36
40
|
```
|
|
37
41
|
|
|
38
|
-
Create an account. The generated password is displayed once
|
|
42
|
+
Create an account. The generated password is displayed once:
|
|
39
43
|
|
|
40
44
|
```sh
|
|
41
45
|
machine-mcp account add alice reviewer
|
|
@@ -50,28 +54,50 @@ machine-mcp account disable build-bot
|
|
|
50
54
|
machine-mcp account enable build-bot
|
|
51
55
|
```
|
|
52
56
|
|
|
53
|
-
Rotate
|
|
57
|
+
Rotate a password or remove an account:
|
|
54
58
|
|
|
55
59
|
```sh
|
|
56
60
|
machine-mcp account rotate-password alice
|
|
61
|
+
machine-mcp account remove alice --yes
|
|
57
62
|
```
|
|
58
63
|
|
|
59
|
-
|
|
64
|
+
The final active owner cannot be disabled, demoted, or removed.
|
|
65
|
+
|
|
66
|
+
Account disablement, role changes, password rotation, and removal revoke that account's credentials by changing or deleting its account version.
|
|
67
|
+
|
|
68
|
+
## Trusted OAuth clients
|
|
69
|
+
|
|
70
|
+
An OAuth `client_id` identifies client software and redirect URIs. Registration alone has no authority.
|
|
71
|
+
|
|
72
|
+
The first successful account authorization binds the client to:
|
|
73
|
+
|
|
74
|
+
- account ID;
|
|
75
|
+
- account version;
|
|
76
|
+
- role;
|
|
77
|
+
- authorization time.
|
|
78
|
+
|
|
79
|
+
A client cannot later authorize as a different account without first being revoked and registered again. This prevents one public client record from becoming a silent cross-account identity switch.
|
|
80
|
+
|
|
81
|
+
List clients:
|
|
60
82
|
|
|
61
83
|
```sh
|
|
62
|
-
machine-mcp account
|
|
63
|
-
machine-mcp account remove alice --yes
|
|
84
|
+
machine-mcp account clients
|
|
64
85
|
```
|
|
65
86
|
|
|
66
|
-
|
|
87
|
+
Revoke one client and all of its codes, access tokens, and refresh tokens:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
machine-mcp account revoke-client CLIENT_ID
|
|
91
|
+
machine-mcp account revoke-client CLIENT_ID --yes
|
|
92
|
+
```
|
|
67
93
|
|
|
68
|
-
|
|
94
|
+
One account may still authorize several distinct client records. Each record is independently visible and revocable.
|
|
69
95
|
|
|
70
|
-
|
|
96
|
+
## OAuth tokens
|
|
71
97
|
|
|
72
|
-
|
|
98
|
+
Authorization codes bind:
|
|
73
99
|
|
|
74
|
-
-
|
|
100
|
+
- client ID;
|
|
75
101
|
- account ID and account version;
|
|
76
102
|
- role;
|
|
77
103
|
- redirect URI;
|
|
@@ -79,33 +105,68 @@ An authorization code records:
|
|
|
79
105
|
- scope and protected resource;
|
|
80
106
|
- expiration.
|
|
81
107
|
|
|
82
|
-
|
|
108
|
+
Access and refresh tokens additionally bind to the deployment token version and refresh-family ID. Token values are stored as SHA-256 lookup keys.
|
|
109
|
+
|
|
110
|
+
Access tokens last fifteen minutes. Refresh tokens rotate on every use, have a fourteen-day idle limit and thirty-day family limit, and leave bounded replay markers. Reuse of a consumed refresh token revokes the complete family, including active access tokens.
|
|
83
111
|
|
|
84
|
-
|
|
112
|
+
A refresh request also verifies that the client remains bound to the current account version and role.
|
|
85
113
|
|
|
86
|
-
|
|
114
|
+
### DPoP
|
|
115
|
+
|
|
116
|
+
A capable client may bind the token family to a P-256 DPoP key. The Worker verifies the proof and requires the same key thumbprint for refresh. A copied token cannot be used without the client private key.
|
|
117
|
+
|
|
118
|
+
Bearer remains available for hosts that do not implement DPoP.
|
|
119
|
+
|
|
120
|
+
## Object ownership
|
|
121
|
+
|
|
122
|
+
Interactive processes, retained output sessions, and managed jobs bind to:
|
|
123
|
+
|
|
124
|
+
- account ID;
|
|
125
|
+
- account version;
|
|
126
|
+
- OAuth client ID;
|
|
127
|
+
- refresh-token family ID.
|
|
128
|
+
|
|
129
|
+
A different account, client, or token family cannot inspect, continue, send input to, cancel, or terminate the object.
|
|
130
|
+
|
|
131
|
+
This binding prevents horizontal control between two clients authorized for the same account as well as between different accounts.
|
|
87
132
|
|
|
88
133
|
## Administrative boundary
|
|
89
134
|
|
|
90
|
-
Account administration is not exposed as an MCP tool
|
|
135
|
+
Account and client administration is not exposed as an MCP tool and does not use a long-lived administration secret.
|
|
91
136
|
|
|
92
|
-
The
|
|
137
|
+
The local CLI creates a root-certified ephemeral P-256 session. Each request signs the Worker origin, HTTP method, path, body hash, session key ID, timestamp, and nonce. The Worker verifies the root certificate, session signature, body, timestamp, and nonce replay state.
|
|
138
|
+
|
|
139
|
+
The default root is portable owner-only P-256 material, including on macOS, so independent account commands do not normally prompt. When a separately provisioned broker has explicitly enrolled a Secure Enclave root, an independent account command may request user presence once. During normal daemon startup, the same in-memory session is reused for initial owner creation and relay authentication.
|
|
140
|
+
|
|
141
|
+
The first start of a new deployment creates an owner account automatically and prints its generated password once. Subsequent starts do not display passwords.
|
|
142
|
+
|
|
143
|
+
## Delegated execution
|
|
144
|
+
|
|
145
|
+
`operator` direct execution requires a behaviorally verified OS sandbox. The sandbox must expose the selected workspace while denying the real user home, Machine Bridge state, Keychain, and desktop automation.
|
|
146
|
+
|
|
147
|
+
When the platform cannot prove that boundary, operator process execution is unavailable. The runtime does not fall back to a path blacklist that only appears isolated.
|
|
148
|
+
|
|
149
|
+
Browser/application control, local data export, credential operations, persistent job creation, sensitive targets, and unrestricted paths remain owner-only.
|
|
93
150
|
|
|
94
151
|
## Concurrency and revocation
|
|
95
152
|
|
|
96
|
-
|
|
153
|
+
MCP sessions provide a request-ID namespace and cancellation boundary. Pending calls are bound to the authenticated token and session.
|
|
97
154
|
|
|
98
|
-
A relay interruption
|
|
155
|
+
A brief relay interruption preserves an ordinary call only within the same-daemon reconnect grace period. Reconciliation or expiry cancels calls without a receiver and terminates their child process trees. A replacement daemon process cannot claim a detached call.
|
|
156
|
+
|
|
157
|
+
Revoking an account, client, or refresh family blocks new requests immediately. Already-relayed work remains subject to local ownership, cancellation, timeout, daemon lifecycle, and process cleanup.
|
|
99
158
|
|
|
100
159
|
## Audit and privacy
|
|
101
160
|
|
|
102
|
-
Operational
|
|
161
|
+
Operational logs and the local security audit do not contain account passwords, tokens, command text, file content, form values, or results.
|
|
162
|
+
|
|
163
|
+
The audit chain records salted principal references, so repeated activity can be correlated locally without storing raw account/client identifiers in each entry. `server_info` may return the current authenticated account ID, role, and version to that account.
|
|
103
164
|
|
|
104
|
-
|
|
165
|
+
Do not use secrets, email addresses, customer identifiers, or unnecessary personal data in account names and display names.
|
|
105
166
|
|
|
106
167
|
## Deployment topology
|
|
107
168
|
|
|
108
|
-
One workspace normally maps to one Worker
|
|
169
|
+
One workspace normally maps to one Worker, one Durable Object instance, one local profile, and one active daemon. Accounts share that topology and OS trust boundary.
|
|
109
170
|
|
|
110
171
|
Use a separate deployment when any of these differ:
|
|
111
172
|
|
|
@@ -116,10 +177,10 @@ Use a separate deployment when any of these differ:
|
|
|
116
177
|
- billing or incident-response boundary;
|
|
117
178
|
- requirement for hard tenant isolation.
|
|
118
179
|
|
|
119
|
-
Do not place
|
|
180
|
+
Do not place unrelated machines or mutually untrusted teams behind one broad owner deployment merely to reduce administration.
|
|
120
181
|
|
|
121
182
|
## Security limits
|
|
122
183
|
|
|
123
|
-
A
|
|
184
|
+
A reviewer is restricted by Machine Bridge, but a bug or compromised dependency remains possible. An operator can execute interpreters and repository code inside the verified sandbox and can still damage the selected workspace. An owner has effectively the authority of the local OS user and granted browser or Accessibility permissions.
|
|
124
185
|
|
|
125
|
-
Roles
|
|
186
|
+
Roles, client binding, DPoP, object ownership, and targeted revocation are defense in depth. They do not replace least-privilege OS design, endpoint security, Cloudflare account protection, and careful review of untrusted repositories and instructions.
|