feat(windows): add brokered AppContainer sandbox support - #2961
Conversation
There was a problem hiding this comment.
Pull request overview
This PR establishes an initial “W0 evidence” slice for the proposed Windows sandbox work: it documents the Phase 4 design baseline (RFC v1), adds an experiments-based closed v1 launcher request contract plus an untrusted probe, and introduces a non-blocking Windows 2025 CI lane to run the evidence tooling.
Changes:
- Update runtime sandbox documentation to point Windows enforcement tracking to #2142 and the new Windows sandbox RFC.
- Add
experiments/windows-sandboxprotocol + probe tooling (Node tests) and a Windows-only Rust launcher prototype. - Add a non-blocking
windows-2025GitHub Actions workflow to run the protocol/probe evidence steps when the experiments change.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/runtime/src/sandbox/README.md | Updates sandbox docs to reference Windows sandbox RFC and current Linux backend behavior/tests. |
| experiments/windows-sandbox/README.md | Documents the W0 spike purpose, how to run the checks, and current candidate behavior. |
| experiments/windows-sandbox/protocol.test.mjs | Adds Node tests for the closed v1 launcher request contract parser. |
| experiments/windows-sandbox/protocol.mjs | Implements the v1 launcher request parser with unknown-key rejection and path/env validation. |
| experiments/windows-sandbox/probe.test.mjs | Adds Node tests for the probe’s pass/fail behavior and JSON reporting. |
| experiments/windows-sandbox/probe.mjs | Implements the untrusted probe (fs, network connect, env, descendant launch) and report output. |
| experiments/windows-sandbox/launcher/src/windows_launcher.rs | Adds a Windows launcher prototype using restricted tokens + Job Object + bounded wait. |
| experiments/windows-sandbox/launcher/src/protocol.rs | Defines/deserializes the Rust-side request shape and performs request validation. |
| experiments/windows-sandbox/launcher/src/main.rs | Adds the Windows-only launcher entrypoint and request loading/dispatch. |
| experiments/windows-sandbox/launcher/Cargo.toml | Introduces the Rust launcher crate and dependencies (serde, windows-sys). |
| experiments/windows-sandbox/launcher/Cargo.lock | Locks Rust dependencies for reproducible CI builds. |
| experiments/windows-sandbox/launcher/.gitignore | Ignores Cargo build output. |
| experiments/windows-sandbox/launcher-smoke.ps1 | Adds a CI smoke script that runs the launcher and validates restricted-token + Job membership. |
| docs/architecture/windows-sandbox-rfc-v1.zh-CN.md | Adds the Chinese RFC v1 describing the proposed Windows sandbox architecture and evidence gates. |
| docs/architecture/windows-sandbox-rfc-v1.md | Adds the English RFC v1 describing the proposed Windows sandbox architecture and evidence gates. |
| .github/workflows/windows-sandbox-w0.yml | Adds a non-blocking Windows 2025 workflow to run protocol tests, build the launcher, and run the smoke probe. |
Suppressed comments (1)
experiments/windows-sandbox/probe.test.mjs:34
spawnSyncenv values are stringified; settingMAKA_W0_TEST_SECRET: undefinedcan result in the child seeing the variable as present (e.g. value "undefined"), making the environment-absence assertion flaky/incorrect. Build an env object and delete the key instead of assigningundefined.
cwd: process.cwd(),
encoding: 'utf8',
env: { ...process.env, MAKA_W0_TEST_SECRET: undefined },
},
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
6f44c32 to
e4c1c10
Compare
74b6529 to
f58a15f
Compare
f58a15f to
1cabbaa
Compare
|
@Astro-Han Thank you — accepting all four preview-scope points as merge gates for #2961. Each is now addressed on head
Verification on the final head: cargo tests including the new admission/lock coverage (multi-link file root, in-tree out-of-tree alias, machine-wide lock naming), the local smoke suite including 10-way concurrent ACL recovery under the machine-wide locks, the Windows workspace suites, a live brokered-Electron AppContainer run of write/read/glob/grep-fail-closed/denied-write, and CI is green across all 16 checks — including Agreed on the process gate: independent human security review remains required before merge, and this CI evidence does not substitute for it. 中文版四个 preview 范围内的问题全部按你建议的窄范围 fail-closed 方案在 head
最终 head 上 16 项 CI 全绿(含跑真打包 worker E2E 的 |
Astro-Han
left a comment
There was a problem hiding this comment.
Approved for the narrowed packaged Windows filesystem-worker preview. The current head runs the packaged broker, Electron executable, and worker end to end, and the earlier runtime-root, per-launch identity, ledger-mode, hard-link, cross-session lock, Grep-contract, and packaging findings are closed.
The two inline P2 notes are deliberately narrow: close the already-agreed exact-write and Job-settlement invariants without expanding this PR into a generalized Windows architecture rewrite. Please rerun the packaged Electron E2E on the final head. Independent human security review remains required before merge under the repository policy; this approval and green CI do not replace that gate.
AI-assisted review: Codex inspected the current PR head, full diff, CI and merge state, prior review ledger, author replies, native ACL/Job lifecycle, Runtime/Core contracts, and packaged evidence, with independent adversarial reviewer passes. The human contributor remains responsible for validating these findings and for the final review and merge decision.
中文版
整体批准当前收窄后的 Windows filesystem-worker preview。两条 inline P2 仅要求用最小方案关闭此前已经接受的 exact-write 与 Job-settlement 不变量,不要求扩展为通用 Windows 架构重构。最终 head 请重跑 packaged Electron E2E;合并前仍需仓库政策要求的独立人工安全审查。
…unproven settle_job collapsed every failure into one error string, so ACL and ledger cleanup ran identically whether the Job was proven empty or termination, waiting and Job accounting themselves failed. In the latter case processes may still hold the launch identity, and normal cleanup would erase the only recovery record while the boundary was still live. Launch failures now carry a settled/unsettled outcome. Only a proven-empty Job (directly, or after a successful terminate-and-drain) enters normal cleanup. An unsettled launch keeps its grants in place, quarantines its ledger as a preserved recovery record, and leaves the AppContainer profile undeleted; the kill-on-close Job handle remains the kernel backstop either way. Recovery never interprets quarantined ledgers and every launch uses a fresh identity, so no later child can inherit the preserved authority. Failure-injection tests cover both outcomes: an unsettled launch preserves grants and quarantines the ledger; a settled failure still releases grants and ledger normally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… shapes closed A write whose target does not exist yet — and directory-entry mutations such as ApplyPatch create/delete — reached the Windows compiler as a runtime-writable parent root, which the launcher could only represent as recursive Modify on the existing parent tree: a kernel boundary broader than the approved exact operation. The worker itself still wrote only the requested target, which is why the packaged E2E kept passing. The compiler now refuses these shapes instead of widening them: the preview fails closed before any process launches, per the agreed W0/W1 parent-entry gate. Precise parent-entry authority remains follow-up work. The packaged E2E and the Windows smoke update a pre-seeded exact file and assert that a missing-target write fails closed without producing a file; verify-windows-sandbox-e2e.mjs joins the release-windows-check path filter so E2E semantic changes rerun the packaged evidence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@Astro-Han Both inline P2 gates are closed on the final head
CI on the final head: 15/16 green including The independent human security review gate remains acknowledged as required by repository policy. 中文版两条 inline P2 已在最终 head
最终 head CI 15/16 绿(含 13 分钟的打包验证)。唯一红项 |
The readiness probe launched its throwaway child as `"<cmd>" /c exit 0` without `/d`, so cmd.exe ran the machine-wide `Software\Microsoft\Command Processor\AutoRun` value before the payload. Because AutoRun is machine-constant, a host that ships an AutoRun which exits non-zero would make *every* probe report failure, and one that ships a blocking AutoRun would hang the child until the Job drain times out -- either way the Windows sandbox fails closed on that machine on every startup, independent of whether the OS can actually stand up the boundary. The probe would then be measuring the host's shell customization instead of the sandbox. Route the command line through a pure `readiness_probe_command_line` helper that emits `"<cmd>" /d /c exit 0`, matching the `/d` the production launch path already passes, and add a unit test asserting `/d` precedes `/c`. Also correct the RFC (EN + zh): the readiness probe and its serialized profile lifecycle are added by this PR (apache#3161), not the merged apache#2961 preview slice -- tag those two bullets accordingly and note the AutoRun-disabled command line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5
…3174) * feat(windows-sandbox): implement production-identity readiness probe The Windows AppContainer backend advertised availability from file existence alone (`existsSync(clientPath)`), which never proves the host can actually stand up the sandbox identity. Replace that with a real readiness probe (RFC §6.4) and align the RFC to the shipped behavior. - launcher: add `--readiness-probe`, which creates the real AppContainer identity/token and a kill-on-close Job and launches a throwaway confined child, failing closed if the host cannot create or enforce the boundary. - runtime: back the Windows backend's `isAvailable` with a memoized spawnSync of `--readiness-probe`, so `auto`/`require` fail closed on hosts where the OS cannot create the boundary rather than trusting the packaged binary's presence. - CI: add readiness-probe-smoke.ps1 to the W0 lane (exit 0, repeatable, argument-rejecting). - docs: align RFC §6.4/§6.5 (EN + zh-CN) — mark the readiness probe as implemented and enforced, and keep private desktop, full per-profile policy at readiness, and launcher signature/version as later gates. Advances #2142 Phase 4 (align the RFC's guarantees with the shipped slice). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): harden readiness probe against PID reuse and identity spoofing Address adversarial review on the production-identity readiness probe: - Make the throwaway AppContainer profile name unique per invocation with a monotonic nonce (SystemTime nanos + PID) so a recycled PID can never collide with a still-registered profile and deadlock the probe (finding A). - Prove enforcement, not mere presence: verify the confined child runs under the SPECIFIC requested Job (IsProcessInJob against our handle) and carries the EXACT requested AppContainer SID (TokenAppContainerSid + EqualSid), failing closed otherwise. "some job / some AppContainer" is not evidence the boundary we asked for is real (finding B). - Cache Windows readiness at module scope keyed by client path so backends sharing a launcher share one probe result; distinct paths stay independent (finding D). - Sync RFC (EN + zh) Updated: date to 2026-08-17 (finding C). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): consolidate availability authority and settle readiness probe deterministically Address maintainer review on the readiness-probe PR: - Availability: make `isBuiltinFilesystemWorkerSandboxAvailable(win32)` consume the memoized readiness probe instead of treating launcher-file presence as a second authority. Runtime Host composition calls this at startup, warming the readiness cache so the backend's later synchronous `isAvailable()` on the transform hot path hits the cache rather than spawning on the event loop. Export `probeWindowsReadiness` with an injectable spawn seam and cover it with unit tests (clean/non-zero/spawn-error/external-timeout/memoized/missing). - Settlement: route the readiness child's post-resume outcomes (verification failure, timeout, clean exit) through explicit TerminateProcess plus the existing `terminate_and_drain_job` primitive, so a child found outside the Job is settled rather than relying on Job close as the only backstop. - Cleanup: give the readiness AppContainer profile one fixed, self-reconciling name that best-effort-deletes any leftover before create, so a profile leaked by an externally-killed probe is reclaimed by the next probe. Replaces the PID+nonce scheme. - Docs: mark the structured unavailable-reason / diagnostics surface as a deferred later gate in both RFC language variants (§6.4/§6.5). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): serialize and bound the readiness probe lifecycle Address four readiness-probe lifecycle blockers on the availability path: 1. Reserve the `readiness-probe` request_id in protocol and reject it in LaunchRequest::validate; derive the probe profile under a disjoint `maka.readiness.` namespace so no production launch can resolve to the profile the probe deletes and recreates. 2. Serialize the whole delete->create->probe->settle->drop window across processes with the DACL-hardened named mutex the ACL ledger uses (LedgerLock), scoped by SID under Global\Maka.WindowsSandbox.ReadinessProfile.v1, failing closed on timeout. 3. Preserve the AppContainer registration on drop when the Job could not be proven empty (keep_on_drop + preserve()), mirroring the production Unsettled contract, instead of deleting a possibly-live identity. 4. Cache negative Windows readiness for a bounded TTL (60s) rather than the process lifetime, and make the synchronous isAvailable hot path strictly cache-only (readCachedWindowsReadiness) so it never spawns on the event loop; positive results stay cached permanently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): scope readiness recovery and quarantine claims to what the code enforces hqhq1025's round-3 review is factually correct on both points; this converges the claims rather than building the heavier machinery, matching the preview's fail-closed scope. Blocker 1 (TTL recovery overclaim): the filesystem worker is published once when a composition is built, so a negative readiness result is not recovered within a running host — the 60s negative TTL only bounds how long a stale negative poisons the module cache so the *next* composition build re-probes. De-claim the RFC (EN+zh §6.4/§6.5) and default-sandbox-manager.ts comments from 're-probes on the next composition rather than disabling until restart' to honest new-composition/restart-scoped recovery, and mark an active running-host readiness retry with dynamic worker publication as a deferred gate. Add a test asserting the hot path never self-recovers a negative; only an explicit re-probe (a new composition build) can. Blocker 2 (ineffective preserve/keep_on_drop): create_readiness deletes the fixed identity unconditionally next cycle, so preserve() only deferred deletion by one probe and never durably quarantined. Remove preserve()/keep_on_drop and the unsettled out-param; the settlement-failure surfacing in the match stays, so an unsettled probe still fails closed (reports unavailable). Document that cleanup relies on the kill-on-close Job's tree termination and a zero-filesystem-root identity, and mark durable quarantine (or unique probe identities plus a reconciliation ledger) as a deferred gate (RFC §6.5). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): disable cmd AutoRun in the readiness probe The readiness probe launched its throwaway child as `"<cmd>" /c exit 0` without `/d`, so cmd.exe ran the machine-wide `Software\Microsoft\Command Processor\AutoRun` value before the payload. Because AutoRun is machine-constant, a host that ships an AutoRun which exits non-zero would make *every* probe report failure, and one that ships a blocking AutoRun would hang the child until the Job drain times out -- either way the Windows sandbox fails closed on that machine on every startup, independent of whether the OS can actually stand up the boundary. The probe would then be measuring the host's shell customization instead of the sandbox. Route the command line through a pure `readiness_probe_command_line` helper that emits `"<cmd>" /d /c exit 0`, matching the `/d` the production launch path already passes, and add a unit test asserting `/d` precedes `/c`. Also correct the RFC (EN + zh): the readiness probe and its serialized profile lifecycle are added by this PR (#3161), not the merged #2961 preview slice -- tag those two bullets accordingly and note the AutoRun-disabled command line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): reject a squatted pre-existing lock by owner The named-lock comment claimed a squatted Global\ name "fails closed at acquisition", but that only held for a squatter with a restrictive DACL: CreateMutexW ignores the supplied security descriptor when the name already exists, so a local user pre-creating the predictable mutex name with a *permissive* DACL would hand the launcher an attacker-owned arbitration object -- readiness and ACL-ledger operations would then block on a mutex the squatter can hold forever (availability DoS), while the code read as if the DACL had rejected them. Close the gap where it is checkable: when CreateMutexW reports ERROR_ALREADY_EXISTS (also the normal same-user contention path), read the existing object's owner via GetSecurityInfo before any wait and require it to be the current user or SYSTEM. Ownership is the one property a permissive squatter cannot forge -- re-owning an object to another SID requires SeTakeOwnership/SeRestore, which standard users do not hold. Any other owner fails closed with an explicit squatted-mutex error instead of blocking. The 10-way concurrency smoke (same-user contention) passes unchanged; the cross-user negative path cannot be exercised by an unprivileged CI runner and is enforced by the owner check itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): accept the token default-owner SID for pre-existing locks The squatted-lock owner check rejected locks owned by BUILTIN\Administrators (S-1-5-32-544), which broke on elevated hosts: an elevated administrator token stamps the Administrators group -- not the user SID -- as the default owner on objects it creates, so a mutex this very code created earlier on the elevated CI runner failed the {user, SYSTEM} check and the W0 protocol lane went red (unsettled_launch_preserves_grants_and_quarantines_the_ledger). Accept the process token's default-owner SID (TokenOwner) as a third legitimate owner. This stays inside the threat model: only an elevated administrator can create objects owned by Administrators, and RFC S1/S5 explicitly does not defend against administrators. Standard-user squatters are still rejected -- they cannot forge either the user SID or the Administrators owner. Adds a unit test pinning the helper to {user SID, S-1-5-32-544} so both elevation states stay covered. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): pin an elevation-independent owner on named locks The owner check accepted {user SID, SYSTEM, this token's default owner}, but the default owner differs between elevation states: a mutex created by an *elevated* instance is owned by BUILTIN\Administrators, while a concurrent *non-elevated* instance of the same user resolves its own token owner to the user SID -- so it rejected the elevated instance's legitimate lock and readiness/ACL-ledger acquisition failed closed whenever elevated and unelevated Maka processes overlapped. Make the lock's identity elevation-independent at the source: the lock security descriptor now pins an explicit owner (O:<user SID> -- always an assignable owner for the user's own token, elevated or not) ahead of the protected DACL, so every lock this code creates carries the same owner in every elevation state. Validation of a pre-existing lock accepts exactly {user SID, SYSTEM, BUILTIN\Administrators} -- the last for locks created by builds that predate the pinning during side-by-side overlap, and safe because only an elevated administrator (outside the RFC S1/S5 threat model) can create Administrators-owned objects. The per-token default-owner query is deleted. Adds a lock_sddl unit test asserting the pinned owner precedes the protected DACL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * feat(windows-sandbox): place sandboxed children on a private desktop Non-interactive AppContainer workers previously inherited the creator's interactive Winsta0\Default desktop, exposing the same-session GUI attack surface (window-message shatter into the user's interactive windows, desktop hooks) — AppContainer confines files/network/token but not the desktop scope. Per RFC v1 §6.3 the private-desktop promise was designed but deferred. This change enforces initial-desktop *placement* plus DACL protection, not escape-proof confinement. Each AppContainer launch (production create + readiness probe) stands up a per-launch alternate desktop on the existing window station, with a protected DACL: a leading deny ACE strips DESKTOP_SWITCHDESKTOP / HOOKCONTROL / journal record+playback (0x138) from the launching-user SID — which the AppContainer child's token still carries as an effective SID, so without the deny the owner's full-control allow would name the child as a grantee of those rights (maintainer review, P2-1) — then allow ACEs grant the launching user and Local System control for cleanup and the child's AppContainer SID only the minimal DESKTOP_* rights (create window/menu, read/write objects, enumerate). STARTUPINFOEXW.lpDesktop points the child at it. If the desktop cannot be created or the DACL cannot be granted (CreateProcessW then fails ACCESS_DENIED), the launch fails closed — auto/require never fall back to the host desktop. Scope, stated honestly (per maintainer review on #3174): - lpDesktop selects only the child's *initial* desktop. This places the worker off the interactive Default desktop and DACL-protects the private one, but it does NOT structurally confine: absent a no-Win32k mitigation, a dedicated window station, or a token boundary, in-process code can still OpenDesktopW("Default") + SetThreadDesktop to re-attach. Enforcing a no-Win32k mitigation is a deferred gate (§6.5). - It does NOT isolate the clipboard: the clipboard belongs to the window station, which both desktops still share. Clipboard isolation with a dedicated window station is a later hardening gate (§6.5). - The create-window/write DACL rights are granted but not relied upon; the worker does no GUI work. A verified Low mandatory-integrity label proving those rights are usable at AppContainer's Low IL is deferred (§6.5). The boundary probe self-attests its own initial desktop name (desktopPrivatePlacement) and requires the launcher-owned maka-sandbox-desktop. prefix — not merely "not Default", so landing on any other pre-existing desktop also fails the placement check; appcontainer-smoke asserts the same prefix and rejects Default. Digest is unchanged: the desktop is a launch-time detail and does not enter the manifest. Stacked on #3161 (readiness probe). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): make the private desktop usable, bounded, and attested Follow-ups from inline review on #3174, each closing a spot where the desktop's documented properties exceeded (or under-stated) what the code enforced: - Pin a Low no-write-up mandatory label (S:(ML;;NW;;;LW)) on the private desktop. Without it the desktop inherited the creator's Medium integrity, and because MIC is evaluated before the DACL, the Low-IL AppContainer child's granted create-window/write rights were unusable in exactly the case the DACL claimed to grant them. The rights are now labeled-usable; an in-child window-creation check proving them end to end stays a deferred gate (RFC S6.5) - the worker still does no GUI work, so the shipped guarantee remains placement. - Bound the per-launch desktop heap: CreateDesktopExW with a 512 KiB budget instead of CreateDesktopW's default 3,072 KiB interactive allocation, so the supported ten-way concurrency costs ~5 MiB of the documented 48 MiB system desktop heap instead of ~30 MiB. A real-OS test holds ten confined desktops live simultaneously to prove the budget. - Fix an unaligned read: TokenAppContainerSid was read through a Vec<u8> buffer cast to TOKEN_APPCONTAINER_INFORMATION, whose leading pointer field requires pointer alignment - UB in Rust. The buffer is now sized in usize words (same pattern as current_user_sid_string). - Attest the readiness boundary instead of exiting 0: --readiness-probe now emits a machine-readable JSON of the facts it verified (exact-SID match, specific-Job membership, settlement drain, private-desktop placement), and readiness-probe-smoke.ps1 asserts those fields, so removing any verification would turn release evidence red rather than leaving a hollow exit-0 gate green. RFC (EN + zh) updated to match: label and heap bound recorded as enforced, the deferred gate narrowed to no-Win32k plus in-child window-creation coverage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 * fix(windows-sandbox): unforgeable desktop names and a narrowed normative claim Maintainer follow-up on the private-desktop delta, both points fixing a gap between what was stated and what the object model guarantees: - Desktop-name uniqueness is now fail-closed. CreateDesktopExW *opens* an existing desktop when the name collides -- silently ignoring the supplied DACL and heap budget -- and the old nonce was wall-clock nanoseconds with a unwrap_or(0) fallback, so PID reuse, clock rollback, same-tick calls, or a failed clock could reopen an older desktop while the prefix attestation still passed. The nonce is now 128 bits from the OS CSPRNG (BCryptGenRandom), collision is cryptographically negligible, and RNG failure fails the launch closed instead of collapsing to a constant name. The ten-desktop live test now also asserts ten *distinct* names that each pass the placement attestation, not merely ten returned handles. - The RFC's top-level S6.3 guarantee no longer states an unconditional "cannot": it now reads "workers start on a launcher-created private desktop, never Default", with the enumerate/message/hook resistance explicitly tied to the deferred no-Win32k/window-station gates (EN + zh). The PR title/description are narrowed the same way. Cleanups from the same review: json_string now delegates to serde_json (hand-rolled escaping and its test deleted), and the redundant '"desktop":"Default"' smoke rejections are removed -- the stronger launcher-prefix assertions already exclude Default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-by: Claude Fable 5 --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… worker The filesystem worker appended the pattern as a bare positional, so a pattern starting with '-' was parsed by ripgrep as flags. A leading flag exits 1, which maps to an empty match set - reporting strings that exist as absent, with no diagnostic. Adds the same '--' separator the host-local workspace executor already pins (apache#2961), plus a regression test asserting the separator and a successful dash-prefixed search. Fixes apache#3733
… worker The filesystem worker appended the pattern as a bare positional, so a pattern starting with '-' was parsed by ripgrep as flags. A leading flag exits 1, which maps to an empty match set - reporting strings that exist as absent, with no diagnostic. Adds the same '--' separator the host-local workspace executor already pins (apache#2961), plus a regression test asserting the separator and a successful dash-prefixed search. Fixes apache#3733
… worker The filesystem worker appended the pattern as a bare positional, so a pattern starting with '-' was parsed by ripgrep as flags. A leading flag exits 1, which maps to an empty match set - reporting strings that exist as absent, with no diagnostic. Adds the same '--' separator the host-local workspace executor already pins (apache#2961), plus a regression test asserting the separator and a successful dash-prefixed search. Fixes apache#3733
… worker The filesystem worker appended the pattern as a bare positional, so a pattern starting with '-' was parsed by ripgrep as flags. A leading flag exits 1, which maps to an empty match set - reporting strings that exist as absent, with no diagnostic. Adds the same '--' separator the host-local workspace executor already pins (apache#2961), plus a regression test asserting the separator and a successful dash-prefixed search. Fixes apache#3733
Summary
PermissionProfileroots, network policy, and environment into a closed launch manifestSecurity Evidence
The blocking Windows 2025 job verifies:
PROC_THREAD_ATTRIBUTE_JOB_LISTmembershipProduct Integration
The Windows release pipeline builds
maka-windows-sandbox.exewith locked Cargo dependencies, packages it underresources/windows-sandbox, and requires that resource during packaged-app verification. Runtime capability detection registers the backend only when that exact packaged resource exists. There is no environment-variable executable override and no unsandboxed retry.Scope Boundary
This PR provides a real native sandbox for the packaged Windows x64 managed-execution path and is ready for implementation review once all checks pass. It does not by itself declare the entire Windows platform fully supported. Authenticode signing, the complete adversarial matrix, cancellation/parent-death/concurrency release evidence, and independent security review remain tracked by #2142.
Verification
node --test experiments/windows-sandbox/*.test.mjscargo fmt --manifest-path experiments/windows-sandbox/launcher/Cargo.toml -- --checkcargo check --manifest-path experiments/windows-sandbox/launcher/Cargo.toml --lockedRelated to #2142. Supersedes the implementation choice proposed in #2940 with the AppContainer result proven by Windows CI.
中文说明
概要
PermissionProfile的目录、网络策略和环境编译为封闭 launch manifest安全证据
阻塞式 Windows 2025 job 验证:
PROC_THREAD_ATTRIBUTE_JOB_LIST原子 Job membership产品接入
Windows 发布流水线使用锁定 Cargo 依赖构建
maka-windows-sandbox.exe,将它打包到resources/windows-sandbox,并在安装包验证时强制检查该资源。Runtime 只从这个打包路径做 capability detection,不接受环境变量替换任意 executable,也不会 unsandboxed retry。范围边界
本 PR 为 Windows x64 安装包的 managed execution 提供真实原生沙箱;全部检查通过后即可进行实现评审。它不等于整个 Windows 平台已经正式支持。Authenticode 签名、完整对抗矩阵、cancel/parent-death/concurrency 发布证据和独立安全审查继续由 #2142 跟踪。
验证
node --test experiments/windows-sandbox/*.test.mjscargo fmt --manifest-path experiments/windows-sandbox/launcher/Cargo.toml -- --checkcargo check --manifest-path experiments/windows-sandbox/launcher/Cargo.toml --locked关联 #2142。Windows CI 的 AppContainer 结果取代 #2940 最初提出的实现选择。