Skip to content

feat(coordination): 受保护 scope 的事务化派发许可存储与平台授权适配层 (M-044/MS-003) - #122

Merged
Kucell merged 2 commits into
mainfrom
codex/m044-ms003-transaction-store
Oct 26, 2026
Merged

Kucell merged 2 commits into
mainfrom
codex/m044-ms003-transaction-store

Conversation

@Kucell

@Kucell Kucell commented Oct 26, 2026

Copy link
Copy Markdown
Owner

Summary

Implements M-044 / MS-003 — the protected scope's transactional dispatch permit store and
the platform authorization adapter that anchors it
.

Two pieces, one property. The property is: the set of identities that can write the anchor
domain is exactly {the service identity}
. The permit store is what depends on that property,
and the adapter is what finally makes it enforceable.

Why this PR exists now

The MS-003 product source had never reached origin/main. It was not an oversight of
this round — every prior Decision for this milestone said "does not authorize committing or
pushing product source, does not authorize creating a PR", so the files stayed in the isolated
worktree across eight rounds of rework. The consequence was concrete: the SamHMI side could
not lift its product-security BLOCK, because the capability was never delivered and
"wait for M-044's capability sign-off" could never be satisfied.

MS-002 shipped the same way via PR #114. This PR is the corresponding step for MS-003.

The protected scope's transactional dispatch permit store

Permits, idempotency keys, desktop draining and revocation tombstones commit in one database
transaction; the permit is returned only after the durable commit.

The property VC-044-007 requires detecting: once a one-shot permit is consumed, if an
attacker rolls the database back to a pre-consumption snapshot, is the permit consumable a
second time?

The high-water mark therefore lives outside the database's rollback domain, in the
protected anchor directory, as an append-only journal of intent(seq, body_digest) /
commit(seq, body_digest) records. Comparing the committed high-water mark H with the
database's own anchor sequence D is unambiguous:

relation reading recoverable?
D < H the database is older than the journal — a rollback never
D > H crash between the database commit and the journal commit yes, the only recoverable case
D == H the database matches the journal the journal's body_digest must equal the database body

A one-step rollback produces D == H-1, which is the first case and is never recoverable.
The recovery entry point therefore cannot launder a rollback.

The platform authorization adapter

The previous strict check implemented pure POSIX semantics (mode bits + st_uid), which
is wrong on two of the three supported platforms:

  • Windows — mode bits are constantly 0666 and there is no st_uid, so strict
    refused every Windows deployment (the target platform) while proving nothing. The real
    authorization model is the DACL.
  • macOS — a named ACL entry grants write without showing up in the mode bits, so a
    deployment that staff could write was accepted as safe.

The adapter reads "who can write this object" from the platform's own authorization model:

platform model source
POSIX mode bits fs.lstatSync
macOS POSIX bits + NFSv4-style ACL ls -lde (LC_ALL=C)
Windows DACL Get-Acl + ConvertTo-Json (structured ACEs)

The judgment rule is unified: the writable identity set must equal {the declared service
identity}
. The declaration is explicit, and the calling process's identity must equal it.
Trusting only "whoever is calling" would make the check circular — a process able to run as
the service identity would pass by definition. The explicit comparison turns impersonation
into a detectable failure.

Three states stay distinguishable:

  • null — the platform model cannot be enumerated. This is not "safe" and not
    "nobody can write": it is "unknown", and it fails closed.
  • empty set — nobody can write the object.
  • a set — these identities can write it.

Collapsing null into the empty set would turn an unreadable or unparseable ACL into a
silently accepted deployment. New error codes 1050-1054 carry this:
ERR_ANCHOR_AUTHORIZATION_UNKNOWN (not decidable), ERR_ANCHOR_SERVICE_IDENTITY_INVALID,
ERR_ANCHOR_SERVICE_IDENTITY_MISMATCH, ERR_ANCHOR_WRITER_SET (the writer set is not
exactly {service identity}), ERR_ANCHOR_ADAPTER_UNAVAILABLE.

The Windows adapter deliberately does not fold a group SID into the caller's identity:
Administrators, Users and Everyone mean "ordinary processes can write this", and their members
are not the deployment operator. The DACL owner is counted as a writer too, because the owner
implies WRITE_DAC.

The declared service identity is persisted with the state

The managed recovery entry points run long after the store was opened and from a different
process. Persisting the identity means they apply the same contract instead of whatever
their own caller happened to pass.

Validation

Local:

  • node --test 'tests/coordination/*.test.js' → 622 pass / 0 fail
  • node --test 'tests/governed/*.test.js' → 231 pass / 0 fail
  • node --test 'tests/security/*.test.js' 'tests/runtime-layout/*.test.js' → 58 pass / 0 fail
  • adapter-specific suite → 12 pass / 0 fail

Real Windows host, three DACL shapes (the probe only applies ACLs to its own temporary
directory and deletes it afterwards; no system directory, no install, no elevation, no
service or task, no account creation, no user switching):

shape owner writable set the adapter derives verdict
1 default inheritance Administrators {"*", SYSTEM, current account, Administrators} unusable
2 SYSTEM only Administrators {SYSTEM, Administrators} unusable
3 SYSTEM only SYSTEM {SYSTEM} usable

Shapes 2 and 3 differ only in the owner: an administrator-group owner implies
WRITE_DAC, so the owner is itself a second writer. This gives real-hardware support to
the deployment contract "the anchor domain's owner must not be an administrator group",
which until now was an inference.

