Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
26d955b
feat(git): add short-lived Gitoxide admission helper
zhiiw Aug 23, 2026
6f1d6c4
fix(git): classify unsupported repository formats
zhiiw Aug 23, 2026
b1d4e67
feat(git): bind helper artifacts to opaque capabilities
zhiiw Aug 23, 2026
08da1fb
feat(git): own short-lived helper invocations
zhiiw Aug 23, 2026
a45ce4b
feat(git): issue repository admission capabilities
zhiiw Aug 23, 2026
4e5333c
test(git): isolate concurrent helper fixtures
zhiiw Aug 23, 2026
303ce56
feat(git): import admitted source heads
zhiiw Aug 23, 2026
83c5e09
build(git): lock source import dependency
zhiiw Aug 23, 2026
a00d338
fix(git): bound managed tree traversal
zhiiw Aug 24, 2026
c930347
fix(runtime-host): preserve tree policy failures
zhiiw Aug 24, 2026
94ab9af
feat(git): publish exact-base successors
zhiiw Aug 23, 2026
d3f749b
build(git): enable tree editing
zhiiw Aug 23, 2026
081a57e
fix(git): validate complete successor trees
zhiiw Aug 24, 2026
05f0148
feat(runtime-host): prepare owner-bound Gitoxide candidates
zhiiw Aug 23, 2026
8ddc864
feat(runtime-host): persist Gitoxide candidate receipts
zhiiw Aug 23, 2026
eca997b
test(runtime-host): bind candidates to imported baseline
zhiiw Aug 23, 2026
4ebfac7
fix(runtime-host): release candidate ref before CAS
zhiiw Aug 23, 2026
94a021b
fix(runtime-host): close candidate observation before CAS
zhiiw Aug 23, 2026
f88ea9e
fix(gitoxide): publish candidates in one ref transaction
zhiiw Aug 23, 2026
3cc4374
diagnostics(gitoxide): report ref transaction failures
zhiiw Aug 23, 2026
4cc1560
diagnostics(runtime-host): surface helper ref errors
zhiiw Aug 23, 2026
0776977
diagnostics(gitoxide): include ref failure chain
zhiiw Aug 23, 2026
63a064f
fix(gitoxide): create the candidate ref namespace
zhiiw Aug 23, 2026
8881e8b
fix(runtime-host): bound Gitoxide artifact path lengths
zhiiw Aug 23, 2026
71458f2
fix(runtime-host): bind candidate proofs to receipts
zhiiw Aug 24, 2026
aec531f
fix(runtime-host): require candidate storage ownership
zhiiw Aug 24, 2026
051e4ea
style(gitoxide): match pinned Rust formatting
zhiiw Aug 24, 2026
8313bab
fix(gitoxide): make source import restartable
zhiiw Aug 24, 2026
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
84 changes: 84 additions & 0 deletions .github/workflows/gitoxide-helper-admission.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

name: Gitoxide helper admission

on:
pull_request:
paths:
- '.github/workflows/gitoxide-helper-admission.yml'
- 'native/gitoxide-helper/**'
- 'packages/runtime-host/src/server/gitoxide-helper-*.ts'
- 'packages/runtime-host/src/__tests__/gitoxide-helper-*.test.ts'
- 'docs/architecture/gitoxide-*.md'
push:
branches:
- main
paths:
- '.github/workflows/gitoxide-helper-admission.yml'
- 'native/gitoxide-helper/**'
- 'packages/runtime-host/src/server/gitoxide-helper-*.ts'
- 'packages/runtime-host/src/__tests__/gitoxide-helper-*.test.ts'
- 'docs/architecture/gitoxide-*.md'

permissions:
contents: read

concurrency:
group: gitoxide-helper-admission-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22.19.0
cache: npm
- name: Check Rust formatting
working-directory: native/gitoxide-helper
run: cargo fmt --check
- name: Test the short-lived Gitoxide helper
working-directory: native/gitoxide-helper
run: cargo test --locked
- name: Install JavaScript dependencies without packaging hooks
run: npm ci --ignore-scripts
- name: Build the helper invocation owner
run: >-
npm --workspace @maka/core run build &&
npm --workspace @maka/storage run build &&
npm --workspace @maka/runtime run build &&
npm --workspace @maka/runtime-host run build
- name: Test the real helper invocation contract
env:
MAKA_GITOXIDE_HELPER_PATH: ${{ github.workspace }}/native/gitoxide-helper/target/debug/maka-gitoxide-helper${{ runner.os == 'Windows' && '.exe' || '' }}
run: >-
node --test
packages/runtime-host/dist/__tests__/gitoxide-helper-artifact-authority-internal.test.js
packages/runtime-host/dist/__tests__/gitoxide-helper-invocation-internal.test.js
packages/runtime-host/dist/__tests__/gitoxide-helper-mutation-candidate-authority-internal.test.js
packages/runtime-host/dist/__tests__/gitoxide-repository-admission-authority-internal.test.js
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ docs/assets/
apps/desktop/tests/real-window-smoke/
deepseek.key

