machine-bridge-mcp 1.2.6 → 1.2.8
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 +21 -0
- package/CONTRIBUTING.md +26 -19
- package/README.md +15 -4
- package/SECURITY.md +3 -3
- package/browser-extension/manifest.json +2 -2
- package/docs/ARCHITECTURE.md +10 -8
- package/docs/AUDIT.md +26 -0
- package/docs/ENGINEERING.md +2 -2
- package/docs/OPERATIONS.md +5 -3
- package/docs/PROJECT_STANDARDS.md +9 -5
- package/docs/RELEASING.md +64 -32
- package/docs/TESTING.md +7 -4
- package/package.json +11 -6
- package/scripts/github-push.mjs +49 -0
- package/scripts/github-release.mjs +15 -8
- package/scripts/local-release-acceptance.mjs +136 -0
- package/scripts/release-acceptance.mjs +169 -0
- package/scripts/release-impact-check.mjs +19 -3
- package/src/local/browser-bridge.mjs +67 -22
- package/src/local/cli-local-admin.mjs +2 -3
- package/src/local/daemon-process.mjs +39 -4
- package/src/local/execution-limits.mjs +36 -0
- package/src/local/job-runner.mjs +5 -8
- package/src/local/loopback-health.mjs +67 -0
- package/src/local/managed-jobs.mjs +22 -9
- package/src/local/process-contract.mjs +19 -0
- package/src/local/process-execution.mjs +11 -10
- package/src/local/process-sessions.mjs +25 -50
- package/src/local/process-tracker.mjs +1 -1
- package/src/local/process-tree.mjs +53 -0
- package/src/local/runtime-reporting.mjs +3 -1
- package/src/local/runtime.mjs +4 -5
- package/src/local/shell.mjs +2 -19
- package/src/worker/index.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.8 - 2026-07-17
|
|
4
|
+
|
|
5
|
+
### Owner-tested release gate and dependency workflow repair
|
|
6
|
+
|
|
7
|
+
- Replace the previous automation-only release assumption with an explicit repository-owner local acceptance boundary. `npm run release:candidate` runs the complete suite and creates the exact npm tarball under ignored local state; `npm run release:accept` records the owner decision only when a second pack is byte-identical. The tracked acceptance record contains package identity, SHA-1, SHA-512 integrity, timestamp, and a fixed confirmation marker, while excluding personal identity, machine paths, logs, credentials, and user content.
|
|
8
|
+
- Add `npm run github:push`, which rejects dirty trees, detached HEAD, direct `main` pushes, untracked acceptance records, or package-hash drift before pushing a release-relevant branch. Pull-request CI and `release:publish` independently rebuild and verify the accepted package. `release:publish` no longer pushes `main`; it requires the accepted branch to have been reviewed and merged so local `HEAD` already equals `origin/main`.
|
|
9
|
+
- Distinguish npm-package changes from GitHub-only repository infrastructure. The release-impact gate now derives package relevance from `package.json.files`, so Action-only Dependabot PRs no longer deadlock on an unrelated npm version bump while source, scripts, browser extension, package metadata, and shipped documentation remain versioned.
|
|
10
|
+
- Consolidate the five pending GitHub Action updates atomically: CodeQL `init`, `analyze`, and `upload-sarif` now use the same 4.37.1 commit; `actions/setup-node` advances to 7.0.0; and `actions/upload-artifact` advances to 7.0.1. Dependabot now groups all GitHub Action updates so coupled action families cannot be split into incompatible PRs.
|
|
11
|
+
- Update Wrangler from 4.111.0 to 4.112.0 and advance the exact reviewed `workerd` install-script allowlist to 1.20260714.1. Complete and production dependency audits remain at zero known vulnerabilities.
|
|
12
|
+
- Rewrite the release, contribution, automation, engineering, architecture, testing, and audit contracts around the owner-tested artifact boundary. Add executable regression coverage for package-impact classification, package-hash acceptance, workflow grouping, CI verification, no automatic `main` push, and package-manifest inclusion of every new helper.
|
|
13
|
+
|
|
14
|
+
## 1.2.7 - 2026-07-17
|
|
15
|
+
|
|
16
|
+
### Process supervision, lifecycle, and isolation audit
|
|
17
|
+
|
|
18
|
+
- Separate argv validation, execution limits, process-tree supervision, one-shot execution, and interactive process sessions into explicit modules. Shell helpers, managed jobs, call cancellation, runtime shutdown, and process sessions now share one graceful `SIGTERM` followed by forced tree-termination contract instead of importing session internals or maintaining duplicate platform branches.
|
|
19
|
+
- Reclaim an unresponsive detached service daemon only after revalidating PID, process start time, entrypoint, command line, daemon mode, workspace, and state root immediately before `SIGKILL`. PID reuse, identity drift, foreground ownership, and ambiguous records remain fail closed. Process-session termination now also escalates after a bounded grace period.
|
|
20
|
+
- Add a machine-readable `server_info.runtime.execution_guardrails` contract for tool-call concurrency, process timeout/stdin/output limits, process-session limits, and cleanup semantics. CPU quota, memory quota, and network isolation are reported explicitly as `not-enforced`; hard isolation still requires a dedicated account, container, or VM.
|
|
21
|
+
- Make browser-broker startup generation-aware so `stop()` cannot race an asynchronous listen/proxy connection and leave a listener alive. Pending proxy routes now receive a terminal error during shutdown, broker recovery failures emit structured debug events, and the local browser-health probe uses bounded direct `127.0.0.1` HTTP instead of environment-routed `fetch`.
|
|
22
|
+
- Reject detached managed-job launch when no process ID was obtained, attach an asynchronous child-error observer, make `shell: false` explicit, and remove duplicate plan-scrubbing logic. Correct stale relay-readiness and runtime-observability documentation, and add fault-path tests for resistant descendants, forced daemon reclamation, startup cancellation, proxy-bypassed loopback health, runner spawn failure, and honest OS-enforcement reporting.
|
|
23
|
+
|
|
3
24
|
## 1.2.6 - 2026-07-17
|
|
4
25
|
|
|
5
26
|
### Relay ready-context and implicit service-daemon takeover
|
package/CONTRIBUTING.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Contributing and release discipline
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read [docs/PROJECT_STANDARDS.md](docs/PROJECT_STANDARDS.md), [docs/ENGINEERING.md](docs/ENGINEERING.md), [GOVERNANCE.md](GOVERNANCE.md), and the relevant domain documentation before changing behavior.
|
|
4
4
|
|
|
5
5
|
## Development workflow
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The repository uses GitHub Flow: branch from current `main`, keep one coherent change, validate it locally, open a pull request, satisfy required checks, squash-merge, and delete the branch. Permanent `develop` or generic release integration branches are not used unless an independently maintained release line creates a concrete need.
|
|
8
|
+
|
|
9
|
+
Repository automation performs GitHub operations only through local `git`, `gh`, and `gh api` commands executed by Machine Bridge. Hosted GitHub connectors and ChatGPT GitHub plugins are prohibited for this repository. Direct pushes to `main` and force pushes are prohibited.
|
|
8
10
|
|
|
9
11
|
Branch names use a category and purpose such as `feat/browser-downloads`, `fix/relay-timeout`, or `chore/dependency-policy`.
|
|
10
12
|
|
|
@@ -14,21 +16,32 @@ Pull-request titles and final commit subjects use Conventional Commits:
|
|
|
14
16
|
<type>[optional scope][optional !]: <imperative description>
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
Accepted types are `feat`, `fix`, `docs`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `security`, `release`, and `revert`. Explain the causal problem, why the solution is correct, compatibility/security/privacy risk, verification, and release impact
|
|
19
|
+
Accepted types are `feat`, `fix`, `docs`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `security`, `release`, and `revert`. Explain the causal problem, why the solution is correct, compatibility/security/privacy risk, verification, and release impact. Bug fixes require a regression test for the original failure mechanism.
|
|
20
|
+
|
|
21
|
+
## Package impact
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
An npm version is required when a change affects `package.json`, `package-lock.json`, or any path included by the package `files` manifest. This includes runtime source, executable scripts, browser-extension files, shared contracts, and shipped documentation. `npm run release-impact:check` derives the decision from the package manifest.
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Repository-only infrastructure changes, such as a `.github/` workflow update, do not require a synthetic npm version when package bytes are unchanged. They still require review and all applicable CI, dependency-review, CodeQL, governance, and Scorecard checks.
|
|
26
|
+
|
|
27
|
+
## Required before pushing an npm-package change
|
|
22
28
|
|
|
23
29
|
1. bump `package.json` to a version newer than the latest reachable `v*` tag;
|
|
24
|
-
2. add the matching dated section to `CHANGELOG.md
|
|
25
|
-
3. run `npm run
|
|
26
|
-
4. inspect the complete diff
|
|
27
|
-
5.
|
|
30
|
+
2. add the matching dated section to `CHANGELOG.md` and update audit/documentation records;
|
|
31
|
+
3. run targeted tests, both dependency audits, `npm run worker:dry-run`, privacy/history review, signature verification, SBOM generation, and package inspection as applicable;
|
|
32
|
+
4. inspect the complete diff;
|
|
33
|
+
5. run `npm run release:candidate`, which executes the complete suite and creates the exact candidate tarball under ignored `.release-candidate/`;
|
|
34
|
+
6. have the repository owner test that exact tarball on the maintainer machine through the normal installation/startup path;
|
|
35
|
+
7. have the owner record the explicit decision with the exact command printed by the candidate tool, creating `release-acceptance/v<version>.json`;
|
|
36
|
+
8. commit the acceptance record and push the clean non-`main` branch only with `npm run github:push`.
|
|
37
|
+
|
|
38
|
+
Automated checks do not authorize step 7. A coding agent must not record owner acceptance or push the release-relevant branch before the owner has tested it. Any packaged-file change after acceptance changes the npm tarball hash and requires a regenerated candidate and a new owner test.
|
|
28
39
|
|
|
29
|
-
After all required pull-request checks pass, repository automation
|
|
40
|
+
After all required pull-request checks pass, repository automation may complete the source release: squash-merge, verify the exact `main` push CI, CodeQL, Governance, and Scorecard runs, and run `npm run release:publish`. The publication helper requires `HEAD === origin/main`; it does not push `main`. It creates or verifies the annotated version tag and final GitHub Release only after the accepted package hash and exact-commit checks match.
|
|
30
41
|
|
|
31
|
-
|
|
42
|
+
The release operator separately authorizes npm publication and any live machine update. Automation must not publish, deprecate, or unpublish npm packages; install the CLI globally; deploy the Worker; rotate credentials; mutate live deployment state; or start, stop, install, remove, or replace the daemon or autostart service without explicit user authorization.
|
|
43
|
+
|
|
44
|
+
Supported upgrade and rollback behavior is defined in [docs/UPGRADING.md](docs/UPGRADING.md). Support requests follow [SUPPORT.md](SUPPORT.md), and repository participation follows [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
|
32
45
|
|
|
33
46
|
After npm publication, the standard machine update is:
|
|
34
47
|
|
|
@@ -36,15 +49,9 @@ After npm publication, the standard machine update is:
|
|
|
36
49
|
npm install -g --omit=optional --allow-scripts=esbuild,workerd,sharp,fsevents machine-bridge-mcp@latest && machine-mcp
|
|
37
50
|
```
|
|
38
51
|
|
|
39
|
-
The npm command updates the global CLI. Normal `machine-mcp` startup checks the Worker deployment hash, expected version, and health, redeploys when necessary, and reconciles the daemon/autostart flow.
|
|
40
|
-
|
|
41
|
-
`npm run release-impact:check` enforces the version and changelog parts. It fails when release-relevant files changed after the latest version tag but the package version was not advanced.
|
|
42
|
-
|
|
43
|
-
A privacy or security correction is always release-relevant. Removing a private identifier only from the current branch is insufficient: publish a replacement npm version, update GitHub, and deprecate or unpublish the affected npm version when policy and authentication permit.
|
|
44
|
-
|
|
45
52
|
## Privacy
|
|
46
53
|
|
|
47
|
-
Use only synthetic names, reserved example domains, and generic paths. Maintain private local identifiers in the ignored `.privacy-denylist` and run `npm run privacy:check` before committing.
|
|
54
|
+
Use only synthetic names, reserved example domains, and generic paths. Maintain private local identifiers in the ignored `.privacy-denylist` and run `npm run privacy:check` before committing. Local acceptance records contain hashes and a fixed marker only; do not add machine paths, personal names, logs, credentials, endpoint URLs, or user content.
|
|
48
55
|
|
|
49
56
|
## Engineering standards
|
|
50
57
|
|
|
@@ -52,4 +59,4 @@ Read [docs/ENGINEERING.md](docs/ENGINEERING.md) before changing architecture, po
|
|
|
52
59
|
|
|
53
60
|
A log change is behavior: test its level, repetition policy, privacy fields, and recovery message. A transport change must distinguish low-level connectivity from authenticated readiness and test timeout/reconnect branches deterministically. Lock, state deletion, service lifecycle, detached process, and credential changes require behavior-level concurrency or fault-injection tests. Review [docs/AUDIT.md](docs/AUDIT.md) before changing those surfaces.
|
|
54
61
|
|
|
55
|
-
Reusable decisions belong in tracked documentation. Keep only machine-specific observations in
|
|
62
|
+
Reusable decisions belong in tracked documentation. Keep only machine-specific observations in ignored `.project-local/`, and never store credentials there.
|
package/README.md
CHANGED
|
@@ -264,7 +264,7 @@ Machine Bridge can discover, refresh, rank, and load capabilities automatically.
|
|
|
264
264
|
|
|
265
265
|
## Runtime lifecycle and observability
|
|
266
266
|
|
|
267
|
-
Every tool call passes through one execution pipeline: bounded call registration and deadline/cancellation ownership, structured observability, shared policy authorization, then the typed handler. Errors use stable codes and retryability metadata instead of transport-specific message parsing. `server_info` exposes the local lifecycle state, in-flight calls, active process ownership, per-tool outcomes, durations,
|
|
267
|
+
Every tool call passes through one execution pipeline: bounded call registration and deadline/cancellation ownership, structured observability, shared policy authorization, then the typed handler. Errors use stable codes and retryability metadata instead of transport-specific message parsing. `server_info` exposes the local lifecycle state, in-flight calls, active process ownership, per-tool outcomes, durations, error-code counts, enforced execution limits, and explicit `not-enforced` CPU/memory/network-isolation fields. The Worker adds pending internal/request-key indexes, daemon candidate/socket counters, and Worker-side per-tool outcomes.
|
|
268
268
|
|
|
269
269
|
Foreground logging defaults to human-readable text. Installed background services use warning-level JSON events by default. Use `--log-format json` for machine-readable foreground logs; arguments, outputs, credentials, resource contents, and local paths remain excluded or redacted.
|
|
270
270
|
|
|
@@ -526,7 +526,7 @@ Default state roots:
|
|
|
526
526
|
|
|
527
527
|
State/config writes use owner-only temporary files, `fsync`, and atomic replacement. Exclusive locks are fully written before a same-directory hard-link claim becomes visible; lock ownership includes a token and process start time so PID reuse and lock replacement cannot silently transfer ownership. Only successfully read but invalid JSON is retained as a bounded corrupt backup; permission, symbolic-link, size, encoding, and I/O failures remain explicit. A custom state root must not equal, contain, or be contained by the selected workspace. Resource source paths are redacted from `status` output. Active managed-job plans are owner-only and are deleted after a terminal result; bounded redacted results are retained temporarily. Uninstall first acquires a state-root maintenance lock that blocks new profile/state operations and state-backed operations from already constructed managed-job/browser managers, stops the platform service and all verified workspace daemons before removing definitions, rechecks jobs and locks, then validates markers, canonical paths, workspace/source exclusions, and known contents before recursive deletion.
|
|
528
528
|
|
|
529
|
-
Worker health probes and the relay honor standard `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment routing. Invalid or unsupported proxy configuration fails fast. Health and relay diagnostics report only coarse `direct`, `proxy`, or invalid-route state and never proxy URLs or credentials.
|
|
529
|
+
Remote Worker health probes and the relay honor standard `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment routing. Invalid or unsupported proxy configuration fails fast. Browser-broker health is strictly loopback-direct and does not rely on `NO_PROXY`. Health and relay diagnostics report only coarse `direct`, `proxy`, or invalid-route state and never proxy URLs or credentials.
|
|
530
530
|
|
|
531
531
|
Default foreground logs report authenticated relay readiness, readable persistent-degradation summaries, and recovery rather than raw WebSocket callbacks or JSON field dumps. Brief self-healing disconnects and close codes/reasons are debug-only. Stalled connection attempts have a deadline, and sustained-outage reminders use autonomous exponential backoff. Every per-tool event—including success, failure, cancellation, and slow-call timing—also appears only at `--log-level debug` or `--verbose`. Background services use `warn`, so ordinary tool outcomes and brief network changes do not fill daemon logs. Log messages and structured fields are bounded, secret-like keys and known token formats are redacted, and tool arguments/results are not written. See [docs/LOGGING.md](docs/LOGGING.md) and [docs/OPERATIONS.md](docs/OPERATIONS.md).
|
|
532
532
|
|
|
@@ -541,7 +541,18 @@ npm audit --omit=dev --audit-level=high
|
|
|
541
541
|
npm pack --dry-run
|
|
542
542
|
```
|
|
543
543
|
|
|
544
|
-
`npm run check` covers privacy and
|
|
544
|
+
`npm run check` covers privacy and package-impact gates, local-release-acceptance hash logic, architecture/link invariants, generated Worker types, TypeScript, recursively discovered JavaScript syntax, semantic undefined-identifier checks, catalog-to-runtime handler parity, deterministic relay lifecycle and secure-file tests, concurrent lock/atomic-replacement/PID-reuse fixtures, fail-closed service lifecycle tests, descendant process-tree termination, local path/write/state/log/service invariants, Ed25519/RSA generation and key-pair validation, real-machine `full` sandbox acceptance, a clean npm package-manifest/mode/sensitive-artifact check, an isolated installation of the actual packed tarball whose zero-argument CLI startup must reach a controlled Worker-deployment boundary, managed-job integrity/redaction/finally/cancellation/recovery, a live stdio MCP flow, a live local OAuth/Worker/WebSocket/MCP flow covering discovery, Claude callback routing, rotating refresh tokens, replay rejection, and account-targeted refresh revocation, plus a real Chromium negative/positive test for CSP-governed OAuth callback navigation. GitHub Actions runs the complete suite on Linux, macOS, and Windows with the pinned Node 26/npm 12 baseline.
|
|
545
|
+
|
|
546
|
+
For an npm-package release, automated checks are followed by a separate repository-owner acceptance boundary:
|
|
547
|
+
|
|
548
|
+
```sh
|
|
549
|
+
npm run release:candidate
|
|
550
|
+
# Test the exact .release-candidate/*.tgz artifact locally.
|
|
551
|
+
npm run release:accept -- --confirm "I TESTED machine-bridge-mcp <version> LOCALLY AND IT WORKS"
|
|
552
|
+
npm run github:push
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
The coding agent must stop before the first GitHub push until the owner tests the exact tarball. The acceptance record stores package hashes, not machine paths or logs, and any packaged-file change invalidates it. See [docs/RELEASING.md](docs/RELEASING.md).
|
|
545
556
|
|
|
546
557
|
The cross-cutting 0.12.0 review, corrected failure modes, and residual OS-level limits are recorded in [docs/AUDIT.md](docs/AUDIT.md). See also [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md), [docs/MULTI_ACCOUNT.md](docs/MULTI_ACCOUNT.md), [docs/AGENT_CONTEXT.md](docs/AGENT_CONTEXT.md), [docs/LOCAL_AUTOMATION.md](docs/LOCAL_AUTOMATION.md), [docs/MANAGED_JOBS.md](docs/MANAGED_JOBS.md), [docs/TESTING.md](docs/TESTING.md), [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), [docs/ENGINEERING.md](docs/ENGINEERING.md), [docs/PROJECT_STANDARDS.md](docs/PROJECT_STANDARDS.md), the generated [MCP tool reference](docs/TOOL_REFERENCE.md), and [SECURITY.md](SECURITY.md).
|
|
547
558
|
|
|
@@ -558,4 +569,4 @@ Use `--keep-worker` to retain deployed Workers while removing local state and au
|
|
|
558
569
|
|
|
559
570
|
MIT
|
|
560
571
|
|
|
561
|
-
See [repository privacy hygiene](docs/PRIVACY.md) and [contribution/release discipline](CONTRIBUTING.md) before committing. Every
|
|
572
|
+
See [repository privacy hygiene](docs/PRIVACY.md) and [contribution/release discipline](CONTRIBUTING.md) before committing. Every npm-package change requires a new version, an owner-tested exact tarball, a matching acceptance record, and a matching npm release. GitHub-only infrastructure changes may remain source-only when package bytes are unchanged.
|
package/SECURITY.md
CHANGED
|
@@ -59,7 +59,7 @@ The default for newly selected workspaces is `full`, which prioritizes ease of u
|
|
|
59
59
|
|
|
60
60
|
`exec_command` has both executable authority and shell expansion. Use `--no-exec` or `review`/`edit` when process execution is unnecessary.
|
|
61
61
|
|
|
62
|
-
For untrusted repositories or instructions, run the bridge inside a disposable VM/container or under a dedicated low-privilege OS account. On macOS and Windows, this external isolation is especially important. The project does not claim an in-process OS sandbox.
|
|
62
|
+
For untrusted repositories or instructions, run the bridge inside a disposable VM/container or under a dedicated low-privilege OS account. On macOS and Windows, this external isolation is especially important. The project does not claim an in-process OS sandbox, CPU quota, resident-memory quota, or network egress policy. `server_info.runtime.execution_guardrails.operating_system_enforcement` reports these gaps explicitly.
|
|
63
63
|
|
|
64
64
|
## Agent instructions, skills, and command manifests
|
|
65
65
|
|
|
@@ -69,7 +69,7 @@ Repository and user instruction files remain untrusted content from the model's
|
|
|
69
69
|
|
|
70
70
|
Automatic `package.*` commands expose only validated script names and fixed package-manager argv; they do not expose script bodies. Executing one still runs repository-controlled package-script code with local-user authority and is not a sandbox or trust upgrade.
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
Remote Worker-health and relay proxy selection honors `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`. Only HTTP(S) proxy URLs are accepted. The local browser-broker health probe never uses those proxy variables: it accepts only canonical `127.0.0.1`, uses a direct bounded HTTP request, and rejects alternate hosts, credentials, query strings, and fragments. Autostart installation persists an allowlist of proxy and custom-CA environment values in `service-environment.json` so a background daemon can reproduce the foreground network route; a proxy URL may itself contain credentials, so this file is sensitive local state and must remain protected with the rest of the state root. Proxy endpoints, credentials, certificate paths, and authorization headers are not returned through MCP or written to operational logs; service status exposes only configured environment key names and relay status exposes only coarse route state.
|
|
73
73
|
|
|
74
74
|
Skill loading is non-executing. `load_local_skill` returns an entrypoint and bounded file inventory; scripts remain inert until a separate process or command tool is called. Symlinked skill directories are followed only after canonical path-policy validation, while symbolic-link `SKILL.md` entrypoints are rejected. Traversal, cycles, content, summaries, and inventory are bounded.
|
|
75
75
|
|
|
@@ -154,7 +154,7 @@ Active plans are owner-only and may temporarily contain argv, non-secret stdin,
|
|
|
154
154
|
|
|
155
155
|
Exact canonical and registration-time resource path aliases, exact resource bytes interpreted as text, and bounded exact base64/hex forms are redacted from retained output. This cannot detect partial, transformed, encrypted, compressed, or application-specific encodings. It also cannot redact unrelated secrets inherited through the full parent environment. Use `capture_output: "discard"` whenever a process may echo credentials, and never place a secret directly in argv, ordinary env, stdin, temporary-file content, or a JSON plan.
|
|
156
156
|
|
|
157
|
-
`finally_steps` run after ordinary success, failure, timeout, and cancellation. Cancellation uses an owner-only marker rather than signaling the runner process itself, so the coordinator remains alive to execute cleanup consistently across platforms. Timeout/cancellation target the process group/tree and keep a forced-termination escalation alive even if the direct child exits before a resistant descendant. Runner identity includes process start time; recovery does not trust a reused PID. A dead runner is detected on the next daemon or local job-CLI start; stale private resource copies are removed and cleanup is retried. This is best effort. Power loss, disk failure, permanent loss of credentials/network access, SIGKILL without later recovery, or security software denying the cleanup executable can prevent cleanup. Finally steps must be idempotent and safe to repeat. Automatic recovery is capped at three attempts so persistent endpoint-security or executable-policy denial cannot create an endless launch loop. Uninstall refuses to remove local state while managed jobs are active; operators must inspect or cancel them first.
|
|
157
|
+
`finally_steps` run after ordinary success, failure, timeout, and cancellation. Cancellation uses an owner-only marker rather than signaling the runner process itself, so the coordinator remains alive to execute cleanup consistently across platforms. Timeout/cancellation target the process group/tree through one shared supervisor and keep a forced-termination escalation alive even if the direct child exits before a resistant descendant. Verified service-daemon stop uses the same graceful-then-force principle but revalidates the complete process identity immediately before escalation. Runner identity includes process start time; recovery does not trust a reused PID. A dead runner is detected on the next daemon or local job-CLI start; stale private resource copies are removed and cleanup is retried. This is best effort. Power loss, disk failure, permanent loss of credentials/network access, SIGKILL without later recovery, or security software denying the cleanup executable can prevent cleanup. Finally steps must be idempotent and safe to repeat. Automatic recovery is capped at three attempts so persistent endpoint-security or executable-policy denial cannot create an endless launch loop. Uninstall refuses to remove local state while managed jobs are active; operators must inspect or cancel them first.
|
|
158
158
|
|
|
159
159
|
Job-scoped `temporary_files` should be used instead of loose helper scripts. They are materialized only below the private job runtime. Remote scripts should preferably be sent through a process stdin instead of written to the remote filesystem.
|
|
160
160
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Machine Bridge Browser",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.8",
|
|
5
5
|
"description": "Connects the current Chromium browser profile to the local Machine Bridge runtime for user-authorized automation.",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"tabs",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"action": {
|
|
31
31
|
"default_title": "Machine Bridge Browser"
|
|
32
32
|
},
|
|
33
|
-
"version_name": "1.2.
|
|
33
|
+
"version_name": "1.2.8"
|
|
34
34
|
}
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -28,7 +28,7 @@ A canonical workspace receives an independent profile, Worker name, secret set,
|
|
|
28
28
|
`LocalRuntime` is the transport-independent local tool orchestrator. It owns the shared authorization/execution pipeline, manager construction, mutation serialization, cancellation, and the narrow delegation surface used by stdio and relay transports. Domain behavior remains in focused services:
|
|
29
29
|
|
|
30
30
|
- `workspace-file-service.mjs` and `git-service.mjs` own canonical filesystem/Git operations;
|
|
31
|
-
- `process-
|
|
31
|
+
- `process-contract.mjs` owns argv shape/size validation, `process-tree.mjs` owns cross-platform tree termination, `process-execution.mjs` and `process-sessions.mjs` own one-shot and interactive execution, and `process-tracker.mjs` owns runtime process accounting;
|
|
32
32
|
- `runtime-reporting.mjs` builds privacy-aware runtime and project snapshots;
|
|
33
33
|
- `runtime-diagnostics.mjs` owns fixed local probes and their stable interpretation;
|
|
34
34
|
- `runtime-capabilities.mjs` composes agent, application, and browser capability results;
|
|
@@ -36,7 +36,7 @@ A canonical workspace receives an independent profile, Worker name, secret set,
|
|
|
36
36
|
|
|
37
37
|
Architecture tests cap the orchestration module and each extracted service independently and reject a return of low-level process, patch, diagnostic, or capability-scoring logic to `LocalRuntime`. `RelayConnection` owns remote WebSocket transport, `hello_ack` authentication, end-to-end `relay_probe`/`ready_ack` readiness, heartbeat liveness, reconnect backoff, outage logging, and a monotonically increasing in-memory session generation. Every relayed tool result is bound to the generation that delivered its call; a disconnected generation cannot send a late result over its replacement socket. Inbound WebSocket dispatch captures that generation at receive time and passes it to the runtime handler, so a successful local tool execution can publish only on the same generation. Stdio mode invokes `LocalRuntime` directly without that adapter.
|
|
38
38
|
|
|
39
|
-
`daemon-process.mjs` owns workspace-daemon inspection and takeover. It distinguishes platform service state from the lock-owning Node process, validates PID and process-start identity, canonicalizes workspace/state paths before comparison, parses bounded process command lines without executing them, accepts lock-backed `--daemon-only` recovery processes that omit repeated path flags
|
|
39
|
+
`daemon-process.mjs` owns workspace-daemon inspection and takeover. It distinguishes platform service state from the lock-owning Node process, validates PID and process-start identity, canonicalizes workspace/state paths before comparison, parses bounded process command lines without executing them, and accepts lock-backed `--daemon-only` recovery processes that omit repeated path flags. Stop/takeover sends `SIGTERM` only to a verified same-workspace service daemon. If it remains alive after the grace period, the code revalidates PID, process-start identity, command line, entrypoint, daemon mode, workspace, and state root before sending `SIGKILL`; a foreground, replaced-PID, or otherwise unverifiable process remains untouched. CLI orchestration never treats a missing launchd/systemd job as proof that the process exited.
|
|
40
40
|
|
|
41
41
|
### Agent context and capability resolver
|
|
42
42
|
|
|
@@ -54,7 +54,7 @@ See [Session instructions, skills, commands, and capability discovery](AGENT_CON
|
|
|
54
54
|
|
|
55
55
|
### Browser extension and machine broker
|
|
56
56
|
|
|
57
|
-
`BrowserBridgeManager` owns only connection orchestration for the loopback HTTP/WebSocket broker, owner/client failover, routed requests, cancellation, and
|
|
57
|
+
`BrowserBridgeManager` owns only connection orchestration for the loopback HTTP/WebSocket broker, owner/client failover, routed requests, cancellation, extension replacement, and start/stop generation control. Every asynchronous startup boundary rechecks the generation so a listener or upstream socket cannot appear after `stop()` has invalidated that start. `browser-operation-service.mjs` owns MCP-facing browser argument normalization, resource-backed values/uploads, form semantics, screenshot conversion, and status presentation. Extension version/capability parsing lives in the strict checked `browser-extension-protocol.mjs`; pairing files and local HTML/Host/Origin helpers live in `browser-pairing-store.mjs`. The first runtime for the machine-level state root becomes broker owner; additional workspaces and stdio runtimes authenticate to `/runtime` and proxy through the same extension socket. This preserves one extension pairing while allowing multiple local MCP runtimes.
|
|
58
58
|
|
|
59
59
|
The packaged Manifest V3 extension runs in the user's existing Chromium profile. Its service worker is limited to pairing, transport, acknowledged protocol readiness, cancellation, and response routing. Fixed `browser-operations.js` owns tab lifecycle, aggregate frame/source budgets, waits, screenshots, and input-backend selection; fixed `page-automation.js` is injected into selected frames for snapshot-version-2 semantics, stable refs, bounded DOM/text traversal, actionability checks, open-Shadow-DOM traversal, structured DOM operations, multi-field forms, and resource-backed file inputs. Fixed `devtools-input.js` exposes only bounded mouse, keyboard, and text sequences through the Chromium debugger API; callers cannot select CDP methods. Trusted sessions attach for one action and detach in `finally`; DOM fallback is allowed only before any DevTools Input dispatch, preventing duplicate side effects after an ambiguous command failure. Protocol 3 requires bidirectional `hello`/`hello_ack` plus exact packaged-version and capability equality; pairing state and replacement are committed only after validation, so an invalid candidate cannot displace or overwrite the working configuration. The broker validates loopback hostnames, canonical extension IDs, matching pairing/broker ports, bearer subprotocols, message sizes, concurrency, and deadlines. Pairing material is owner-only and omitted from MCP/log output.
|
|
60
60
|
|
|
@@ -205,7 +205,7 @@ This is a process-level transaction, not a filesystem-wide atomic transaction ac
|
|
|
205
205
|
|
|
206
206
|
The default `full` profile passes the complete parent environment. Isolated environment mode, used by the narrower named profiles unless overridden, creates private runtime HOME, temporary, and cache directories and passes only a small set of path/locale/platform variables. It reduces accidental credential inheritance but cannot prevent explicit access to known filesystem paths, credential stores, network services, or other user resources.
|
|
207
207
|
|
|
208
|
-
One-shot calls have bounded output and timeouts. Startup-lock waits, daemon takeover, process-session reads, managed-job recovery handoff, browser/page waits, application-cache freshness, and in-memory duration metrics use monotonic elapsed time, so wall-clock correction cannot extend or prematurely terminate their configured duration. Persisted timestamps and retention/credential expiry continue to use wall time. Process sessions retain bounded byte buffers with monotonic offsets, accept bounded stdin, support short output/exit waits, and are capped per runtime. Valid UTF-8 is returned as text; byte slices that are not valid UTF-8 also include lossless base64 data. Session IDs are random. Sessions are memory-only and are killed on runtime stop, remote disconnect, or daemon replacement.
|
|
208
|
+
`execution-limits.mjs` is the shared source for local tool-call concurrency, one-shot process timeout/stdin/output limits, and process-session count/stdin/output/retention limits. `server_info.runtime.execution_guardrails` reports those enforced limits together with explicit `not-enforced` values for CPU quota, memory quota, and network isolation. One-shot calls have bounded output and timeouts. Startup-lock waits, daemon takeover, process-session reads, managed-job recovery handoff, browser/page waits, application-cache freshness, and in-memory duration metrics use monotonic elapsed time, so wall-clock correction cannot extend or prematurely terminate their configured duration. Persisted timestamps and retention/credential expiry continue to use wall time. Process sessions retain bounded byte buffers with monotonic offsets, accept bounded stdin, support short output/exit waits, and are capped per runtime. Valid UTF-8 is returned as text; byte slices that are not valid UTF-8 also include lossless base64 data. Session IDs are random. Sessions are memory-only and are killed on runtime stop, remote disconnect, or daemon replacement.
|
|
209
209
|
|
|
210
210
|
Child processes run in a separate process group where supported. Timeout, cancellation, disconnect, and replacement send termination to process trees, with a referenced forced-escalation timer that remains alive even when the direct child exits before a resistant descendant. Windows uses tree-aware task termination.
|
|
211
211
|
|
|
@@ -215,7 +215,7 @@ Managed jobs use the same argv/environment primitives but a different lifecycle.
|
|
|
215
215
|
|
|
216
216
|
Worker deployment is an explicit two-evidence state machine owned by `worker-deployment.mjs`. Wrangler upload is the authoritative remote write. Public `/healthz` is a subsequent read used to verify identity and package version; it is not a transaction commit signal for the upload. After a successful Wrangler result, local state atomically records the detected `workers.dev` URL, MCP URL, content/secret fingerprint, deployed package version, and timestamp before health verification begins. If verification is ambiguous, the next start compares the same fingerprint and performs a read-only verification rather than repeating the remote write.
|
|
217
217
|
|
|
218
|
-
`worker-health.mjs` owns bounded health I/O: exact HTTPS `workers.dev` origin and Worker-name validation, environment-proxy selection, request timeout, redirect rejection, response-size limit, JSON/identity/version validation, and coarse error classification. `network-proxy.mjs` is shared by HTTP health probes and WebSocket relay construction so both paths honor `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` without exposing proxy details. Definitive stale evidence is retried for propagation and then permits a same-name redeploy; timeout, TLS, network, proxy, and temporary server failure remain ambiguous and fail without upload.
|
|
218
|
+
`worker-health.mjs` owns bounded health I/O: exact HTTPS `workers.dev` origin and Worker-name validation, environment-proxy selection, request timeout, redirect rejection, response-size limit, JSON/identity/version validation, and coarse error classification. `network-proxy.mjs` is shared by remote HTTP health probes and WebSocket relay construction so both paths honor `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` without exposing proxy details. Local browser-broker health uses `loopback-health.mjs`, which accepts only canonical `http://127.0.0.1:<port>/healthz`, disables agent reuse, bounds the response, and deliberately bypasses environment proxies. Definitive stale evidence is retried for propagation and then permits a same-name redeploy; timeout, TLS, network, proxy, and temporary server failure remain ambiguous and fail without upload.
|
|
219
219
|
|
|
220
220
|
Worker-name mutation is a separate identity transition. Existing state rejects a different name unless the caller also supplies the explicit force option. An authorized transition clears the current URL/fingerprint and appends the prior validated name to bounded uninstall inventory. This prevents a health-retry workaround from silently becoming a new remote resource while preserving cleanup of intentional replacements.
|
|
221
221
|
|
|
@@ -247,7 +247,7 @@ Browser-origin handling separates CORS response sharing from protocol authentica
|
|
|
247
247
|
|
|
248
248
|
## Observability
|
|
249
249
|
|
|
250
|
-
Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, managed-job counts, resource alias names without paths or values, relay route state without endpoint details, authenticated/probing/ready socket counts, end-to-end readiness evidence, and privacy-preserving capability-routing evidence. It separates the daemon capability ceiling from the authenticated account authority: `daemon.policy`/`daemon.tools` retain the pre-role ceiling, while `authorization.effective_policy`/`authorization.effective_tools` and the top-level `tools` report the role-intersected authority before any host-side filtering. It explicitly reports that the host-exposed subset is unknown to the server. `diagnose_runtime` runs fixed local probes and explicitly reports that its own request reached the daemon.
|
|
250
|
+
Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, managed-job counts, resource alias names without paths or values, relay route state without endpoint details, authenticated/probing/ready socket counts, end-to-end readiness evidence, local execution guardrails, explicit OS-enforcement gaps, and privacy-preserving capability-routing evidence. It separates the daemon capability ceiling from the authenticated account authority: `daemon.policy`/`daemon.tools` retain the pre-role ceiling, while `authorization.effective_policy`/`authorization.effective_tools` and the top-level `tools` report the role-intersected authority before any host-side filtering. It explicitly reports that the host-exposed subset is unknown to the server. `diagnose_runtime` runs fixed local probes and explicitly reports that its own request reached the daemon.
|
|
251
251
|
|
|
252
252
|
Foreground logging defaults to `info`; autostart uses `warn`. Authenticated readiness, persistent degradation, and recovery are user-visible state transitions. Brief relay interruptions, raw transport close details, retry timing, and all per-tool starts/successes/failures/cancellations/durations are debug-only. Unexpected local and Worker infrastructure errors are reduced to classes. Messages, strings, arrays, object depth/key counts, and serialized fields are bounded.
|
|
253
253
|
|
|
@@ -255,9 +255,11 @@ Cloudflare sampling is size control rather than an audit log. The project intent
|
|
|
255
255
|
|
|
256
256
|
## Release integrity
|
|
257
257
|
|
|
258
|
-
Repository-local checks are necessary but cannot prove
|
|
258
|
+
Repository-local automated checks are necessary but cannot prove that the maintainer's ordinary installation path works. `scripts/local-release-acceptance.mjs` builds the exact npm tarball, requires an explicit repository-owner confirmation after local testing, and records both npm hashes outside the package. `scripts/github-push.mjs`, pull-request CI, and `scripts/github-release.mjs` rebuild the package and reject any mismatch. The release helper also requires `HEAD === origin/main`; it cannot silently push `main`.
|
|
259
259
|
|
|
260
|
-
|
|
260
|
+
Cross-platform evidence remains independent. `scripts/github-release.mjs` queries CI, CodeQL, Governance, and Scorecard for the exact `origin/main` commit and requires the newest push-triggered run for each workflow to be completed with `success` before it creates or verifies a version tag, GitHub Release, or package asset. Pull-request runs, older successful runs, pending runs, and successful runs for another SHA do not satisfy the gate. The workflow selection policy is isolated in `scripts/release-ci.mjs` and tested independently.
|
|
261
|
+
|
|
262
|
+
Third-party workflow actions are pinned to immutable commit SHAs. Dependabot groups GitHub Action updates into one reviewed PR so coupled action families cannot drift across versions. `architecture:test` rejects movable action tags, split update policy, loss of local acceptance verification, or removal of the reachable-history package-audit step.
|
|
261
263
|
|
|
262
264
|
## Explicit non-goals
|
|
263
265
|
|
package/docs/AUDIT.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Security and privacy audit notes
|
|
2
2
|
|
|
3
|
+
## 2026-07-17 version 1.2.8 release-integrity and dependency-automation audit
|
|
4
|
+
|
|
5
|
+
The core failure was procedural rather than a missing unit test: the repository treated a green automated suite as sufficient evidence for source publication, and `release:publish` could push a locally tested commit directly to `main`. That model cannot satisfy the reported history of formally released builds failing on the maintainer's real installation. It also assigned the coding agent authority to infer release acceptance, even though only the repository owner can observe the ordinary local environment and decide whether the product is usable.
|
|
6
|
+
|
|
7
|
+
Version 1.2.8 separates automated verification from owner acceptance. The candidate command runs the full suite and packs the exact artifact. The owner tests that tarball and records a fixed confirmation; a second pack must have identical npm SHA-1 and SHA-512 integrity before the tracked record is written. The record is outside the package manifest, so adding it and squash-merging do not alter the accepted bytes. Any packaged source, script, metadata, browser-extension, or shipped-documentation change invalidates the record. The guarded push command checks cleanliness, branch safety, tracking, and package hashes. CI repeats the hash check. Final release creation requires the same acceptance plus exact-commit CI, CodeQL, Governance, and Scorecard success, and it no longer contains a path that pushes `main`. The acceptance record is a reviewed process assertion, not a cryptographic identity signature; automation is explicitly prohibited from creating it on the owner's behalf.
|
|
8
|
+
|
|
9
|
+
The five open Dependabot PRs exposed a second design defect. The three CodeQL sub-actions were proposed independently even though CodeQL rejects mixed action versions, while every Action-only PR was forced through an npm release-impact gate that considered all repository files package changes. The combined update now keeps all CodeQL components on 4.37.1, updates setup-node to 7.0.0 and upload-artifact to 7.0.1, groups future GitHub Action updates, and derives npm release relevance from the package manifest. GitHub-only workflow maintenance can therefore be reviewed without inventing an npm version, while package content remains fail-closed. Official tag objects were resolved through GitHub and match every pinned SHA. The setup-node and upload-artifact majors move their action runtimes to Node 24/ESM without changing the inputs used here; CodeQL 4.37.1 advances the default bundle to 2.26.1. Architecture tests now require all three CodeQL action roles to share one immutable commit even if dependency automation regresses.
|
|
10
|
+
|
|
11
|
+
The broader pass rechecked dependency health, install-script policy, package contents, release scripts, workflow permissions, immutable Action pinning, source and test size guardrails, process/network boundary inventory, privacy scanning, documentation ownership, and existing architecture limits. Both complete and production npm audits report zero vulnerabilities, the dependency tree reports no structural problems, and Wrangler's only available patch was advanced to 4.112.0 with the exact new workerd install script reviewed and allowlisted. No credential-like tracked artifact beyond the deliberate non-secret repository `.npmrc` was found. Existing execution, relay, browser, state, ACL, logging, and lifecycle behavior remains covered by the prior risk-directed suites; this change does not claim OS CPU/memory/network isolation that the runtime does not implement.
|
|
12
|
+
|
|
13
|
+
No branch, tag, GitHub Release, npm package, Worker deployment, global installation, daemon/service replacement, credential change, or live state mutation is performed before the repository owner tests and accepts the 1.2.8 candidate.
|
|
14
|
+
|
|
15
|
+
## 2026-07-17 version 1.2.7 process-supervision and lifecycle audit
|
|
16
|
+
|
|
17
|
+
The core question in this review was not whether the existing green suite covered many paths; it was whether failure and ownership boundaries remained truthful when processes resist termination, startup is interrupted, proxy state is hostile, or the operating system refuses a spawn. The audit found that generic argv validation and process-tree termination had drifted into the interactive-session module, while shell and managed-job paths maintained adjacent termination branches. This created a dependency inversion: one-shot execution and process accounting depended on an adapter whose responsibility should have been only interactive session state.
|
|
18
|
+
|
|
19
|
+
Version 1.2.7 extracts `process-contract.mjs`, `process-tree.mjs`, and `execution-limits.mjs`. All process-owning paths now share the same cross-platform tree supervisor and bounded graceful-to-forced escalation. A verified detached service daemon that ignores `SIGTERM` is no longer left indefinitely alive: immediately before `SIGKILL`, Machine Bridge repeats process-start identity and complete daemon command/workspace/state validation. A reused PID, changed command, foreground process, partial identity, or other ambiguity blocks escalation. Process sessions use the same escalation, and tests use resistant descendants rather than source-shape assertions alone.
|
|
20
|
+
|
|
21
|
+
A separate lifecycle race existed in the browser broker. `stop()` could run while pairing/listen/proxy startup was awaiting I/O; the old start could then finish and repopulate a listener after shutdown. Startup now carries a monotonically increasing generation through every asynchronous boundary. Stop invalidates that generation, and stale completion closes all HTTP/WebSocket transports, pending calls, and routed proxy requests. Browser status also no longer relies on global `fetch` for loopback health: a strict bounded direct-HTTP adapter accepts only canonical `127.0.0.1` and cannot be diverted by environment proxy configuration. Remote Worker health and relay traffic continue to use the documented proxy resolver.
|
|
22
|
+
|
|
23
|
+
The resource review distinguished application bounds from kernel controls. The implementation has real concurrency, timeout, stdin, output, retention, and job-size limits, but it does not create CPU quotas, resident-memory ceilings, syscall sandboxes, or egress filters. `server_info.runtime.execution_guardrails` now states both categories explicitly so a timeout cannot be misread as a CPU quota and a proxy route cannot be misread as network isolation. Hard isolation remains an external deployment responsibility: dedicated low-privilege account, container, or VM.
|
|
24
|
+
|
|
25
|
+
Managed-job launch previously assumed `spawn()` returned a usable child. A system-level launch failure could emit an unhandled child `error` after the job had been reported accepted. Launch now attaches the error observer before returning, refuses acceptance without a positive PID, records a coarse structured failure class, and keeps shell parsing disabled explicitly. The audit also corrected stale `hello_ack`-only readiness wording, incorrect `server_info` field paths, a duplicated plan-retention guard, and documentation that still described daemon takeover as non-escalating.
|
|
26
|
+
|
|
27
|
+
Policy revision 5, state schema 6, OAuth/account records, browser-extension protocol 3, and the account role mapping are unchanged. Profile ACL remains a two-sided intersection: the Worker filters the account role against the daemon ceiling, and the local runtime repeats the role check before handler dispatch. This remains application authorization, not per-account OS tenancy. No Worker deployment, daemon/service replacement, credential rotation, global installation, npm publication, tag, or GitHub Release is performed by the source changes themselves.
|
|
28
|
+
|
|
3
29
|
## 2026-07-17 version 1.2.6 relay ready-context and daemon-takeover audit
|
|
4
30
|
|
|
5
31
|
Version 1.2.5 introduced fail-closed rejection of ordinary tool calls before end-to-end readiness. That boundary is correct, but an incomplete inbound dispatch object that carried only `sessionId` (the 1.2.4 session-binding shape) evaluated as not ready and converted the first real tool call into a permanent local protocol error. Version 1.2.6 keeps the explicit `ready: false` fail-closed path, requires RelayConnection to forward boolean `authenticated`/`ready`, and allows a live ready relay status to satisfy readiness only when the snapshot omitted the field.
|
package/docs/ENGINEERING.md
CHANGED
|
@@ -9,7 +9,7 @@ This document records project-wide decisions that must survive individual fixes,
|
|
|
9
9
|
3. **Machine Bridge authority and host authority are separate.** `full` removes Machine Bridge's own policy, path, shell, and environment restrictions. It cannot override an MCP host, connector gateway, operating system, endpoint-security product, cloud IAM, remote authentication, or `sudo`.
|
|
10
10
|
4. **Publication surfaces contain no real environment metadata.** Source, tests, fixtures, examples, release notes, filenames, package contents, tags, and release assets use synthetic identifiers and reserved example domains.
|
|
11
11
|
5. **Secrets are never operational log data.** Tool arguments, command text, stdin, stdout, stderr, file content, OAuth bodies, credentials, and local resource values are not logged.
|
|
12
|
-
6. **A release is one
|
|
12
|
+
6. **A release is one owner-tested package with successful cross-platform evidence.** The repository owner must test the exact npm tarball and record its hashes before the first GitHub push of an npm-package change. Package metadata, Worker version, browser-extension version/name, acceptance record, Git tag, GitHub Release, npm version, documentation, and deployed health version must agree, and the exact `origin/main` commit must have completed successful push-triggered CI, CodeQL, Governance, and OpenSSF Scorecard runs before a tag or release is created.
|
|
13
13
|
7. **Generic local automation is structured, not arbitrary evaluation.** Browser/application features may expose broad user authority under canonical `full`, but must not accept caller-provided JavaScript, AppleScript, JXA, or extension code.
|
|
14
14
|
8. **Daily-browser integration uses the existing profile.** The supported primary browser path is the packaged authenticated extension and machine-level loopback broker, preserving current tabs/login state; a separate automation profile is not an equivalent replacement.
|
|
15
15
|
9. **Pairing and resource secrets are not conversation or log data.** Tokens and injected local-resource values must not be returned, embedded in URLs, or written to operational logs.
|
|
@@ -24,7 +24,7 @@ A proposed change that conflicts with an invariant requires an explicit owner de
|
|
|
24
24
|
|
|
25
25
|
## Change and release-operation ownership
|
|
26
26
|
|
|
27
|
-
Repository source release completion and live release operations are separate responsibilities. Under
|
|
27
|
+
Repository implementation, owner acceptance, source release completion, and live release operations are separate responsibilities. Under `AGENTS.md`, coding automation may edit, test, and commit locally, then generate an exact candidate tarball. It must stop before the first GitHub push until the repository owner personally tests that artifact and records `release-acceptance/v<version>.json`. The agent may then push only through `npm run github:push`, complete the pull request through local `git`/`gh`, and create the annotated version tag plus final GitHub Release only after the accepted package hash and exact `main` checks pass. `release:publish` never pushes `main`. Automation must not assert owner acceptance, publish or alter npm packages, install globally, deploy or reconfigure a Worker, rotate credentials, mutate live deployment state, or replace daemon/service state without explicit user authorization.
|
|
28
28
|
|
|
29
29
|
The normal handoff is: the repository owner publishes the reviewed npm version, then runs `npm install -g --omit=optional --allow-scripts=esbuild,workerd,sharp,fsevents machine-bridge-mcp@latest && machine-mcp`. The npm command updates the global CLI but cannot hot-reload an existing Node process. The subsequent normal foreground startup validates the Worker deployment hash, expected version, and health, requests shutdown of an active autostart daemon, waits a bounded interval for its lock, redeploys when necessary, and then takes over with the installed version. Live operations require explicit authorization even when they appear to be the obvious next release step.
|
|
30
30
|
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -61,7 +61,7 @@ A brief relay interruption is retried automatically and is visible only with `--
|
|
|
61
61
|
|
|
62
62
|
Use `--verbose` only when close codes, close reasons, heartbeat timeouts, and retry delays are needed for diagnosis. A close code of 1006 means the transport ended without a normal close handshake; it does not by itself identify the cause.
|
|
63
63
|
|
|
64
|
-
The daemon honors `HTTPS_PROXY`/`HTTP_PROXY` and `NO_PROXY` through standard environment-proxy resolution. `wss:` targets use HTTPS proxy selection and `ws:` targets use HTTP proxy selection. Only HTTP and HTTPS proxy URLs are accepted. Invalid URLs or unsupported protocols fail startup with corrective guidance instead of entering the reconnect loop. `server_info.runtime.relay.network_route` reports only `direct`, `proxy`, or `invalid-proxy-configuration`; proxy endpoints and credentials are never returned or logged.
|
|
64
|
+
The daemon honors `HTTPS_PROXY`/`HTTP_PROXY` and `NO_PROXY` through standard environment-proxy resolution for remote Worker health and relay traffic. `wss:` targets use HTTPS proxy selection and `ws:` targets use HTTP proxy selection. Only HTTP and HTTPS proxy URLs are accepted. Invalid URLs or unsupported protocols fail startup with corrective guidance instead of entering the reconnect loop. `server_info.runtime.relay.network_route` reports only `direct`, `proxy`, or `invalid-proxy-configuration`; proxy endpoints and credentials are never returned or logged. The browser-broker CLI health probe is a separate loopback-only path: it accepts only canonical `127.0.0.1`, uses direct Node HTTP with no proxy agent, and does not depend on `NO_PROXY`.
|
|
65
65
|
|
|
66
66
|
## Browser extension setup and diagnosis
|
|
67
67
|
|
|
@@ -95,7 +95,7 @@ Application UI inspection/actions require Accessibility permission for the Node/
|
|
|
95
95
|
|
|
96
96
|
`machine-mcp` is a foreground command. It remains attached to the terminal, defaults to `info` logging, and stops on `Ctrl+C`. `machine-mcp service start` launches the installed platform service in the background and returns to the shell; that service uses `warn` logging.
|
|
97
97
|
|
|
98
|
-
A global npm install changes the CLI files on disk but does not replace an already running Node process. Startup and other state-changing CLI operations use a token/process-identity lock and wait up to 30 seconds for a normal concurrent startup to finish; duration limits use monotonic elapsed time, so NTP or manual wall-clock correction does not lengthen or shorten the wait; a short launchd/systemd overlap is therefore serialized rather than reported immediately as an error. On a normal foreground start, Machine Bridge unloads the platform service and then independently examines the workspace daemon lock. This second path handles a detached/orphan `--daemon-only` process that launchd, systemd, or Task Scheduler no longer tracks. Only current lock records containing service mode, version, PID, process start time, entrypoint, workspace, and state root are eligible for takeover. Before sending `SIGTERM`, Machine Bridge verifies PID and process start time plus the live command line, entrypoint, and daemon-only flag. Explicit `--workspace` and `--state-dir` must both match the active state when present; a recovery daemon started with only `--daemon-only` is accepted when the lock owner already records that workspace and state root. Partial path identity (only one of the two flags) is rejected.
|
|
98
|
+
A global npm install changes the CLI files on disk but does not replace an already running Node process. Startup and other state-changing CLI operations use a token/process-identity lock and wait up to 30 seconds for a normal concurrent startup to finish; duration limits use monotonic elapsed time, so NTP or manual wall-clock correction does not lengthen or shorten the wait; a short launchd/systemd overlap is therefore serialized rather than reported immediately as an error. On a normal foreground start, Machine Bridge unloads the platform service and then independently examines the workspace daemon lock. This second path handles a detached/orphan `--daemon-only` process that launchd, systemd, or Task Scheduler no longer tracks. Only current lock records containing service mode, version, PID, process start time, entrypoint, workspace, and state root are eligible for takeover. Before sending `SIGTERM`, Machine Bridge verifies PID and process start time plus the live command line, entrypoint, and daemon-only flag. Explicit `--workspace` and `--state-dir` must both match the active state when present; a recovery daemon started with only `--daemon-only` is accepted when the lock owner already records that workspace and state root. Partial path identity (only one of the two flags) is rejected. If the verified daemon ignores graceful termination, Machine Bridge waits for the grace period, then repeats process-instance and full daemon-identity verification before sending `SIGKILL`. PID reuse, identity drift, foreground mode, or any ambiguity blocks escalation. The total stop remains bounded at 15 seconds and stale lock reclamation still uses token-aware ownership. A foreground or unverifiable process is left untouched; stop a foreground instance with `Ctrl+C`.
|
|
99
99
|
|
|
100
100
|
`machine-mcp service status [WORKSPACE]` reports two independent layers: the platform service (`active`) and `workspace_daemon`, plus `effective_active` and `orphaned_workspace_daemon` summary flags. On macOS it is possible for launchd to report inactive while a prior Node process remains alive with parent PID 1; that is an orphan-daemon condition, not proof that the daemon stopped. `service stop` unloads the provider when present and then terminates only a verified service-style workspace daemon. `service uninstall` and full uninstall are ordered fail-closed operations: provider stop → verified daemon stop(s) → definition removal. A failed or ambiguous stop leaves definitions and state intact. If takeover reaches its deadline, run:
|
|
101
101
|
|
|
@@ -147,7 +147,7 @@ Uninstall acquires a state-root `maintenance.lock` that blocks new profile/state
|
|
|
147
147
|
|
|
148
148
|
### Lifecycle and pending-call diagnosis
|
|
149
149
|
|
|
150
|
-
`server_info.runtime.lifecycle` reports `ready`, `starting`, `running`, `failed`, `stopping`, or `stopped`. `
|
|
150
|
+
`server_info.runtime.lifecycle` reports `ready`, `starting`, `running`, `failed`, `stopping`, or `stopped`. `server_info.observability.in_flight_calls` and `server_info.runtime.processes` distinguish a blocked call from a surviving process. `server_info.runtime.execution_guardrails` reports the enforced local concurrency/timeout/stdin/output/session limits and explicitly states that CPU quota, memory quota, and network isolation are not enforced in process. Worker `server_info.worker.pending_calls` reports both the internal-call index and client request-key index; they must return to zero after a terminal result, explicit cancellation, client disconnect, timeout, send failure, or daemon disconnect. Nonzero request-key counts after active calls reach zero indicate a lifecycle defect rather than normal load. `worker.observability.calls.unmatched_results` is the bounded counter for late results that no longer have a receiver.
|
|
151
151
|
|
|
152
152
|
Stable errors include `policy_denied`, `invalid_request`, `timeout`, `cancelled`, `network_error`, `unavailable`, `limit_exceeded`, and `integrity_error`, with retryability metadata. Diagnose by code first; free-form messages are guidance, not an API contract.
|
|
153
153
|
|
|
@@ -268,6 +268,8 @@ Defense-in-depth limits include:
|
|
|
268
268
|
- application Accessibility inspection: 500 elements and depth 12; action text: 4,000 characters;
|
|
269
269
|
- job-scoped temporary files: 16 files, 512 KiB total content.
|
|
270
270
|
|
|
271
|
+
The list above describes bounded application resources, not OS quotas. CPU time shares, resident-memory ceilings, syscall sandboxes, and egress policy must be imposed by the account/container/VM that runs Machine Bridge. Check `server_info.runtime.execution_guardrails.operating_system_enforcement`; current in-process values are intentionally `not-enforced` rather than inferred from timeouts or output limits.
|
|
272
|
+
|
|
271
273
|
## Upgrade behavior
|
|
272
274
|
|
|
273
275
|
Policy revision 5 makes named profiles canonical and evaluates compound tool requirements from the shared contract. A state entry labelled `full` means writes, direct processes, process sessions, shell execution, unrestricted direct filesystem paths, absolute path output, the complete parent environment, and the complete tool catalog. CLI capability overrides are stored as `custom`. Persisted policies from another revision are rejected rather than interpreted.
|
|
@@ -18,11 +18,15 @@ Branch names use a short category and purpose, for example `feat/browser-downloa
|
|
|
18
18
|
|
|
19
19
|
Direct pushes to `main`, force pushes, and branch deletion are blocked by repository protection. An exception requires an incident record and an explicit owner decision.
|
|
20
20
|
|
|
21
|
-
### Completion ownership
|
|
21
|
+
### Completion ownership and local acceptance
|
|
22
22
|
|
|
23
|
-
Repository automation owns
|
|
23
|
+
Repository automation owns implementation, local validation, and pull-request completion, but it does not own the maintainer's release acceptance decision. For every npm-package change, automation must generate the exact candidate tarball with `npm run release:candidate` and stop before the first GitHub push. The repository owner must install or otherwise exercise that exact tarball on the maintainer machine through the normal user path and record a passing decision with `npm run release:accept -- --confirm "I TESTED machine-bridge-mcp <version> LOCALLY AND IT WORKS"`. Automation must not create that assertion on the owner's behalf.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The tracked `release-acceptance/v<version>.json` record binds the decision to the npm tarball SHA-1 and SHA-512 integrity value. The record is excluded from the package, so a content-preserving squash merge does not invalidate it; any source, executable script, package metadata, or packaged-documentation change produces a different package hash and requires a new local test. `npm run github:push`, pull-request CI, and `release:publish` verify the record. Raw direct pushes of release-relevant branches are prohibited.
|
|
26
|
+
|
|
27
|
+
After owner acceptance, repository automation may push only through `npm run github:push`, open and complete the pull request, verify the resulting `main` commit, and remove the merged branch. Every npm-package change advances the package version and is completed by an annotated `v<version>` tag plus a final GitHub Release for the exact successful `main` commit. GitHub-only repository infrastructure changes that do not alter npm package contents do not require a synthetic package version or local runtime acceptance, but they still require review and their applicable CI/security checks.
|
|
28
|
+
|
|
29
|
+
The coding agent may perform the tag and GitHub Release work only after the recorded owner acceptance and exact-commit checks succeed. npm publication, Worker deployment, credential mutation, global installation, and daemon/service replacement remain separate live operations requiring explicit authorization.
|
|
26
30
|
|
|
27
31
|
### Local GitHub control plane
|
|
28
32
|
|
|
@@ -115,10 +119,10 @@ Flaky tests are defects. A retry may diagnose environmental instability but may
|
|
|
115
119
|
## 7. Security and software supply chain
|
|
116
120
|
|
|
117
121
|
- GitHub workflow permissions default to read-only and are expanded per job only when required.
|
|
118
|
-
- Third-party Actions are pinned to immutable commit SHAs and reviewed when Dependabot updates them.
|
|
122
|
+
- Third-party Actions are pinned to immutable commit SHAs and reviewed when Dependabot updates them. GitHub Action updates are grouped into one atomic pull request so coupled suites such as CodeQL cannot be split across incompatible versions.
|
|
119
123
|
- npm dependencies use exact versions and a committed lockfile. Source bootstrap uses `npm ci`; the CI npm baseline itself is downloaded from an exact URL and verified against a pinned SHA-512 SRI before use. Registry signatures and attestations are verified in CI.
|
|
120
124
|
- Dependency review blocks newly introduced vulnerable dependencies. CodeQL performs JavaScript/TypeScript and workflow analysis. OpenSSF Scorecard audits supply-chain posture, and both SARIF streams are failing gates with exact, expiring exceptions rather than advisory-only uploads.
|
|
121
|
-
- CI generates and validates a CycloneDX SBOM. Release artifacts must be reproducible from a reviewed commit and tied to successful exact-commit CI, CodeQL, Governance, and Scorecard evidence.
|
|
125
|
+
- CI generates and validates a CycloneDX SBOM. Release artifacts must match the repository-owner-tested tarball hash, be reproducible from a reviewed commit, and be tied to successful exact-commit CI, CodeQL, Governance, and Scorecard evidence.
|
|
122
126
|
- Secret scanning and push protection are enabled. Repository examples use synthetic identities and reserved domains; reachable history is scanned before release.
|
|
123
127
|
- Long-lived publication tokens should be replaced by npm trusted publishing with GitHub OIDC. Until that external registry configuration is completed, release credentials remain an explicit operator responsibility and must never be stored in the repository.
|
|
124
128
|
- Security reports follow [SECURITY.md](../SECURITY.md), not public issue templates.
|