machine-bridge-mcp 3.0.0-beta.199 → 3.0.0-beta.200
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 +13 -111
- package/README.md +2 -0
- package/browser-extension/manifest.json +1 -1
- package/docs/AUDIT.md +2 -2
- package/package.json +14 -14
- package/scripts/verification-state.mjs +2 -1
- package/src/local/cf-network-integrity.mjs +68 -0
- package/src/local/cf-project.mjs +40 -13
- package/src/local/wrangler-toolchain/package-lock.json +171 -189
- package/src/local/wrangler-toolchain/package.json +7 -7
- package/src/local/wrangler-toolchain-installed-tree.mjs +15 -14
- package/src/local/wrangler-toolchain.mjs +23 -28
- package/src/worker/index.ts +1 -1
- package/src/local/cf-network-compatibility.mjs +0 -100
package/CHANGELOG.md
CHANGED
|
@@ -1,117 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 3.0.0-beta.
|
|
3
|
+
## 3.0.0-beta.200 - 2026-10-09
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- Remove the redundant managed-job result `recovered` compatibility boolean; recovery outcome is represented only by the terminal status enum, and interrupted recovery never replays main steps.
|
|
18
|
-
- Require Git 2.50 or later for reachable-history privacy scanning instead of carrying an older `rev-list` output parser; fail before scanning when the trusted Git version is too old or malformed.
|
|
19
|
-
- Reject non-string OAuth grant types, authorization codes, PKCE verifiers, client identifiers, redirect URIs, resources, scopes and refresh tokens before credential lookup or consumption.
|
|
20
|
-
- Apply the Sharp 0.35.5 minimum independently to consumer CycloneDX validation as well as the installed dependency tree, including malformed and prerelease version rejection.
|
|
21
|
-
- Reject coercible legacy resource-staging publisher PID evidence instead of accepting strings, arrays or booleans as process identities; retain the staging files on malformed ownership.
|
|
22
|
-
- Refuse staging reclamation when the publisher PID encoded in a current-format filename exceeds safe integer bounds, rather than treating invalid process identity as permission to delete.
|
|
23
|
-
- Remove the retired version-2 capability-lease/release-task cleanup compatibility surface from current documentation and state-root removal; unsupported older state is preserved and rejected instead of interpreted by the current runtime.
|
|
24
|
-
- Reject non-string browser extension IDs, origins, and manifest public keys instead of allowing arrays or other values to acquire extension identity through JavaScript string coercion.
|
|
25
|
-
- Treat synchronous security-audit worker transport failures as terminal worker failures, settle all pending audit promises, mark health unavailable, and account for records that could not be persisted instead of leaving queued callers hanging.
|
|
26
|
-
- Stop interpreting retired schema-v1 Worker continuity evidence; unsupported persisted continuity schemas now fail closed to empty current-schema diagnostics instead of partially migrating historical counters.
|
|
27
|
-
- Reject non-string persisted daemon socket roles instead of allowing arrays or other values to pass role validation through JavaScript string coercion.
|
|
28
|
-
- Add a random per-daemon pseudonym correlation epoch to new security-audit events so incident review can identify runtime-key rotation boundaries without creating stable cross-restart principal or target identifiers.
|
|
29
|
-
- Remove the redundant browser-extension `tabs` permission; existing `<all_urls>` host authority already supplies tab metadata for scriptable pages, while restricted browser-internal pages now expose less metadata to the extension.
|
|
30
|
-
- Route npm publication cleanup warnings through the shared release diagnostic sanitizer so a successful publication cannot leak local home paths or credential-shaped values through best-effort cleanup messages.
|
|
31
|
-
- Mark browser-derived page text, accessibility labels, DOM attributes, and screenshots as untrusted data in remote MCP server instructions so webpage prompt injection is not presented as authorization or higher-precedence guidance.
|
|
32
|
-
- Repair the privacy regression fixture so Git-version boundary assertions use Node's strict assertion API instead of the test file's boolean-only helper, restoring coverage-gate execution of the privacy suite.
|
|
33
|
-
- Remove schema-v1 migration rationale from the always-injected MCP server instructions now that the runtime is current-schema-only; historical rationale remains in release history instead of consuming every client context.
|
|
34
|
-
- Reject Git version components outside JavaScript safe-integer bounds so malformed trusted-Git version output cannot satisfy the privacy-history minimum through numeric infinity coercion.
|
|
35
|
-
- Keep promotion-digest npm pack metadata type-exact by rejecting non-string paths and non-integer file modes instead of normalizing coercible values into release evidence.
|
|
36
|
-
- Replace stale fixed beta.1 commands in the release guide with an explicit next-version variable and a soak-confirmation command derived from the current package version, preventing copy/paste of an obsolete prerelease identifier.
|
|
37
|
-
- Reject non-string local account-admin lookup targets instead of allowing arrays or other values to select a privileged account through string coercion.
|
|
38
|
-
- Require persisted resource lease, waiter, transaction-lock, and newly bound child PIDs to be positive safe integers so precision-losing process identities fail as integrity errors instead of being silently reclaimed or bound.
|
|
39
|
-
- Apply the same safe-integer PID boundary to the shared owner-state lock primitive so malformed toolchain and maintenance ownership evidence cannot be reclaimed after precision loss.
|
|
40
|
-
- Preserve an in-flight browser pairing exchange after invalid final challenge, nonce, or proof attempts; the one-time grant is now consumed only after the final HMAC proof succeeds, preventing unauthenticated failures from deleting a legitimate pending exchange.
|
|
41
|
-
- Require service network/TLS environment values to remain native strings on capture and reload so malformed persisted arrays or numbers cannot be coerced into active proxy or certificate configuration.
|
|
42
|
-
- Make shared device-session and daemon-authentication transcript builders type-exact so arrays, numeric strings, or other coercible values cannot acquire signed protocol semantics if a future caller omits its own pre-validation.
|
|
43
|
-
- Keep process-tree ownership snapshots type-exact by accepting only positive safe-integer child PIDs, matching persisted active-child and lock ownership boundaries.
|
|
44
|
-
- Advance security-audit state to schema 3 while retaining one exact, one-way beta.198 schema-1 data migration: prior event objects and hashes remain unchanged under a schema-3 envelope with an explicit legacy-prefix count, while all newly appended events require current pseudonym, operation-correlation, and settlement fields.
|
|
45
|
-
- Split browser operation scalar/response-contract validation into a fixed preloaded extension module and lower the browser-operations responsibility budget, removing its near-limit 1900-line concentration without changing dispatch semantics.
|
|
46
|
-
- Stop reclaiming malformed daemon/startup/maintenance and managed-job lock files by age alone. Current lock publication is complete-before-visible, so malformed owner metadata is now retained as an integrity blocker; only structurally valid owners with provably stale process identity are automatically reclaimed.
|
|
47
|
-
- Keep browser pairing types exact after the URL parsing boundary: the service worker and HMAC bootstrap now require native integer ports, string grants, and numeric clocks instead of accepting coercible arrays or numeric strings.
|
|
48
|
-
- Gate remote non-read-only dispatch on durable security-audit health and a persisted `dispatch_intent`. Intent and terminal records share a runtime-private operation reference; the intent deliberately proves only that the authorized pre-dispatch boundary was reached, so a timeout cannot be misread as proof that the handler started.
|
|
49
|
-
- Make the audit pre-dispatch gate consume an explicit local side-effect classification rather than MCP annotation metadata, and regression-check public `readOnlyHint` values against that security classification so catalog drift cannot silently weaken the gate.
|
|
50
|
-
- Expose whether managed-job recovery attribution is complete without inventing beta.198 history: beta.199 recovery entries must form a contiguous suffix ending at the current attempt count, while prior-version attempt counts with no persisted reason/time remain explicitly `recovery_history_complete=false`.
|
|
51
|
-
- Keep daemon relay targets type-exact from persisted/runtime configuration through WebSocket and HTTPS fallback: non-string Worker URLs are rejected rather than being coerced into authenticated network origins, and malformed HTTP relay URLs use one fixed error classification.
|
|
52
|
-
- Apply the same exact-string Worker origin/name boundary to deployment health verification so malformed persisted arrays cannot be normalized into healthy Worker identity evidence.
|
|
53
|
-
- Keep current security-audit hashes, pseudonym epochs, timestamps, and numeric counters type-exact; arrays and numeric strings no longer become valid-looking audit evidence through regular-expression or numeric coercion.
|
|
54
|
-
- Tighten both current and beta.198 audit readers to the actual writer image: canonical ISO timestamps, bounded token/text forms, and non-negative safe-integer duration/byte counters. Hash-consistent values that no supported writer could emit are rejected as integrity failures.
|
|
55
|
-
- Reject precision-losing process IDs in resource ancestry sampling and lease accounting so malformed `ps`/PowerShell evidence cannot collapse distinct PIDs into one JavaScript number.
|
|
56
|
-
- Retire pre-beta.198 temporary Worker-secret filename compatibility. Cleanup now recognizes only the current PID + creation-time + process-start-time + 12-hex nonce shape; obsolete lookalike secret files are retained as explicit integrity blockers instead of being weakly attributed or silently ignored.
|
|
57
|
-
- Keep local device-root/session authentication primitives type-exact: public roots now pass shared canonical P-256 validation, authentication clocks require native finite numbers, and session-signing transcripts require native strings rather than coercible values.
|
|
58
|
-
- Preserve security-audit evidence types end to end: the daemon no longer coerces injected audit clocks before persistence, and recent-activity projection no longer normalizes string/array timestamps or byte counters into valid-looking evidence.
|
|
59
|
-
- Keep managed-job retention timestamps type-exact before destructive maintenance: malformed staged `created_at` values no longer gain expiry authority through string coercion, and terminal retention ordering only parses native timestamp strings.
|
|
60
|
-
- Make account-administration authentication transcripts and local request construction type-exact: origin/method/path/hash/key/nonce fields no longer accept coercible values, signed body bytes must already be a string, and display names are rejected rather than stringified.
|
|
61
|
-
- Require daemon candidate/readiness/liveness timestamps to be native canonical ISO strings before they can establish freshness or alarm deadlines; JavaScript-coercible arrays and alternate timestamp spellings no longer become liveness evidence.
|
|
62
|
-
- Document the existing `file:` browser-automation privacy boundary explicitly: when Chromium file-URL access is enabled, local file-backed tabs are data-bearing automation surfaces rather than ordinary harmless tab metadata.
|
|
63
|
-
- Add an explicit offline `machine-mcp browser reset` revocation path. It serializes through state maintenance, refuses active runtime/job ownership, rechecks that the loopback broker is stopped, and atomically rotates both broker HMAC credentials without exposing their replacements.
|
|
64
|
-
- Correct the browser-pairing storage model in the threat/automation docs: authoritative broker credentials remain in owner-only Machine Bridge state, while the extension stores its extension-token copy in Chromium local extension storage for restart persistence and may retain an unusable stale copy after local state reset.
|
|
65
|
-
- Keep the macOS Secure Enclave broker boundary type-exact: configured/provisioned broker paths and signing transcripts now require native strings, preventing coercible arrays or objects from acquiring trust-broker path or signature semantics.
|
|
66
|
-
- Redact browser pairing grants and managed-job recovery/control credentials by URL parameter name at the final logging boundary, including extension/runtime token parameters, while leaving harmless names such as `grant_type` intact.
|
|
67
|
-
- Keep browser pairing grant and launch clocks/ports type-exact and internally consistent: native safe integers are required, one wall-clock sample governs each bootstrap transition, and grant creation rejects timestamps that cannot produce the protocol's canonical 13-digit expiry.
|
|
68
|
-
- Tighten process-identity evidence to the current writer/probe image: snapshot PIDs must be safe integers, snapshot start times must already be numeric, and persisted owner timestamps must be canonical ISO strings rather than merely parseable dates.
|
|
69
|
-
- When browser history-state cleanup fails on the ephemeral pairing page, replace the current location with the token-free `/pair` URL before stopping; pairing still fails closed, but the short-lived grant no longer remains indefinitely in the visible fragment/history entry.
|
|
70
|
-
- Clear pairing bootstrap material from the content-script closure immediately after successful or ordinary failed pairing; retain it only for the explicit short-lived manual-repair branch that still needs the same grant.
|
|
71
|
-
- On POSIX, synchronize the security-audit parent directory after atomic state replacement before acknowledging a batch, so a pre-dispatch intent is not reported persisted solely because the temporary file contents reached storage before the rename metadata.
|
|
72
|
-
- Require the signed DPoP `htm` claim to match the normalized expected HTTP method exactly instead of uppercasing the proof claim, aligning the verifier with RFC 9449-style exact method binding and mature OAuth implementations.
|
|
73
|
-
- Clarify incident diagnostics so recent audit `pending/unknown` effect-settlement counts are not mistaken for a live termination queue; current process termination remains a separate runtime snapshot.
|
|
74
|
-
- Restore the local CLI browser-pairing launcher helper after compatibility-copy cleanup removed its imports while leaving the default dependency reference in place; CLI startup and `--version` no longer fail before argument dispatch.
|
|
75
|
-
- Update the page-automation VM regression harness for browser-global Web Crypto and automation API version 6, keeping the production document epoch on `crypto.randomUUID()` instead of weakening it for Node test contexts.
|
|
76
|
-
- Remove stale version-2 lease and schema-1 migration rationale from current architecture, operations, and release guidance now that those compatibility readers and surfaces are no longer supported.
|
|
77
|
-
- Expand the privacy publication scan beyond Git-visible files to every literal `package.json#files` tree, closing a gap where Git-ignored files such as `src/local/*.local` were still included by `npm pack` but escaped the privacy gate.
|
|
78
|
-
- Require canonical current account roles in every persisted OAuth authority record and remove the online bad-role repair branch; malformed or non-canonical role state now fails the current-schema boundary instead of being rewritten at runtime.
|
|
79
|
-
- Remove the unreachable local-admin external-launch helper and its process-spawn/browser-launch dependencies, leaving the current pairing launch path owned only by the browser pairing service.
|
|
80
|
-
- Reject prototype-shaped or otherwise malformed account IDs before indexing the persisted account table, and require runtime tool-handler dispatch to use own properties only.
|
|
81
|
-
- Extend the publication privacy gate across npm's implicit README/LICENSE/package/main/bin/man surfaces, closing a second gap where a Git-ignored root README could still be auto-included by `npm pack`.
|
|
82
|
-
- Document the residual same-user ancestor-directory race for ordinary workspace file mutations instead of overstating path canonicalization as an atomic cross-platform directory-handle boundary.
|
|
83
|
-
- Document that the owner-only autostart network snapshot can persist embedded proxy authentication and private certificate paths even though those values are excluded from status output and logs.
|
|
84
|
-
- Reject malformed hosted managed-job dependency IDs before capability verification instead of string-coercing array or other non-string values and deferring rejection to the daemon plan parser.
|
|
85
|
-
- Keep OAuth, admin, and daemon edge throttling bound to the caller network identity even when an attacker adds arbitrary Authorization headers; credential-scoped rate-limit buckets are now reserved for the MCP endpoint that actually authenticates with those credentials.
|
|
86
|
-
- Clarify the local-resource confidentiality boundary: browser/application mutation results do not echo injected resource content, while the destination receives it and later explicit value/source/screenshot observations may expose content the destination now holds.
|
|
87
|
-
- Keep security-audit evidence type-exact: malformed non-string target hashes, principal identifiers, roles, tools, outcomes, and risk categories now fall back to null/unknown evidence instead of being string-coerced into valid-looking audit records.
|
|
88
|
-
- Enforce exact string types for browser pairing grants, challenges, proofs, and credentials, and require an integer pairing port instead of accepting equivalent values through JavaScript coercion.
|
|
89
|
-
- Enforce exact string types for resource-request family and contention identities so malformed persisted/request metadata cannot cross the coordinator contract through JavaScript coercion.
|
|
90
|
-
- Require exact string resource names and resource-file paths in managed-job planning, keeping resource aliases and persisted plan evidence type-exact with the rest of the job schema.
|
|
91
|
-
- Keep MCP subscription and pending-read per-account capacity keys type-exact instead of normalizing non-string runtime values into account identities.
|
|
92
|
-
- Correct multi-account protocol documentation so removed initialization-era requests are described as rejected, not as a compatibility path.
|
|
93
|
-
- Validate relay account/client/family identity again at the in-flight call attribution boundary instead of coercing malformed principals into revocation metadata.
|
|
94
|
-
- Reject unknown in-flight principal kinds instead of misattributing them as local calls, preserving fail-closed revocation and interruption attribution.
|
|
95
|
-
- Persist at most three privacy-bounded managed-job recovery attribution records with fixed interruption reasons and exact timestamps, expose them with the strict recovery-attempt count, and reject coercible or malformed recovery metadata instead of using it to drive automatic relaunch.
|
|
96
|
-
- Require exact current Worker deployment identity types and formats for Worker names, OAuth token-version secrets, historical Worker names, and deployment fingerprints; arrays and other coercible values no longer become valid deployment identity through string conversion.
|
|
97
|
-
- Require runtime package entry, expected package identity, platform selector, and packaged manifest version to have their exact string types before service activation provenance is accepted; malformed manifest arrays can no longer stringify into a valid release version.
|
|
98
|
-
- Rename the fail-closed cached-schema helper from “compatibility” to “guidance” to make explicit that stale host schemas receive refresh instructions but never regain retired execution semantics.
|
|
99
|
-
- Remove the unused asynchronous `auditWarning` request-context mutation; audit persistence failures remain reported through the bounded security-audit failure reporter instead of writing dead state after a response may already have settled.
|
|
100
|
-
- Remove documentation and result-shape accommodation for older browser extensions: the current handshake already requires the exact packaged extension and `computer_observation_v1`, and missing tab-metadata verification evidence now projects as unverified rather than a legacy tri-state.
|
|
101
|
-
- Remove the unwritten legacy `operation-authorization.lock` scan/migration path and parse the current `security-audit.lock` with its actual owner-state contract, restoring live PID attribution in state inventory.
|
|
102
|
-
- Make the current OAuth store contract genuinely current-only: reject one-character legacy account names and clients missing the current DCR registration identity/revision instead of keeping them authorization-readable, and remove stale-registration status from the admin projection.
|
|
103
|
-
- Fail a managed-job step immediately when a still-live spawned child has no verifiable process-start identity; the runner terminates that child instead of allowing an active claim that crash recovery could only classify as ambiguous.
|
|
104
|
-
- Extend private Wrangler toolchain reuse verification to the executable install-script dependencies `esbuild` and `workerd`, and bump the audit marker schema so existing cached installs are revalidated under the stronger contract.
|
|
105
|
-
- Remove the obsolete browser setup note for migrating older local-candidate extension paths; current setup documents only the stable unpacked-extension path.
|
|
106
|
-
- Split managed-job recovery history accounting out of general state validation so recovery attribution has a dedicated bounded module instead of expanding the core status validator beyond its responsibility boundary.
|
|
107
|
-
- Reject multiply linked package files while computing the promotion digest so an alternate hard-link path cannot mutate candidate content behind the verified package path.
|
|
108
|
-
- Centralize Worker-name and OAuth token-version validation in one current identity contract instead of duplicating security-sensitive regular expressions across state, deployment fingerprinting, health checks, and state inventory.
|
|
109
|
-
- Retain temporary Worker-secret files when filename ownership PID/timestamp evidence exceeds safe-integer bounds instead of treating malformed process identity as reclaimable stale state; legacy secret cleanup remains only to remove credential residue safely.
|
|
110
|
-
- Validate tool arguments after tool/role authority gating but before relay operation risk/path authorization, so malformed remote inputs cannot trigger local path classification or other operation-level inspection before schema rejection.
|
|
111
|
-
- Require hardened-npm artifact descriptors and explicit proxy/NO_PROXY overrides to use native string/integer types, preventing coercible arrays or numeric strings from becoming supply-chain identity or network-routing configuration.
|
|
112
|
-
- Extend managed-job resource-output defense-in-depth redaction to exact Base64URL encodings, while documenting that arbitrary transformed or application-specific representations still require `capture_output: "discard"` when credentials may be echoed.
|
|
113
|
-
- Record a privacy-safe error class when a successfully delivered transient-process result cannot clear its stronger pending-recovery marker, preserving the user result while making temporary quota/retention over-protection diagnosable.
|
|
114
|
-
- Keep runtime shutdown on the ownership-checked process-tree supervisor: forced drain now uses zero-additional-grace supervised escalation, preserves already-pending ownership checks, and waits for retained descendant-escalation settlement instead of replacing it with an unverified direct group `SIGKILL`.
|
|
5
|
+
- Refresh cf, Wrangler, Babel parser, ESLint, globals, Node types, fast-check and ws with synchronized source/private locks and exact native install-script approvals.
|
|
6
|
+
- Remove the obsolete cf bundle rewrite and its standalone Undici dependency. Verify the unchanged upstream cf artifact and exercise connector/TLS-option preservation offline before private CLI execution.
|
|
7
|
+
- Share one locked toolchain verification lifecycle for cf and Wrangler; deduplicate Miniflare and ws across deployment tooling without expanding the consumer runtime's three direct dependencies.
|
|
8
|
+
- Adapt architecture parsing to Babel 8's TypeScript import-type AST so type-only dependency edges remain checked.
|
|
9
|
+
- Reject coercible Worker deployment names before toolchain initialization; verify Durable Object and rate-limit binding types and exact rate-limit parameters before deployment callbacks.
|
|
10
|
+
- Bound Build Output module count and aggregate bytes, and require every module path to stay within its bundle.
|
|
11
|
+
- Preserve build/callback failures alongside private-project cleanup failures, including cleanup after staging permission errors.
|
|
12
|
+
- Enforce dependency-node admission before reading values and avoid reflecting unverified package version text in integrity errors.
|
|
13
|
+
- Group npm update proposals and monitor the private toolchain manifest, while retaining version, acceptance, audit, signature and release gates.
|
|
14
|
+
- Correct the optional verifier configuration: preserve offline sandboxed regressions and run complete native suites with their required loopback, installation, browser and platform access.
|
|
15
|
+
- Bind full-verification receipts to deployment configurations, verifier manifests and the Worker type seed; reject stale receipts after content or mode changes.
|
|
16
|
+
- Retire the cf compatibility exception and stale transformation documentation; add causal boundary, privacy, budget and cleanup regressions.
|
|
115
17
|
|
|
116
18
|
## Historical releases
|
|
117
19
|
|
package/README.md
CHANGED
|
@@ -103,6 +103,8 @@ machine-mcp doctor
|
|
|
103
103
|
|
|
104
104
|
`Unknown cli config "--allow-scripts"` means the package installation ran under npm 11 or older. `Invalid property "node"` or `Invalid property "devEngines.node"` means an older npm parser inspected incompatible nearby project metadata. Repeat the empty-directory procedure and reopen the terminal if `npm --version` still resolves to an older executable.
|
|
105
105
|
|
|
106
|
+
The consumer runtime has three direct dependencies. Deployment tooling is installed and audited separately; its upstream cf bundle is verified without rewriting third-party code.
|
|
107
|
+
|
|
106
108
|
For a source checkout:
|
|
107
109
|
|
|
108
110
|
```sh
|
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
"action": {
|
|
30
30
|
"default_title": "Machine Bridge Browser"
|
|
31
31
|
},
|
|
32
|
-
"version_name": "3.0.0-beta.
|
|
32
|
+
"version_name": "3.0.0-beta.200",
|
|
33
33
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxryYkpZhq8+VAQLHcGS9BAHQcyKX8RHGIpIwvtIVRU/rcOcE0bNdnM0aZJ/h6xWQsGDHlhvjT2+1aJaAn/9k8473BRWajzVXld961CdHYVFVHoce2hHiSJ0xydWrHMMZhAm0mN0UzjEpgZ0tMw209efcZHIvSwuxhteZMRy4kyiVjwFlOf5oXFCxRuCJnPj3AK9CmCf4XgEBuPIJ0TZmjGHOOdBvJmbCNnAWXYEo5/mf7MfCGhV4IJ1hNuhpoNQfOFKMUcw9/v/IpT62XpfXdGYTfGYCmCjC+gntK1spbkr2P4/2+sYMQtLpse71mpSNGXfcf3abU55Vpn+gncSxRQIDAQAB"
|
|
34
34
|
}
|
package/docs/AUDIT.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Current audit status
|
|
2
2
|
|
|
3
|
-
The source dependency override and private hardened npm bootstrap pin brace-expansion 5.0.12 with the registry SHA-512 artifact integrity, addressing GHSA-q2hr-2g5m-vwhr, GHSA-qhr7-859c-m2p7, and GHSA-6j4f-fj2g-mc7p. Consumer packages have no postinstall hook
|
|
3
|
+
The source dependency override and private hardened npm bootstrap pin brace-expansion 5.0.12 with the registry SHA-512 artifact integrity, addressing GHSA-q2hr-2g5m-vwhr, GHSA-qhr7-859c-m2p7, and GHSA-6j4f-fj2g-mc7p. Consumer packages have no postinstall hook. The original upstream cf bundle must pass its pinned integrity check before private CLI execution. Real private builds declare the exact audited Wrangler provider and receive the executable runner.
|
|
4
4
|
|
|
5
5
|
Source and private Cloudflare toolchain pin Sharp 0.35.5 (GHSA-wq5f-xc86-pv6w). Integrity checks reject older installs; consumer trees require 0.35.5 or newer. Audit each lock separately.
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ This review is scoped to source contracts, risk-bearing control paths, isolated
|
|
|
24
24
|
- **Logging and diagnostics are privacy-minimized by contract.** Runtime logs are structured and must not contain tool arguments, command output, credentials, account identity, arbitrary URLs, private paths, or other user content. Explicit local CLI/tool results are a separate user-requested output surface. Security-audit telemetry is content-free, bounded, and hash-chained; diagnostics expose coarse provenance/health rather than secrets or private values.
|
|
25
25
|
- **Effect-settlement evidence is time-scoped.** Audit events retain the settlement state observed when a tool response was recorded. Recent `unknown_effect_settlements_last_15m` and `pending_effect_settlements_last_15m` are historical event counts, not a live queue. Current local process termination is reported separately by `runtime.processes.terminating_processes` and `termination_escalations_pending`; a later process exit does not rewrite the append-only audit event.
|
|
26
26
|
- **Resource admission is cooperative scheduling, not a hostile-code sandbox.** CPU, memory, I/O, disk-reserve, queue, and result budgets protect service continuity, but ordinary execution still has the daemon OS user's ambient authority unless a dedicated low-privilege account or VM/container supplies the stronger boundary.
|
|
27
|
-
- **Deployment audits cover bundled code as well as the dependency graph.** The consumer runtime excludes cf, Wrangler, and Miniflare. Deployment uses an exact private toolchain whose registry signatures, dependency audit, and artifact bytes are checked before execution.
|
|
27
|
+
- **Deployment audits cover bundled code as well as the dependency graph.** The consumer runtime excludes cf, Wrangler, and Miniflare. Deployment uses an exact private toolchain whose registry signatures, dependency audit, and artifact bytes are checked before execution. A zero-vulnerability dependency audit is insufficient for bundled code: the unchanged upstream cf bundle is hash-bound and its custom connector and TLS-verification preservation are exercised offline. No third-party bundle rewriting or standalone network-library substitution remains. Unknown artifact bytes fail closed. Structured cf authentication must be positive before unattended activation can mutate the Worker or service; source snapshots, generated manifests, Worker identity, SQLite export, preserved secrets, and typed rate-limit bindings with exact parameters are validated before upload. Module paths, counts and aggregate bytes are bounded; staging cleanup preserves the primary failure. These local controls still require candidate-bound deployed-edge acceptance.
|
|
28
28
|
- **Release and package evidence remain separate from audit prose.** Shipped-source or packed-document changes require synchronized package identity and fresh verification. Candidate acceptance, publication, activation, and stable promotion must be proven by their dedicated records and external systems; no sentence in this audit summary inherits or confers release authority.
|
|
29
29
|
|
|
30
30
|
## Relay quota incident evidence boundary
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "machine-bridge-mcp",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.200",
|
|
4
4
|
"description": "Cross-client MCP bridge for local agent context, structured browser and application automation, files, Git, processes, resources, and durable jobs over stdio or OAuth relay.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -265,23 +265,22 @@
|
|
|
265
265
|
"browser-cli-pairing:test": "node tests/browser-cli-pairing-test.mjs",
|
|
266
266
|
"resource-admission:test": "node tests/resource-admission-test.mjs",
|
|
267
267
|
"resource-build-root:test": "node tests/resource-build-root-test.mjs",
|
|
268
|
-
"cf-network:test": "node tests/cf-network-
|
|
268
|
+
"cf-network:test": "node tests/cf-network-integrity-test.mjs"
|
|
269
269
|
},
|
|
270
270
|
"dependencies": {
|
|
271
271
|
"https-proxy-agent": "9.1.0",
|
|
272
272
|
"proxy-from-env": "2.1.0",
|
|
273
|
-
"ws": "8.
|
|
273
|
+
"ws": "8.22.0"
|
|
274
274
|
},
|
|
275
275
|
"devDependencies": {
|
|
276
|
-
"@babel/parser": "
|
|
277
|
-
"@types/node": "26.4
|
|
278
|
-
"cf": "1.0.0-beta.
|
|
279
|
-
"eslint": "10.
|
|
280
|
-
"fast-check": "4.10.
|
|
281
|
-
"globals": "17.
|
|
276
|
+
"@babel/parser": "8.0.7",
|
|
277
|
+
"@types/node": "26.6.4",
|
|
278
|
+
"cf": "1.0.0-beta.13",
|
|
279
|
+
"eslint": "10.12.0",
|
|
280
|
+
"fast-check": "4.10.2",
|
|
281
|
+
"globals": "17.13.0",
|
|
282
282
|
"typescript": "7.0.2",
|
|
283
|
-
"
|
|
284
|
-
"wrangler": "4.144.0"
|
|
283
|
+
"wrangler": "4.149.0"
|
|
285
284
|
},
|
|
286
285
|
"keywords": [
|
|
287
286
|
"mcp",
|
|
@@ -310,10 +309,10 @@
|
|
|
310
309
|
},
|
|
311
310
|
"homepage": "https://github.com/YuLeiFuYun/machine-bridge-mcp#readme",
|
|
312
311
|
"allowScripts": {
|
|
313
|
-
"esbuild@0.28.
|
|
312
|
+
"esbuild@0.28.2": true,
|
|
314
313
|
"fsevents": false,
|
|
315
314
|
"sharp@0.35.5": true,
|
|
316
|
-
"workerd@1.
|
|
315
|
+
"workerd@1.20261006.1": true
|
|
317
316
|
},
|
|
318
317
|
"packageManager": "npm@12.0.2",
|
|
319
318
|
"devEngines": {
|
|
@@ -331,6 +330,7 @@
|
|
|
331
330
|
"overrides": {
|
|
332
331
|
"sharp": "0.35.5",
|
|
333
332
|
"brace-expansion": "5.0.12",
|
|
334
|
-
"
|
|
333
|
+
"miniflare": "5.20261006.1-alpha",
|
|
334
|
+
"ws": "$ws"
|
|
335
335
|
}
|
|
336
336
|
}
|
|
@@ -9,9 +9,10 @@ const RECEIPT_MAX_BYTES = 16 * 1024;
|
|
|
9
9
|
export const FULL_VERIFICATION_RECEIPT_MAX_AGE_MS = 6 * 60 * 60 * 1000;
|
|
10
10
|
|
|
11
11
|
const VERIFICATION_RUN_GENERATION_OPTIONS = {
|
|
12
|
-
roots: ["src", "scripts", "tests", "browser-extension", ".github", "docs", "bin", "native", "release-acceptance", ".release-candidate"],
|
|
12
|
+
roots: ["src", "scripts", "tests", "browser-extension", ".github", "docs", "bin", "native", "toolchain", "release-acceptance", ".release-candidate"],
|
|
13
13
|
files: [
|
|
14
14
|
"package.json", "package-lock.json", "tsconfig.json", "tsconfig.local.json", "wrangler.jsonc", "eslint.config.mjs",
|
|
15
|
+
"cloudflare.config.ts", "wrangler.config.ts", "workflow-bundle.json", ".machine-bridge/agent.json",
|
|
15
16
|
".npmrc", ".node-version", ".nvmrc", ".gitattributes", ".gitignore", ".privacy-denylist", ".privacy-denylist.example",
|
|
16
17
|
"mbm", "mbm.cmd", "README.md", "CHANGELOG.md", "CONTRIBUTING.md", "SECURITY.md", "LICENSE",
|
|
17
18
|
"CODE_OF_CONDUCT.md", "GOVERNANCE.md", "SUPPORT.md", "AGENTS.md",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readBoundedRegularFileSync } from "./secure-file.mjs";
|
|
5
|
+
import { privateToolchainIntegrityError, throwOperationalOrIntegrity } from "./private-toolchain-integrity.mjs";
|
|
6
|
+
|
|
7
|
+
export const CF_NETWORK_ARTIFACT = Object.freeze({
|
|
8
|
+
version: "1.0.0-beta.13",
|
|
9
|
+
bundledUndici: "7.30.0",
|
|
10
|
+
bundle: "dist/dist-BHEmAAHr.mjs",
|
|
11
|
+
sha256: "44d51802036f7c7d936c2f467386c435e8487fd4cef61b2ace3c5ad53efbed57",
|
|
12
|
+
});
|
|
13
|
+
const MAX_BUNDLE_BYTES = 2 * 1024 * 1024;
|
|
14
|
+
|
|
15
|
+
export function verifyCfNetworkArtifact(root, { allowAbsent = false } = {}) {
|
|
16
|
+
if (typeof root !== "string" || !root) throw new TypeError("cf toolchain root must be a path string");
|
|
17
|
+
const canonicalRoot = realpathSync(path.resolve(root));
|
|
18
|
+
const cfRoot = path.join(canonicalRoot, "node_modules", "cf");
|
|
19
|
+
let cfInfo;
|
|
20
|
+
try { cfInfo = lstatSync(cfRoot); }
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (allowAbsent && error?.code === "ENOENT") return { present: false };
|
|
23
|
+
throwOperationalOrIntegrity(error, "cf package is missing or structurally invalid");
|
|
24
|
+
}
|
|
25
|
+
if (cfInfo.isSymbolicLink() || !cfInfo.isDirectory()) throw privateToolchainIntegrityError("cf package must be a real directory");
|
|
26
|
+
const manifestPath = path.join(cfRoot, "package.json");
|
|
27
|
+
requireContainedRegularFile(canonicalRoot, manifestPath);
|
|
28
|
+
let manifest;
|
|
29
|
+
try {
|
|
30
|
+
manifest = JSON.parse(readBoundedRegularFileSync(manifestPath, 16 * 1024, "cf package manifest", {
|
|
31
|
+
verifyPathIdentity: true, rejectMultipleLinks: true,
|
|
32
|
+
}).toString("utf8"));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (error instanceof SyntaxError) throw privateToolchainIntegrityError("cf package manifest is not valid JSON");
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
if (manifest?.name !== "cf" || manifest.version !== CF_NETWORK_ARTIFACT.version) {
|
|
38
|
+
throw privateToolchainIntegrityError("cf package version does not match the reviewed upstream artifact");
|
|
39
|
+
}
|
|
40
|
+
const file = path.join(cfRoot, CF_NETWORK_ARTIFACT.bundle);
|
|
41
|
+
requireContainedRegularFile(canonicalRoot, file);
|
|
42
|
+
const bytes = readBoundedRegularFileSync(file, MAX_BUNDLE_BYTES, "cf network bundle", {
|
|
43
|
+
verifyPathIdentity: true, rejectMultipleLinks: true,
|
|
44
|
+
});
|
|
45
|
+
if (createHash("sha256").update(bytes).digest("hex") !== CF_NETWORK_ARTIFACT.sha256) {
|
|
46
|
+
throw privateToolchainIntegrityError("cf network bundle does not match the pinned upstream artifact");
|
|
47
|
+
}
|
|
48
|
+
return { present: true, version: manifest.version, bundleSha256: CF_NETWORK_ARTIFACT.sha256 };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function requireContainedRegularFile(root, file) {
|
|
52
|
+
const relative = path.relative(root, file);
|
|
53
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
54
|
+
throw privateToolchainIntegrityError("cf artifact must remain inside its private toolchain");
|
|
55
|
+
}
|
|
56
|
+
let current = root;
|
|
57
|
+
for (const part of relative.split(path.sep)) {
|
|
58
|
+
current = path.join(current, part);
|
|
59
|
+
let info;
|
|
60
|
+
try { info = lstatSync(current); }
|
|
61
|
+
catch (error) { throwOperationalOrIntegrity(error, "cf artifact is missing or structurally invalid"); }
|
|
62
|
+
if (info.isSymbolicLink() || (current !== file && !info.isDirectory())
|
|
63
|
+
|| (current === file && (!info.isFile() || Number(info.nlink) !== 1
|
|
64
|
+
|| (process.platform !== "win32" && (Number(info.mode) & 0o022) !== 0)))) {
|
|
65
|
+
throw privateToolchainIntegrityError("cf artifact must be a contained private regular file without aliases");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
package/src/local/cf-project.mjs
CHANGED
|
@@ -6,9 +6,11 @@ import { packageRoot } from "./package-identity.mjs";
|
|
|
6
6
|
import { readBoundedRegularFileSync } from "./secure-file.mjs";
|
|
7
7
|
|
|
8
8
|
const PRESERVED_BINDING_TYPES = ["plain_text", "json", "secret_text", "secret_key"];
|
|
9
|
+
const MAX_OUTPUT_MODULES = 256, MAX_MODULE_BYTES = 16 * 1024 * 1024, MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
|
|
9
10
|
|
|
10
11
|
export async function withCfProject(snapshot, workerName, callback, options = {}) {
|
|
11
|
-
if (!/^[a-z0-9][a-z0-9-]{0,62}$/.test(workerName)) throw new Error("Invalid Worker deployment name");
|
|
12
|
+
if (typeof workerName !== "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(workerName)) throw new Error("Invalid Worker deployment name");
|
|
13
|
+
if (typeof callback !== "function") throw new TypeError("cf project requires a callback");
|
|
12
14
|
const toolchainRoot = await (options.ensureToolchain || ensureCloudflareToolchain)({
|
|
13
15
|
stateRoot: options.stateRoot, packageRoot: options.packageRoot || packageRoot,
|
|
14
16
|
env: options.env || process.env, runCommand: options.runCommand || runExecutable,
|
|
@@ -17,8 +19,9 @@ export async function withCfProject(snapshot, workerName, callback, options = {}
|
|
|
17
19
|
128 * 1024, "Cloudflare toolchain manifest", { verifyPathIdentity: true, rejectMultipleLinks: true }));
|
|
18
20
|
const builderVersion = toolchainManifest.dependencies.wrangler;
|
|
19
21
|
const directory = mkdtempSync(path.join(toolchainRoot, "cf-project-"));
|
|
20
|
-
|
|
22
|
+
let result, primaryError, failed = false;
|
|
21
23
|
try {
|
|
24
|
+
chmodSync(directory, 0o700);
|
|
22
25
|
for (const file of snapshot.files) {
|
|
23
26
|
const target = path.resolve(directory, file.path);
|
|
24
27
|
const relative = path.relative(directory, target);
|
|
@@ -38,32 +41,56 @@ export async function withCfProject(snapshot, workerName, callback, options = {}
|
|
|
38
41
|
await runCf(["build"], { ...project, stateRoot: options.stateRoot, packageRoot: options.packageRoot || packageRoot,
|
|
39
42
|
capture: true, hardTimeout: true, timeoutMs: options.buildTimeoutMs ?? 120_000 });
|
|
40
43
|
validateCfBuildOutput(directory, workerName);
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
+
result = await callback(project);
|
|
45
|
+
} catch (error) { primaryError = error; failed = true; }
|
|
46
|
+
try { rmSync(directory, { recursive: true, force: true, maxRetries: 6, retryDelay: 30 }); }
|
|
47
|
+
catch (cleanupError) {
|
|
48
|
+
if (failed) throw new AggregateError([primaryError, cleanupError], "cf project operation failed and private cleanup was incomplete");
|
|
49
|
+
throw cleanupError;
|
|
44
50
|
}
|
|
51
|
+
if (failed) throw primaryError;
|
|
52
|
+
return result;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
export function validateCfBuildOutput(directory, workerName) {
|
|
48
56
|
const configPath = ".cloudflare/output/v0/workers/default/worker.config.json";
|
|
49
57
|
const config = JSON.parse(readProjectArtifact(directory, configPath, 128 * 1024));
|
|
50
|
-
const kept = config
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|| config.
|
|
54
|
-
|| config.env
|
|
55
|
-
|| config.env.
|
|
58
|
+
const kept = config?.unsafe?.metadata?.keep_bindings;
|
|
59
|
+
const modules = config?.manifest?.modules;
|
|
60
|
+
if (typeof workerName !== "string" || config?.name !== workerName
|
|
61
|
+
|| config.exports?.BridgeRoom?.storage !== "sqlite" || config.exports.BridgeRoom.type !== "durable-object"
|
|
62
|
+
|| config.env?.BRIDGE?.type !== "durable-object" || config.env.BRIDGE.worker !== workerName
|
|
63
|
+
|| config.env.BRIDGE.exportName !== "BridgeRoom"
|
|
64
|
+
|| !rateLimitMatches(config.env.STATEFUL_GLOBAL_RATE_LIMITER, "4301702", 1200)
|
|
65
|
+
|| !rateLimitMatches(config.env.STATEFUL_RATE_LIMITER, "4301701", 120)
|
|
56
66
|
|| !Array.isArray(kept) || kept.length !== PRESERVED_BINDING_TYPES.length
|
|
57
67
|
|| PRESERVED_BINDING_TYPES.some(type => !kept.includes(type))
|
|
58
68
|
|| config.manifest?.type !== "complete" || config.manifest.mainModule !== "index.js"
|
|
59
|
-
||
|
|
69
|
+
|| !modules || typeof modules !== "object" || Array.isArray(modules) || modules["index.js"]?.type !== "esm") {
|
|
60
70
|
throw new Error("cf Build Output does not preserve the Machine Bridge deployment contract");
|
|
61
71
|
}
|
|
72
|
+
let count = 0;
|
|
73
|
+
for (const module in modules) {
|
|
74
|
+
if (!Object.hasOwn(modules, module)) continue;
|
|
75
|
+
if (++count > MAX_OUTPUT_MODULES) throw new Error("cf Build Output exceeds its module limit");
|
|
76
|
+
if (module.includes("\\") || module.split("/").some(part => !part || part === "." || part === "..")) {
|
|
77
|
+
throw new Error("cf Build Output module escapes its bundle");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
62
80
|
const prefix = ".cloudflare/output/v0/workers/default/bundle/";
|
|
63
|
-
|
|
81
|
+
let remaining = MAX_OUTPUT_BYTES;
|
|
82
|
+
for (const module in modules) {
|
|
83
|
+
if (!Object.hasOwn(modules, module)) continue;
|
|
84
|
+
const bytes = readProjectArtifact(directory, prefix + module, Math.min(MAX_MODULE_BYTES, remaining));
|
|
85
|
+
remaining -= bytes.length;
|
|
86
|
+
}
|
|
64
87
|
return config;
|
|
65
88
|
}
|
|
66
89
|
|
|
90
|
+
function rateLimitMatches(binding, namespace, limit) {
|
|
91
|
+
return binding?.type === "rate-limit" && binding.namespace === namespace
|
|
92
|
+
&& binding.simple?.limit === limit && binding.simple.period === 60;
|
|
93
|
+
}
|
|
67
94
|
function readProjectArtifact(directory, relativePath, limit) {
|
|
68
95
|
const root = realpathSync(directory);
|
|
69
96
|
const target = path.resolve(root, relativePath);
|