# Built only by the dedicated Gitoxide helper lane; normal workspace tests do not use Cargo.
/native/gitoxide-helper/target/

# Generated Computer Use executor binary; provenance metadata stays tracked.
apps/desktop/resources/bin/
# Rebuilt from experiments/windows-sandbox by scripts/package-windows-x64.mjs.
Expand Down
116 changes: 116 additions & 0 deletions docs/architecture/gitoxide-helper-artifact-authority-v1.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

# Gitoxide helper artifact authority v1

状态:stacked 验证切片;尚无正式 release issuer、Desktop/CLI/Runtime Host 生产消费者,必须保持
Draft。

## 1. 主要不变量

本切片只证明:

> 普通 caller 不能用自报的 executable path 或 SHA-256 获得 Gitoxide helper 调用资格;只有内部
> release owner 签发、与 owner token 绑定的 artifact claim,在 exact platform、architecture、
> protocol、size 与 SHA-256 校验通过后,才能转换为另一个指定 owner 可消费的 opaque invocation
> capability。artifact 在 admission 后变化时,调用前重验必须 fail closed。

它不证明平台签名、安装目录保护、helper spawn、repository observation、T1 admission、managed
workspace 或 crash recovery。

## 2. Owner 与 API 权限

```text
未来的 packaged-release owner
└─ issueGitoxideHelperReleaseArtifactClaimInternal(ownerToken, exact artifact identity)
↓ opaque release claim
artifact authority
└─ exact file/platform/protocol verification
↓ opaque invocation capability
未来的 invocation owner
└─ verifyGitoxideHelperArtifactForInvocationInternal(ownerToken, capability)
```

- claim 与 capability 的状态存放在模块私有 `WeakMap` 中;对象表面不包含 path、digest 或 size。
- claim 必须由相同的 release owner token 消费;capability 必须由签发时指定的 invocation owner token
消费。
- 相关 internal API 不从 `@maka/runtime-host/server` 导出。
- 旧的 caller-provided `{ executablePath, expectedSha256 }` 不能成为这条链的 authority。

当前没有 production release owner。`issueGitoxideHelperReleaseArtifactClaimInternal()` 只是未来受信
packaging owner 的接缝,不是签名信任根;在该 owner 落地前,本切片不能转 Ready。

## 3. 校验边界

一次 artifact 校验包含:

1. 输入 claim 的 protocol/platform/architecture/size/digest 形状检查;
2. 拒绝 claimed path 任意组件中的 symlink 或 Windows junction;
3. 打开 canonical regular file,并限制 helper artifact 最大为 256 MiB;
4. 在同一 handle 上进行 64 KiB 有界缓冲的 SHA-256 流式读取;
5. 比较读取前后 handle identity/size/timestamps;
6. 比较读取后 path identity 与已打开 handle;
7. 比较 exact byte count 与 digest。

admission 与每次 invocation resolve 都执行这套校验。它可以识别校验之前或校验期间的替换,不会把
相邻 manifest 当作自证信任根。

## 4. 原子性、失败状态与回滚

| 项目 | v1 合同 |
| --- | --- |
| owner | Runtime Host 内部 artifact authority |
| 原子性边界 | 单个打开 file handle 的一次 identity + streaming digest observation |
| durable state | 无;claim/capability 仅存在于进程内 |
| 非法/伪造 claim | `gitoxide_helper_release_claim_invalid` |
| 平台或架构不匹配 | `gitoxide_helper_release_claim_unsupported` |
| path/symlink/读取失败 | `gitoxide_helper_artifact_invalid` |
| size/digest/identity 漂移 | `gitoxide_helper_artifact_identity_mismatch` |
| 错误 owner/伪造 capability | `gitoxide_helper_invocation_capability_invalid` |
| rollback | 只读校验,无副作用,无需回滚 |

## 5. 明确不承诺的威胁模型

本切片没有声称抵抗拥有同一 OS 用户文件写权限的主动攻击者。特别是:

- 它尚未验证 macOS code signature、Windows Authenticode 或 Linux 发布清单的受信签名;
- 它尚未把 helper 放进由正式安装器保护的只读目录;
- 它尚未拥有 spawn,因此不声称消除了“最后一次 path 校验完成后、未来 spawn 开始前”的替换窗口。

下一切片在接入 spawn 前,必须由正式 packaged-release owner 提供信任根,并明确三平台安装目录与
签名能力。不能通过给本 API 再传一个裸 expected digest 来绕过这一门槛。

## 6. 平台能力矩阵

