Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
21b02e7
chore(interactive): open P0-A staged Draft PR (no code changes)
rockyshi1993 Nov 12, 2026
c3a3fdf
docs(interactive): record G01 frozen contract audit
rockyshi1993 Nov 12, 2026
d17a7da
docs(interactive): record G03 Grok Build capability limits
rockyshi1993 Nov 12, 2026
6989190
fix(interactive): retain validated compile feature stage
rockyshi1993 Nov 12, 2026
9c66d1d
feat(interactive): separate public terminal projection from trusted r…
rockyshi1993 Nov 12, 2026
6d30087
test(security): add isolated Host fixtures for Linux and Windows
rockyshi1993 Nov 12, 2026
1ec7d2e
ci(security): run dual-account Host isolation checks
rockyshi1993 Nov 12, 2026
ce179a1
test(security): precompile the Windows access probe before logon
rockyshi1993 Nov 12, 2026
57a39c8
test(security): restrict Windows Host process and token DACLs
rockyshi1993 Nov 12, 2026
9a17bd9
test(interactive): verify multi-process receipts and delayed acknowle…
rockyshi1993 Nov 12, 2026
7014366
test(interactive): verify long ledger and installed Interactive types
rockyshi1993 Nov 12, 2026
e1cd5c7
feat(interactive): add compatible async SDK and versioned transition …
rockyshi1993 Nov 12, 2026
6892aa4
feat(interactive): migrate SQLite for atomic audited admin termination
rockyshi1993 Nov 13, 2026
eb58230
test(interactive): record Codex App Server acceptance and inline limits
rockyshi1993 Nov 13, 2026
7acdfdd
feat(interactive): bind immutable file handoff to observed Codex calls
rockyshi1993 Nov 13, 2026
9584184
Fix Windows Node 22 file handoff identity checks
rockyshi1993 Nov 13, 2026
4deb7c8
Prepare isolated Codex App Server acceptance runners
rockyshi1993 Nov 13, 2026
52633b2
Restore blocking stdio for isolated Linux Codex
rockyshi1993 Nov 13, 2026
493213c
Capture Windows launcher fixture failures
rockyshi1993 Nov 13, 2026
695bc0e
Compile Windows stdio helper as a standalone executable
rockyshi1993 Nov 13, 2026
d9dcc00
Read Windows token elevation without impersonation
rockyshi1993 Nov 13, 2026
81c6a29
Record live Windows and Linux dual-account acceptance
rockyshi1993 Nov 13, 2026
81a4c6e
Recover signed Codex receipts from a durable Host outbox
rockyshi1993 Nov 13, 2026
56ddf93
Record Windows and Linux native Outbox acceptance
rockyshi1993 Nov 13, 2026
f01f2b5
Recover Codex file receipts and reconcile post-CAS Outbox Ack
rockyshi1993 Nov 13, 2026
380be08
Record post-CAS and file Outbox recovery on both hosts
rockyshi1993 Nov 13, 2026
ddf8c68
Exercise Codex Outbox signing cuts and key rotation
rockyshi1993 Nov 13, 2026
cfe867c
Record native Outbox signing lifecycle results on both hosts
rockyshi1993 Nov 13, 2026
ab931af
Probe revoked Host trust and current Outbox retention
rockyshi1993 Nov 13, 2026
32fec01
Record native trust revocation and Outbox retention evidence
rockyshi1993 Nov 13, 2026
1693f06
Map dual-platform Codex evidence to P0-A release gates
rockyshi1993 Nov 13, 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
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
- name: Measure repeated Interactive Program loads (diagnostic, Ubuntu Node 24)
if: ${{ matrix.os == 'ubuntu-24.04' && matrix.node == '24.22.1' }}
run: node scripts/bench-interactive-load.mjs
- name: Measure Interactive ledger writes and verify reopened receipt history
if: ${{ matrix.os == 'ubuntu-24.04' && matrix.node == '24.22.1' }}
run: node scripts/bench-interactive-ledger.mjs
- name: Consume candidate package through all documentation examples
env:
FLOWKIT_DOCS_EVIDENCE: .tmp/docs/candidate.json
Expand Down Expand Up @@ -85,11 +88,29 @@ jobs:
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Prove cross-UID model worker cannot read Host key or SQLite DB
run: node tests/security/host-isolation.mjs
- name: Verify the disposable Linux Host profile
if: ${{ matrix.node == '24.22.1' }}
run: sudo -n "$(command -v node)" tests/security/secure-host-linux.mjs
- name: Prove M6 Host and isolated worker integration
env:
FLOWKIT_M6_ISOLATION: '1'
run: node --test tests/integration/m6-e2e.test.mjs

