Repository navigation
feat(coordination): 受保护 scope 的事务化派发许可存储与平台授权适配层 (M-044/MS-003) - #122
Merged
Merged
Conversation
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,而该实测属安装期动作。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 ofthis 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 markHwith thedatabase's own anchor sequence
Dis unambiguous:D < HD > HD == Hbody_digestmust equal the database bodyA 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), whichis wrong on two of the three supported platforms:
0666and there is nost_uid, so strictrefused every Windows deployment (the target platform) while proving nothing. The real
authorization model is the DACL.
deployment that
staffcould write was accepted as safe.The adapter reads "who can write this object" from the platform's own authorization model:
fs.lstatSyncls -lde(LC_ALL=C)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.
Collapsing
nullinto the empty set would turn an unreadable or unparseable ACL into asilently 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 notexactly {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 failnode --test 'tests/governed/*.test.js'→ 231 pass / 0 failnode --test 'tests/security/*.test.js' 'tests/runtime-layout/*.test.js'→ 58 pass / 0 failReal 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):
"*", SYSTEM, current account, Administrators}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 tothe 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-discriminatorprobe (the tokencarries
SeRestorePrivilegeand friends; removing them makes the same write fail withEPERM). 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)
elevated, no system directory ACL is modified
current account and only reads ACLs/SIDs/tokens
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