| 平台 | 当前持续验证 | 尚未承诺 |
| --- | --- | --- |
| Linux | regular-file identity、digest、symlink path rejection | package signature、protected install root、spawn identity |
| macOS | 同 Linux | code-sign verification、notarized artifact binding、spawn identity |
| Windows | regular-file identity、digest、junction path rejection | Authenticode binding、ACL-protected install root、spawn identity |

## 7. 后续切片

后续只能按下面顺序推进:

1. 发布/安装 owner 把受信 helper identity 绑定到 signed product artifact;
2. 短生命周期 invocation owner 消费 opaque capability 并运行 strict helper protocol;该 stacked
Draft 的合同见 `gitoxide-helper-invocation-owner-v1.zh-CN.md`;
3. repository observation 再转换为 T1 前的 opaque admission capability。

在第 1 项完成以前,不接 Desktop/CLI,也不恢复旧 Git CLI adapter。
94 changes: 94 additions & 0 deletions docs/architecture/gitoxide-helper-invocation-owner-v1.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

# Gitoxide short-lived invocation owner v1

状态:stacked Draft;真实 Rust helper 的三平台 contract 进入 CI,但仍无正式 release issuer、
Desktop/CLI/managed-workspace 生产消费者。

## 1. 主要不变量

本切片只证明:

> Runtime Host 只能通过 owner-bound opaque artifact capability 启动一次 exact Gitoxide helper;
> invocation 使用固定 strict JSON request、最小环境、有界 stdin/stdout/stderr、固定超时与取消边界;
> exit 0/1/2 必须分别匹配 inspected/operational failure/policy rejection 的 exact response shape,任意
> 不一致均 fail closed。

它不签发 repository admission capability,不写 SQLite/T1,不创建 Git artifact,也不接 Desktop/CLI。

## 2. Owner 与调用链

```text
opaque GitoxideHelperInvocationCapability
↓ invocation owner token 验证 + artifact bytes 重验
fixed argv [] / minimal env / no shell
↓ 64 KiB strict JSON request
one short-lived Rust helper
↓ bounded stdout/stderr + exact exit/response decoder
typed observation | typed policy rejection | stable error
```

caller 不能提供 executable path、argv、environment、protocol version、timeout 或 output limit。唯一可变
输入是 absolute repository path 与 AbortSignal;repository path 在 spawn 前 canonicalize。

## 3. 原子性、失败状态与回滚

| 项目 | v1 合同 |
| --- | --- |
| owner | 单次 Runtime Host invocation owner |
| 原子性边界 | artifact revalidation 后启动的一个 helper process 与其 exact response |
| 成功 | exit 0 + exact SHA-1 `repository_inspected` |
| policy rejection | exit 2 + exact `unsupported_object_format` |
| repository/helper failure | exit 1 + allowlisted stable helper reason |
| timeout | 5 秒后 force-kill process tree,`gitoxide_helper_invocation_timed_out` |
| cancellation | preflight 或运行中 fail closed,`gitoxide_helper_invocation_aborted` |
| resource failure | stdout 64 KiB、stderr 16 KiB,超限 force-kill |
| malformed protocol | exit code、JSON shape、OID 或字段不一致均拒绝 |
| rollback | helper 是只读 observation,无 durable side effect |

Rust helper v1 不启动 descendants;Runtime 仍使用共享 process-tree terminator 处理 timeout、abort 和
output overflow,不允许常驻或 detached helper。

## 4. 配置与数据边界

- argv 固定为空,禁止 caller 注入 helper option;
- `shell: false`,不会经过 shell parsing;
- child `PATH` 为空,只保留 Windows loader 与临时目录所需的最少环境变量;
- Rust 侧仍使用 `gix::open::Options::isolated()` 与 `strict_config(true)`;
- request 最大 64 KiB;stdout 最大 64 KiB;stderr 最大 16 KiB;
- SHA-1 OID 必须是 40 位小写十六进制;SHA-256/未知格式只返回 rejection,禁止 fallback。

## 5. 平台证据

同一个 workflow 在 Linux、macOS、Windows 上:

1. 编译并测试 Rust helper;
2. 构建 Runtime Host;
3. 通过真实 helper executable 验证 SHA-1 success、SHA-256 rejection、unborn SHA-1 failure。

该证据只覆盖进程崩溃/终止和只读协议,不包含平台安装签名或恶意同用户替换;后者仍属于正式
packaged-release trust root。

## 6. 下一切片

下一步只把 exact repository observation 转换成 T1 前可消费的 owner-bound opaque admission
capability,并绑定 canonical repository path、object format、HEAD commit/tree 与 observation protocol;
合同见 `gitoxide-repository-admission-capability-v1.zh-CN.md`。不在该切片中实现 source import、
worktree projection、candidate 或 ref CAS。
Loading
Loading