Shape 3's same-account write succeeds — that is the administrator-token privilege bypass
already located and reproduced by the privilege-bypass-discriminator probe (the token
carries SeRestorePrivilege and friends; removing them makes the same write fail with
EPERM). The adapter therefore excludes ordinary same-account processes, not an elevated
administrator token — the boundary V6 records, unchanged by this PR.

Evidence: .agent/missions/M-044/evidence/ms003-windows-authorization-adapter-verification-2026-10-26.md.

Scope boundaries (deliberately not touched)

  • No protected service is installed, no service or scheduled task is created, nothing is
    elevated, no system directory ACL is modified
  • No Windows connection for sensitive UIA
  • No user account is created and no login user is switched — the whole M-044 line uses the
    current account and only reads ACLs/SIDs/tokens
  • No SamHMI product code, no release or distribution
  • Submission is by precise path; git add . was never run, and this repo's other agents'
    untracked content is untouched

Status and remaining gate

VC-044-007 stays REVISE. Closing it still requires measuring the ACL on a protected
deployment, which is an installation-time action that this PR does not authorize. The
deployment contract also carries two items that remain unmeasured: the shape with a real
service SID (this host has no registered service SID) and whether a non-administrator
service identity can establish and hold that ACL.

The SamHMI-side product-security posture stays BLOCK; this PR does not change that.

Refs: M-044 / MS-003

cortex-agent added 2 commits October 26, 2026 19:41
M-044 MS-003 的产品源码此前从未进入 origin/main,导致 M-053 侧产品安全无法解除
BLOCK——能力未交付,收敛条件「等待 M-044 出具能力交付签认」永远无法满足。本批
按 Decision D-M044-MS003-PRODUCT-SOURCE-DELIVERY-OPEN 交付。

【受保护 scope 的事务化派发许可存储】

许可、幂等键、桌面 draining 与撤销墓碑在同一数据库事务提交,持久 commit 才返回
许可。一次性许可被消费后,攻击者若把数据库回滚到消费前快照,许可会不会被消费
第二次——这是 VC-044-007 要求检测的性质。

高水位锚点放在数据库回滚域**之外**的锚点域里:journal 追加式记录 intent/commit,
已提交的高水位 H 与数据库自身锚点序列 D 比较,三种情形无歧义(D<H 拒绝、
D>H 是唯一可恢复的崩溃窗口、D==H 时 journal 的 body_digest 必须等于数据库当前
body)。单步回滚产生 D==H-1,永不可恢复,恢复入口因此无法洗白一次回滚。

【平台授权适配层(本批新增)】

原 strict 检查只实现纯 POSIX 语义(mode 位 + st_uid),在两个受支持平台上都不成立:

  Windows  mode 位恒为 0666 且无 st_uid,于是 strict 在目标平台上恒定拒绝,
           什么都没证明;实际授权模型是 DACL。
  macOS    命名 ACL 条目赋予的写权限在 mode 位里看不见,于是带 staff 写权限的
           部署被误判为安全。

适配层把「谁能写」换成平台原生授权模型:POSIX mode 位 / macOS ACL(ls -lde
枚举)/ Windows DACL(Get-Acl + ConvertTo-Json 的结构化 ACE)。判定规则统一为
「可写身份集合 == {声明的服务身份}」,并新增**调用进程身份 == 声明服务身份**的
显式比对——只信「谁在调用」会让检查自证循环,能以服务身份运行的进程按定义就
通过。显式比对把进程冒充变成可检出的失败。

三态严格区分:「判不出来」(null,平台模型无法枚举)不是「安全」,也不是「无人
可写」(空集),一律 fail-closed。相应地新增错误码 1050-1054,其中
ERR_ANCHOR_AUTHORIZATION_UNKNOWN 用于不可判定,ERR_ANCHOR_WRITER_SET 用于可写者
集合不等于 {服务身份}。

Windows 适配器不把组 SID 折叠成调用者身份:Administrators、Users、Everyone 这类
宽组意味着「普通进程也能写」,其成员不是部署操作者;DACL 属主同样计入可写者,
因为属主隐含 WRITE_DAC。

【显式服务身份贯通】

服务身份随状态持久化,因此长期之后、由不同进程调用的三个恢复入口应用同一份
契约,而不是各自调用方恰好传入的那份。

【验证】

本机:coordination 622/622、governed 231/231、security + runtime-layout 58/58
全通过。

Windows 真机对照三个 DACL 形态:默认继承(含当前账号 FullControl)判不可用;
仅 SYSTEM 但属主为 Administrators 判不可用;仅 SYSTEM 且属主为 SYSTEM 判**可用
且可写者恰为 {SYSTEM}**。后两者唯一差别是属主,这为「锚点域属主不得是管理员组」
这条 ACL 契约提供了真机支持。证据见 .agent/missions/M-044/evidence/
ms003-windows-authorization-adapter-verification-2026-10-26.md。

【边界】

本批不安装受保护服务、不创建服务或计划任务、不提权、不修改系统目录 ACL、
不连接 Windows 执行敏感 UIA、不新建用户账号或切换登录用户。VC-044-007 维持
REVISE——闭合它还需要在受保护部署上实测 ACL,而该实测属安装期动作。
@Kucell
Kucell merged commit ea3fa73 into main Oct 26, 2026
2 checks passed
@Kucell
Kucell deleted the codex/m044-ms003-transaction-store branch October 26, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant