Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions docs/architecture/windows-sandbox-rfc-v1.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
---
doc_id: architecture.windows-sandbox-rfc-v1
title: "Windows sandbox RFC v1"
language: en
source_language: en
implementation_status: current
document_status: current
translation_status: synced
last_verified: 2026-09-04
Comment thread
Astro-Han marked this conversation as resolved.
owners:
- maka-backend
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
Expand All @@ -19,8 +31,8 @@

# Windows sandbox backend RFC v1

- Status: implementation baseline selected; first preview slice ([#2961](https://github.com/maka-agent/maka-agent/pull/2961)) merged 2026-08-17; product integration continuing under release validation (preview scope in §6.5)
- Tracking: Windows Phase 4 in [issue #2142](https://github.com/maka-agent/maka-agent/issues/2142)
- Status: implementation baseline selected; first preview slice ([#2961](https://github.com/apache/maka/pull/2961)) merged 2026-08-17; product integration continuing under release validation (preview scope in §6.5)
- Tracking: Windows Phase 4 in [issue #2142](https://github.com/apache/maka/issues/2142)
- Updated: 2026-08-18
- Owners: `@maka/runtime` sandbox boundary and Runtime Host execution composition
- Chinese version: [windows-sandbox-rfc-v1.zh-CN.md](./windows-sandbox-rfc-v1.zh-CN.md)
Expand Down Expand Up @@ -241,13 +253,14 @@ Lexical prefix checks are never authorization evidence.
### 6.5 Preview implementation status (2026-08-24)

The first product slice — the packaged Windows 11 x64 AppContainer backend in
[#2961](https://github.com/maka-agent/maka-agent/pull/2961), merged 2026-08-17 — enforces a subset
[#2961](https://github.com/apache/maka/pull/2961), merged 2026-08-17 — enforces a subset
of the guarantees above. This subsection aligns the documented guarantees with what the code
actually ships so the RFC does not overclaim. Bullets tagged with a follow-up PR number
(`(#3161)` readiness probe, `(#3174)` private-desktop placement) land in that PR rather than the
merged #2961 slice; the untagged bullets are enforced by #2961 today. The remaining guarantees are
actually ships so the RFC does not overclaim. Bullets tagged with a follow-up PR number — `(#3722)`
for the launch-owner handle, the 64-launch soak, and the malicious-child matrix, `(#3174)` for the
readiness probe and private-desktop placement — land in that PR rather than the merged #2961 slice;
the remaining untagged bullets are enforced by #2961 today. The remaining guarantees are
designed but explicitly deferred as later gates, tracked by Phase 4 in
[#2142](https://github.com/maka-agent/maka-agent/issues/2142).
[#2142](https://github.com/apache/maka/issues/2142).

Enforced (merged in #2961 unless tagged with a follow-up PR):

Expand All @@ -260,14 +273,14 @@ Enforced (merged in #2961 unless tagged with a follow-up PR):
- inheritance limited to declared stdio/protocol handles through `PROC_THREAD_ATTRIBUTE_HANDLE_LIST`
(§6.3);
- a closed, sorted, allowlisted environment (§6.3);
- a kernel-observed Runtime Host owner handle on the packaged one-shot broker: owner exit interrupts
- a kernel-observed Runtime Host owner handle on the packaged one-shot broker **(#3722)**: owner exit interrupts
the first launch, terminates and drains the AppContainer Job, and releases the launch ledger/ACEs;
- a packaged 64-launch repeated-wave concurrency soak with disjoint launch identities, followed by
- a packaged 64-launch repeated-wave concurrency soak with disjoint launch identities **(#3722)**, followed by
process and ACL-ledger residue assertions;
- a packaged malicious-child matrix covering recursive junction and multi-hard-link admission,
outside-file access, TCP connection denial, host named-pipe access, ambient environment,
host HKCU values, parent-token access, descendant AppContainer/Job inheritance, and quarantined
identity non-reuse;
identity non-reuse **(#3722)**;
- per-launch private-desktop **placement** (§6.3) **(#3174)**: each production launch and the readiness probe
create an alternate desktop on the current window station whose DACL grants only the launching user,
Local System, and that launch's AppContainer SID — the SID getting only minimal non-interactive
Expand All @@ -282,15 +295,15 @@ Enforced (merged in #2961 unless tagged with a follow-up PR):
stops in-process code from `OpenDesktopW("Default")` + `SetThreadDesktop`, and the clipboard is
window-station-scoped and remains shared (a no-Win32k mitigation, a dedicated window station, and a
token boundary are deferred gates below);
- a production-identity readiness probe (§6.4) **(#3161)**: `--readiness-probe` stands up the real
- a production-identity readiness probe (§6.4) **(#3174)**: `--readiness-probe` stands up the real
AppContainer identity and token, a kill-on-close Job, and the private desktop, then launches a
throwaway confined child on that desktop (`cmd.exe /d /c exit 0`, with AutoRun disabled so a host's
shell customization cannot skew the result), so availability fails closed on hosts where the OS
cannot create the boundary rather than on the packaged binary's presence alone; on success it emits
a machine-readable attestation of the verified facts (exact-SID match, specific-Job membership,
settlement, private-desktop placement) that the release smoke asserts field by field, so the gate
cannot silently degrade into a hollow exit-0 check;
- a dedicated, cross-process-serialized readiness profile lifecycle (§6.4) **(#3161)**: the probe profile lives
- a dedicated, cross-process-serialized readiness profile lifecycle (§6.4) **(#3174)**: the probe profile lives
in a namespace disjoint from production, its reserved `requestId` is rejected by validation, a
DACL-hardened per-user named mutex serializes its delete→create→probe→drop cycle, an unsettled
probe fails closed rather than claiming a clean boundary (relying on the kill-on-close Job and a
Expand Down
28 changes: 20 additions & 8 deletions docs/architecture/windows-sandbox-rfc-v1.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
---
doc_id: architecture.windows-sandbox-rfc-v1
title: "Windows sandbox RFC v1"
language: zh-CN
source_language: en
implementation_status: current
document_status: current
translation_status: synced
last_verified: 2026-09-04
owners:
- maka-backend
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
Expand All @@ -19,8 +31,8 @@

# Windows 沙箱后端 RFC v1

- 状态:实现基线已选定;首个预览切片([#2961](https://github.com/maka-agent/maka-agent/pull/2961))已于 2026-08-17 合并;产品接入继续做发布验证(预览范围见 §6.5)
- 跟踪:[Issue #2142](https://github.com/maka-agent/maka-agent/issues/2142) Windows Phase 4
- 状态:实现基线已选定;首个预览切片([#2961](https://github.com/apache/maka/pull/2961))已于 2026-08-17 合并;产品接入继续做发布验证(预览范围见 §6.5)
- 跟踪:[Issue #2142](https://github.com/apache/maka/issues/2142) Windows Phase 4
- 更新日期:2026-08-18
- Owner:`@maka/runtime` sandbox boundary 与 Runtime Host execution composition
- 英文版:[windows-sandbox-rfc-v1.md](./windows-sandbox-rfc-v1.md)
Expand Down Expand Up @@ -164,7 +176,7 @@ Maka 外已失陷的同用户进程。sandboxed code 从第一条指令开始按

### 6.5 预览实现状态(2026-08-24)

首个预览切片 [#2961](https://github.com/maka-agent/maka-agent/pull/2961) 已于 2026-08-17 合并,强制上述保证的一个子集。本节把文档与已交付代码对齐,使 RFC 不 overclaim:§6.3/§6.4 中尚未强制的保证在此显式标为后续门禁。标注 `(#3161)` 的条目落在 readiness-probe 后续 PR,而非已合并的 #2961 切片;其余条目由 #2961 当前强制。
首个预览切片 [#2961](https://github.com/apache/maka/pull/2961) 已于 2026-08-17 合并,强制上述保证的一个子集。本节把文档与已交付代码对齐,使 RFC 不 overclaim:§6.3/§6.4 中尚未强制的保证在此显式标为后续门禁。标注 `(#3722)` 的条目(Runtime Host 父进程 wait handle、64 次 soak、恶意 child 矩阵)与标注 `(#3174)` 的条目(readiness probe 与 private desktop 放置)落在对应后续 PR,而非已合并的 #2961 切片;其余未标注条目由 #2961 当前强制。

**已强制(未标注者由 #2961 合并强制):**

Expand All @@ -175,16 +187,16 @@ Maka 外已失陷的同用户进程。sandboxed code 从第一条指令开始按
- 创建时原子附加、close 时杀整棵树的 kill-on-close Job(§6.3);
- 仅通过 `PROC_THREAD_ATTRIBUTE_HANDLE_LIST` 继承声明的 handle(§6.3);
- 封闭、排序后的 allowlist 环境(§6.3);
- 打包 one-shot broker 持有由内核进程表确认的 Runtime Host 父进程 wait handle:Host 退出会
- 打包 one-shot broker 持有由内核进程表确认的 Runtime Host 父进程 wait handle **(#3722)**:Host 退出会
中断首次启动、终止并 drain AppContainer Job,并释放本次 ledger/ACE;
- 打包路径执行 64 次、按波次重复的并发 soak,每次使用互不相同的启动 identity,最后断言无进程与
ACL-ledger 残留;
ACL-ledger 残留 **(#3722)**
- 打包恶意 child 矩阵覆盖递归 junction 与多硬链接准入、outside 文件、TCP connection 拒绝、宿主 named
pipe、ambient 环境、宿主 HKCU、父进程 token、descendant 的 AppContainer/Job 继承,以及 quarantine
identity 不复用;
identity 不复用 **(#3722)**
- 按启动的 private desktop **放置(placement)**(§6.3)**(#3174)**:每次生产启动与 readiness probe 均在当前 window station 上创建 alternate desktop,其 DACL 仅授予发起用户、Local System 与该次启动的 AppContainer SID(且只给该 SID 最小非交互权限;并以前置 deny ACE 从 AppContainer 子进程有效携带的发起用户 SID 上剥离 `DESKTOP_SWITCHDESKTOP`/`DESKTOP_HOOKCONTROL`/journal 录制回放),并以 `STARTUPINFOW.lpDesktop` 指向它启动子进程,建不出或授不了即 fail closed。桌面钉在 Low integrity(`S:(ML;;NW;;;LW)`)使授予权限对 Low-IL 子进程通过 MIC,且 heap 经 `CreateDesktopExW` 按启动限额(512 KiB)使受支持并发不会耗尽系统 desktop heap。由于 `lpDesktop` 只选择*初始*桌面,这把 worker 放置到交互 `Default` 桌面之外并对私有桌面做 DACL 保护;这是 placement 加 DACL 保护、**不是**防逃逸边界——没有结构性机制阻止进程内代码 `OpenDesktopW("Default")` + `SetThreadDesktop` 重新挂回,clipboard 也归 window station、仍为共用(no-Win32k mitigation、独立 window station 与 token 边界见下方暂缓门禁);
- 生产 identity readiness probe(§6.4)**(#3161)**:`--readiness-probe` 真正建立 AppContainer identity/token、kill-on-close Job 与 private desktop 并在该桌面上启动抛弃式受限子进程(`cmd.exe /d /c exit 0`,以 `/d` 关闭 AutoRun 使宿主 shell 定制不能扭曲结果),使可用性在宿主无法创建边界时 fail closed,而非仅凭打包二进制存在;成功时输出机器可读 attestation(精确 SID 匹配、特定 Job membership、settlement、private-desktop placement),发布冒烟逐字段断言,使该 gate 不会静默退化为空洞的 exit-0 检查;
- 专属且跨进程串行的 readiness profile 生命周期(§6.4)**(#3161)**:probe profile 位于与生产不相交的命名空间,其保留 `requestId` 被 validation 拒绝,一个 DACL 加固的按用户命名互斥量串行其 delete→create→probe→drop 生命周期,未证清空的 probe 按周期 fail closed 而非宣称边界干净(清理依赖 kill-on-close Job 与零权限 identity,而非持久隔离),负可用性按有界 TTL 缓存以限制一次瞬时失败毒化 module 缓存的时长——由下一次 composition 构建重探,而非运行中宿主原地恢复;
- 生产 identity readiness probe(§6.4)**(#3174)**:`--readiness-probe` 真正建立 AppContainer identity/token、kill-on-close Job 与 private desktop 并在该桌面上启动抛弃式受限子进程(`cmd.exe /d /c exit 0`,以 `/d` 关闭 AutoRun 使宿主 shell 定制不能扭曲结果),使可用性在宿主无法创建边界时 fail closed,而非仅凭打包二进制存在;成功时输出机器可读 attestation(精确 SID 匹配、特定 Job membership、settlement、private-desktop placement),发布冒烟逐字段断言,使该 gate 不会静默退化为空洞的 exit-0 检查;
- 专属且跨进程串行的 readiness profile 生命周期(§6.4)**(#3174)**:probe profile 位于与生产不相交的命名空间,其保留 `requestId` 被 validation 拒绝,一个 DACL 加固的按用户命名互斥量串行其 delete→create→probe→drop 生命周期,未证清空的 probe 按周期 fail closed 而非宣称边界干净(清理依赖 kill-on-close Job 与零权限 identity,而非持久隔离),负可用性按有界 TTL 缓存以限制一次瞬时失败毒化 module 缓存的时长——由下一次 composition 构建重探,而非运行中宿主原地恢复;
- fail-closed capability check,绝不 unsandboxed fallback(§6.4)。

**已设计但作为后续门禁暂缓(预览切片尚未强制):**
Expand Down
12 changes: 12 additions & 0 deletions docs/permission-onboarding-plan.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
---
doc_id: permission-onboarding-plan
title: "Drag-to-grant permission onboarding (macOS)"
language: en
source_language: en
implementation_status: current
document_status: current
translation_status: source-only
last_verified: 2026-09-04
owners:
- maka-backend
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
Expand Down
24 changes: 19 additions & 5 deletions docs/workspace-privacy-context.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
---
doc_id: workspace-privacy-context
title: "Workspace privacy context"
language: en
source_language: en
implementation_status: current
document_status: current
translation_status: source-only
last_verified: 2026-09-04
owners:
- maka-backend
---
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
Expand Down Expand Up @@ -29,21 +41,23 @@ export interface WorkspacePrivacyContext {

## Authority

The main process owns the effective workspace privacy state. Renderers may request a change and display the current value, but a renderer-provided value is never proof of the effective state.
The Runtime Host owns the effective workspace privacy state as runtime policy. Renderers may request a change and display the current value, but a renderer-provided value is never proof of the effective state.
Comment thread
Astro-Han marked this conversation as resolved.

The current authority path is:

- `apps/desktop/src/renderer/settings/general-settings-page.tsx` requests settings changes.
- `apps/desktop/src/main/main.ts` resolves the effective state through `getWorkspacePrivacyContext()`.
- Main-process consumers receive that resolved context rather than trusting renderer input.
- The effective state is the Runtime Host runtime policy: `packages/core/src/runtime-policy.ts` declares the readonly `privacy.incognitoActive` field and defaults it to `false`; patches are validated by the policy codec's `privacy patch` record rule.
- Desktop surfaces resolve the effective state from the policy via `queryRuntimePolicy()` (for example `apps/desktop/src/main/runtime-host-search-ipc-main.ts`), and core-boundary consumers validate the projected context through `validateWorkspacePrivacyContext()` (`packages/core/src/incognito.ts`) before reading any field.

`defaultWorkspacePrivacyContext()` returns `{ incognitoActive: false }` for explicit initialization. `validateWorkspacePrivacyContext()` rejects malformed input; it never converts missing or invalid data to `false`. Boundaries that cannot resolve a valid authoritative context must fail closed.
One documented exception: the run-ended notification gate (`apps/desktop/src/main/notifications-ipc-main.ts`) still reads `privacy.incognitoActive` from the local settings store, and privacy patches never reach that store (`apps/desktop/src/shared/settings-ownership.ts` excludes `privacy` from the local patch), so the gate keeps seeing the stale or default value after incognito is enabled and can raise a notification carrying the session title and reply preview. Migrating this gate to the policy authority is a named follow-up; until it lands, this gate is the one documented deviation from the rule above.

`validateWorkspacePrivacyContext()` rejects malformed input; it never converts missing or invalid data to `false`. Boundaries that cannot resolve a valid authoritative context must fail closed.

## Consumer rule

`incognitoActive: false` only means that incognito mode did not block the operation. It is not general permission to read, write, search, capture, or transmit data. Every consumer must still apply its own settings, permission, and retention rules.

When `incognitoActive` is true, each privacy-sensitive consumer defines a fail-closed result at its existing main-process boundary. The composition in `apps/desktop/src/main/main.ts` and focused consumer tests own the current inventory. Do not duplicate that inventory here, add another incognito flag, copy the state into a parallel store, or let a renderer self-attest.
When `incognitoActive` is true, each privacy-sensitive consumer defines a fail-closed result at its existing main-process boundary. The Runtime Host composition, the desktop main-process consumers, and their focused tests own the current inventory. Do not duplicate that inventory here, add another incognito flag, copy the state into a parallel store, or let a renderer self-attest.

## Contract changes

Expand Down