host-security-windows-profile:
name: Host OS-user isolation / Windows
runs-on: windows-2025
timeout-minutes: 8
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '24.22.1'
- name: Verify the disposable Windows Host profile
shell: powershell
run: .\tests\security\secure-host-windows.ps1 -Node (Get-Command node.exe).Source -DisposableRunner

website:
runs-on: ubuntu-24.04
timeout-minutes: 15
Expand Down
39 changes: 39 additions & 0 deletions docs/evidence/p0a-admin-codex-20261113/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# P0-A 管理终止和 Codex 实测

Draft [#22](https://github.com/devcodex-labs/flowkit/pull/22) 的实施基线为 `e1cd5c7c4f89397fbdee50e1a430074c4c610e9d`,基线 [CI](https://github.com/devcodex-labs/flowkit/actions/runs/43331776187) 8/8 通过。

## R5 管理终止

SQLite 使用显式 V2 迁移。维护窗口内先停写入方,再由可信 Host 调用:

```js
const persistence = createSqliteInteractivePersistence(file, {
namespace, migrationBackupPath: newProtectedBackupFile,
});
```

备份路径必须是可安全新建的 Host 私有文件。SQLite 生成一致性备份,并执行完整性检查。事务锁定写入后重新核对 schema 和 data version,再创建专用审计表、安装写入保护并提交 V2。新 writer 可在迁移后正常写入,已部署旧二进制不含 V2 writer 函数,旧 SQL 写入会被触发器拒绝。该保护针对旧软件兼容性,私有数据库的 OS 访问仍依赖 Host 账户隔离。需要回滚时,在停写窗口将原备份恢复到独立位置并校验 Run/Journal。切换到迁移前快照会丢掉迁移之后的写入,需要先对账。

管理控制器仅接受由可信 Host 在进程内创建的独立管理能力,核对 namespace、管理主体和 `run:admin-terminate`。在一个 SQLite 事务写入 `cancelled` Checkpoint、转移账本及 `fk_i_admin_events`,审计只保存操作主体、reason code、时间和转移身份。管理操作无需加载 Program。原状态已终结时直接返回其终态,审计写入失败回滚整个事务。重复操作不会追加审计,迟到回执拒绝,已持久接纳记录仍可从 Store 读出。管理操作与 P0-B 业务撤销分开。

本地 Windows / Node 24.22.2 的 `npm run verify` 通过 405 项及打包消费者。S12-A 新增测试验证迁移、备份重开、旧写入方拒绝、跨租户与假能力拒绝、专用审计回滚、Program 字节不可用、重复终止、迟到回执,以及两个 SQLite 连接上的管理终止和业务终态竞争。现有生产数据库没有执行迁移。

## Codex App Server 实际执行

Codex CLI 0.145.0 通过 stdio 启动 App Server,使用账号模型目录默认项 `gpt-5.6-sol`。同一 Windows SID 下真实生成一个 Agent 结果。FlowKit 实际编译、发布 Pending、观察原生动态工具开始和回调、校验同一调用 ID 及规范参数摘要,再签名接纳。Run 返回 succeeded,接纳 revision 4,终态 revision 9,Journal 10 条。所有工具的响应都是实际程序输出。

| 样本 | 结果 | 证据限制 |
|---|---|---|
| 65,536 B 完整内联 JSON | PASS | 开始事件、工具回调及预期规范字节完全相同,回合成功完成。 |
| 262,144 B 完整内联 JSON | BLOCKED | 模型结束回合,未发出该动态工具调用。 |
| 2,093,056 B 完整内联 JSON | BLOCKED | 模型结束回合,未发出该动态工具调用。 |

三档都使用确定性 ASCII 样本,大小计算包含完整探针 JSON 对象。64 KiB 属实际传输实测。另两档只能证明当前模型和提示没有交付所需调用,无法推断底层硬上限或 2 MiB FlowKit 内联回执已通过。未启用文件回退。

**Windows/Linux 双账户等价验收 BLOCKED。** Windows 本机非提升账户,WSL 在有界探测中未启动。仓库没有配置凭据或注册自托管 runner。此前的双账户 CI 使用受限脚本并已实测 OS 权限,仍缺当前版本 Codex App Server 在独立身份下的模型调用、进程和句柄证据。探针可接收环境提供的受信隔离启动器。Linux 包含同 PID 的 exec 身份检查。Windows 需要受信启动器从实际非管理员 Host/Model Token 记录两个 SID,并只传递指定 stdio。启动器和真实环境还需联合验证。等价验收、真实多会话、签后崩溃恢复以及 NAT-14/15 保持 BLOCKED。

## 文件回退候选,待确认

建议对超过已验证内联范围的结果采用由 Host 固定的不可变内容。模型工具提交的仅是当前 Pending 的有界引用,Host 从预设的隔离入口获取内容,把同一份读取快照写入 Host 私有存储,再校验长度、UTF-8、JSON、schema 和 SHA-256。摘要、长度、命名空间、Run、Request、Attempt、thread/turn/call 及过期时间与当前受保护的动态调用绑定。模型自报路径或摘要只用于定位或比对,授权与摘要以 Host 的实际观测为准。

验收要求:256 KiB 和接近上限可由 Host 固定并复核。内容变化、超限、截断、过期、错 Run/tenant、重复消费以及未绑定调用均拒绝且无签名或 CAS。外部业务产物和完整内联回执按各自限额处理。成本是增加私有临时存储、清理和对账流程,收益是完整字节可以独立验证。等待用户确认后才实施。
22 changes: 22 additions & 0 deletions docs/evidence/p0a-codex-file-fallback-20261113/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Codex 文件回退验收

Draft [#22](https://github.com/devcodex-labs/flowkit/pull/22) 的基线 `eb5823094cdee0f5d8fe8a558a9824e1c712db4d` 在 [CI](https://github.com/devcodex-labs/flowkit/actions/runs/43343789989) 8/8 通过。本批只修改 Host 示例、Codex 探针和测试。FlowKit Core、Receipt V1、Checkpoint 格式、内联容量和包导出沿用原契约。

Host 在预设入口用受信来源登记字节数、SHA-256、Pending 和会话。工具收到的是 Host 颁发的随机引用和 requestId。入口文件只打开一次并有界读取,读取时检查普通文件、身份、长度和变化,随后校验实际原始字节的摘要、严格 UTF-8、规范 JSON 和应用提供的 schema。原始字节以 BLOB 写入 Host 私有 SQLite,使用 WAL/FULL。入口文件此后可删掉。模型工具不接收文件路径,也没有登记摘要和读取私有 BLOB 的能力。

提交时,Host 比较自己观察到的动态工具开始事件和回调,核对 thread/turn/call、相同规范参数、当前 namespace/Run/Request/Node/Attempt、Program/Policy 摘要和时效。再次校验私有快照字节数和 SHA-256,原子领取一次,然后才调用可信签名与接纳。已签收的 Agent 结果只包含快照 ID、长度和 Host 摘要。调用结束时记录接纳 revision。失去签收结果的已领取引用保持锁定,等待人工对账,重开后也不会重签。过期且未领取的快照可清除。已领取及已接纳快照的持久恢复和保留由部署方决定,自动 Outbox 恢复仍属独立验收。

| 样本 | Codex App Server 同账户实测 |
|---|---|
| 256 KiB(262,144 B) | Codex 读取真实 Pending,提交有界引用。Host 从已保存原始字节核对摘要,签名并接纳,再返回 succeeded。 |
| 近 2 MiB(2,093,056 B) | 同路径,快照字节数和摘要与登记一致,仍只把引用写进 FlowKit State。 |

两个样本由受信合成生产者生成。模型实际调用了 App Server 的动态工具并提交引用。Host 在签收前删除入口文件。日志分别记录原生开始事件、回调、快照 SHA-256、签名、接纳和终态。在该同账户验收阶段,Windows/Linux 双账户原生宿主、生产文件入口的权限部署、真实签后崩溃恢复及 NAT-14/15 均待验证。此次文件回退实测的对象是 Host 合成输入和模型提交的真实引用。

定向用例覆盖入口文件在登记前被替换、截断、超限、非法 UTF-8/重复键/schema、错误 Pending 或会话、缺少开始事件、重复或并发消费、过期、已领取后重开。登记成功后替换或删除入口文件,签收使用已固定的原始快照。

## Windows Node 22 文件身份回归

基线 `7acdfdd0137bc34cd4407ee9ffb8c2fa1e5a18a7` 的 [Windows Node 22.13.0 CI](https://github.com/devcodex-labs/flowkit/actions/runs/43345740815/job/131624564355) 将普通入口文件误判为 `FK_FILE_SOURCE`。在 Windows 实测,Node 22.13.0 对同一文件的 `lstat` 返回设备号 0,句柄 `stat` 返回非零设备号,两者的文件 ID 一致。Windows 路径查询缺失设备号时仍要求打开前后路径与句柄的非零文件 ID 一致,并要求两次路径查询的设备号相同。可用的非零设备号仍须匹配。校验同时保留普通文件、单链接、长度、时间戳和原始字节 SHA-256 检查。

P 级回归用真实文件和私有 SQLite 测试。新增硬链接和文件符号链接拒绝用例,Windows 无文件符号链接权限时实测目录联接点。两项拒绝后,同一请求仍能登记合法文件。后续两个平台均通过[独立账户下的三个真实样本](../p0a-codex-isolated-20261113/live-samples.md),生产部署和完整原生安全门禁仍待验收。
42 changes: 42 additions & 0 deletions docs/evidence/p0a-codex-isolated-20261113/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Codex App Server 双账户验收

适用范围是 Draft #22 的隔离验收。Host 与 Model 各用普通系统账户,Host 持有 FlowKit 私有目录、Store 和签名能力,Model 持有自己的 Codex 登录。探针使用合成任务和字节样本。以下布置用于指定的隔离测试机或 VM,系统账户、SSH 配置和 Codex 登录由该机器的操作者管理。

## 共同布置

1. 将 Draft #22 拉到测试机,记录 `git rev-parse HEAD`、OS、Node 和 `codex --version`。管理员保护 Node、Codex、启动器和探针源码,Model 无写权限。以 Host 账户运行探针,Host 的临时目录和输出目录仅 Host 可写、可读。Model 的工作目录和 Codex 登录目录仅 Model 可写,登录目录也仅 Model 可读。
2. 在测试机上用专用 Model 账户完成 `codex login --device-auth`,再运行 `codex login status`。使用该账户自己的配置目录。保存登录状态与版本,设备码和登录缓存留在登录流程内。Host 无需登录 Codex。[Codex CLI 登录文档](https://learn.chatgpt.com/docs/auth?surface=cli)
3. 若用 SSH,使用仅监听回环地址的测试实例,预先核验服务端主机公钥。Host 专用密钥仅 Host 可读。服务器把该密钥绑定到 Model 账户与固定命令,禁用代理转发、端口转发、PTY 和用户启动脚本。客户端配置 `Host flowkit-model`、Model 的 `User`、`Port`、专用 `IdentityFile` 和 Host 私有的 `UserKnownHostsFile`。记录有效配置的无敏感信息摘要。关闭调试登录输出,以免污染 JSONL。

## Windows

在指定 Windows 测试机上准备两个普通本地账户。编译受信启动器,在账户可读、仅管理员可修改的目录放置结果。

```powershell
& "$env:SystemRoot\Microsoft.NET\Framework64\v4.0.30319\csc.exe" /nologo /warnaserror /target:exe `
/out:C:\FlowKitLab\codex-model-stdio.exe (Resolve-Path .\tests\security\codex-model-stdio-windows.cs).Path
```

SSH 固定命令使用此启动器,唯一参数为 Model 可运行的绝对 `codex.exe` 路径。Model 启动器从实际 Codex 进程令牌读取 SID 并拒绝提升及受 UAC 过滤的管理员令牌,使用 Windows 句柄列表限定继承的三个标准流。Host 在本地通过同一程序的 `--host-identity` 核对自己的 SID。[Windows 句柄继承文档](https://learn.microsoft.com/windows/win32/procthread/creating-processes)

在 Host 的 PowerShell 设置 `FLOWKIT_CODEX_WINDOWS_IDENTITY` 为该启动器的绝对路径,`FLOWKIT_HOST_SID` 和 `FLOWKIT_MODEL_SID` 为实际账户 SID。SSH 模式下将 `FLOWKIT_CODEX_LAUNCHER` 设为绝对 `ssh.exe` 路径,将 `FLOWKIT_CODEX_SSH_CONFIG` 设为 Host 专用配置的绝对路径。

## Linux

使用两个不同非零 UID 和 GID 的账户。使用 glibc 2.34+、Linux 5.9+ 的测试机,编译并部署非特权的 exec shim。

```sh
cc -O2 -Wall -Wextra -Werror tests/security/codex-model-exec-linux.c -o /path/to/flowkit-model-exec
```

当前探针支持预先配置的本机受信启动器,也支持回环 SSH。SSH 的固定命令以 Model 身份执行 `setpriv --no-new-privs`,再用绝对 Node 路径执行 `tests/security/codex-model-identity.mjs`。参数依次为 Model UID、GID、exec shim、Codex 绝对路径及 `app-server --listen stdio:// -c 'web_search="disabled"'`。Model 账户应无额外组成员关系,命令只使用 Model 的 HOME、私有临时目录和受控 PATH。身份 helper 核对有效 UID/GID、组、能力和 `NoNewPrivs`,同 PID 交接给 shim。shim 关闭标准流外的描述符、恢复阻塞标准流,再同 PID 执行 Codex。固定命令及 Model 的 shell 启动环境由测试机操作者保护。

在 Host 进程设置 `FLOWKIT_HOST_UID`、`FLOWKIT_HOST_GID`、`FLOWKIT_MODEL_UID`、`FLOWKIT_MODEL_GID`。SSH 模式同时设置 `FLOWKIT_CODEX_LAUNCHER=/usr/bin/ssh` 和 `FLOWKIT_CODEX_SSH_CONFIG`。本机受信启动器模式设置 `FLOWKIT_CODEX_LAUNCHER` 和 `FLOWKIT_CODEX_LINUX_EXEC`,探针会传入 Node、身份 helper、Model UID/GID、exec shim、Codex 和固定 App Server 参数。操作者为启动器设置有界退出和 Model 侧清理。Host 只关闭标准输入,不能凭自身权限可靠终止其他 UID 的进程。

## 实际验收与留档

在 Host 下分别运行 `node tests/security/codex-flowkit-probe.mjs <绝对Codex路径> <Model工作目录绝对路径> <新证据目录绝对路径> <样本> isolated`。样本为 `loop`、`file-262144` 和 `file-2093056`,每个样本使用不同输出目录。SSH 模式由固定命令决定 Codex 路径,应与记录中的版本和路径一致。对命令、退出码、三个协议原始日志、`observer.ndjson` 和增量 Diff 保存 SHA-256。预期证据包含实际 Host/Model 身份、Model PID、原生开始与回调、同一个 Pending、签收 revision 和最终 `succeeded`。文件样本另核对固定字节数与摘要。

Windows CI 在一次性普通 Model 账户内验证启动器的标准流往返与实际进程 SID。Linux CI 以一次性 Model UID/GID 验证受限身份、同 PID exec 和标准流往返。两者均为 P 级 OS/启动器证据。Windows/Linux 各三个认证后的真实样本见[双账户实测记录](./live-samples.md)。

Linux 云任务在基线 `9584184d7098a402a15f3edd8bfb11ea95f7ed49` 的准备阶段使用专用容器实测 UID/GID 41001/41002。47 项 OS 权限负例通过,真实 App Server 完成同 PID 初始化。独立 Model 登录前,三个样本均返回 401,工具调用、文件登记、签名和接纳均为零。该轮报告归档 SHA-256 为 `136db4c02521fafaf76d8486d3cfd8cb597f81b39e0d0eceaecac9e61c5c0360`。
26 changes: 26 additions & 0 deletions docs/evidence/p0a-codex-isolated-20261113/live-samples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Codex App Server 双账户三样本实测

2026-11-13 在 Draft #22 的 `d9dcc0067b5d24e8a91bbe459256e99d9f285428` 上运行 `tests/security/codex-flowkit-probe.mjs` 的 `isolated` 模式。用户在两个平台各自的 Model 系统账户下完成 Codex 设备登录,Host 账户只运行 FlowKit 探针。

| 平台 | 实测环境 | 普通闭环 | 256 KiB 文件回退 | 近 2 MiB 文件回退 |
|---|---|---|---|---|
| Windows | 普通 Host 和 Model 的实际 SID 不同,受信启动器通过本机回环 SSH 启动 Codex CLI 0.145.0,模型 `gpt-5.6-sol` | PASS | PASS,262,144 B | PASS,2,093,056 B |
| Linux | 专用容器内 Host 41001、Model 41002,Model 零能力且 `NoNewPrivs=1`,Codex CLI 0.167.0-alpha.4,模型 `gpt-6.1-sol` | PASS | PASS,262,144 B | PASS,2,093,056 B |

六次实测各记录三组原生动态工具开始和回调,thread、turn 和 call ID 对应。Host 对真实 Pending 签收,接纳 revision 为 4,终态为 `succeeded`(revision 9,Journal 10 条)。两个文件样本的正文来自受信合成生产者。真实模型读取 PublicTask 后提交 Host 固定的文件引用,两端登记和接纳的字节数与摘要一致。

| 字节数 | 两端 SHA-256 |
|---|---|
| 262,144 | `a89ec2764412be3284c3b2334a8ba4a484bfb7f6df2a8e274acc782a4e3231bb` |
| 2,093,056 | `716f7d91c27f9e89e87fa13d2e2d47ba3b4dba942cb42f371610eac0ed83fd87` |

Linux 登录后的首轮因缺少配套 Code Mode 组件,模型完成回合但没有提交工具调用。FlowKit 任务从同一 Codex 安装补齐 `codex-code-mode-host`、`codex-exec-server` 和 `bwrap` 后重跑通过,首轮原始记录留档。Linux 测试容器仍需为长期运行配置 init/reaper。本轮 Windows 回环 SSH 使用签名校验通过的便携版,监听 `127.0.0.1:41762`。系统 OpenSSH 服务保持停止,默认入站规则已禁用。

P、M、T 级证据覆盖这三个样本的实际程序运行、真实模型回合和独立系统身份下的原生工具通道。完整 256 KiB 和近 2 MiB 的内联传输、完整 NAT-14/15 与 C12/S13 仍为 BLOCKED。此批的验收记录保存 Host 验签接纳及声明摘要。后续[双会话竞争与 Outbox 实测](./outbox-live.md)覆盖另两个场景,并保存了可离线验签的证据。

| 原始证据包 | ZIP SHA-256 |
|---|---|
| Windows 本次验收交付 `flowkit-windows-dual-account-evidence.zip` | `5442cd27e74674451a1f16ea88c24f84f01ca7a74fab7f6d0fd8fc036dca4d76` |
| Linux FlowKit 云任务交付 `FlowKit-Linux-Live-Three-Samples-20261113.zip` | `b18af80ac30c49694bdff4b4d1aeb4c0c5e835bcd849a09152b057af4474cb50` |

两个归档包含实际执行记录、原始协议日志、Host 观察日志和逐文件哈希。设备码、密码和令牌留在登录边界内。
Loading