release: add one-click sole reviewer signing

This commit is contained in:
2026-09-27 09:54:02 +08:00
parent 74da61a9f1
commit 1a8657fcce
12 changed files with 3438 additions and 66 deletions
+2
View File
@@ -73,4 +73,6 @@ Do not reintroduce the old root `apps/`、`services/`、`packages/`、`sdks/`、
8. **提速不能绕过底线。** 身份与租户隔离、合同事实完整性、版本保护、备份恢复、迁移兼容、TLS/密钥、失败接管、正式政策及最终公众切流授权不得为赶工而取消。
9. **单一人工发布审核人。** 本轮唯一人工发布审核人为陈钰麒(总经理);技术门禁、数据库/备份/恢复核验和证据比对由系统自动完成,不再追加第二名发布审核人。60 资产+14 Prompt 只作一次批次签名批准,系统生成 74 项应用证据;Provider、公开政策、恢复与回退也只接受该审核人的具名决定,其中每次恢复或回退只接受一条 `release_owner` 批准。离线根密钥与日常审批密钥必须用途隔离且不得复用。两名普通 UAT 账号只是租户隔离测试身份,不是审核人;租户自己的业务审批策略不受本条改变。
RC-06 审核人只使用两个无复杂参数入口:`yuqei-infra/scripts/Initialize-ReleaseSigner.cmd` 完成一次性加密密钥初始化,候选和 RC-05 材料齐备后使用 `yuqei-infra/scripts/Approve-ReleaseCandidate.cmd` 核对一页摘要并签署一次;不得手工编辑 JSON、hash 或 pin。详见 [`project-docs/RC06-single-reviewer-one-click-signing-runbook-2026-09-27.md`](project-docs/RC06-single-reviewer-one-click-signing-runbook-2026-09-27.md)。工具代码存在不代表真实密钥或批准已经形成。
本轮收口唯一执行顺序是 `FREEZE → BUILD → RC05-RUN → RC06-UAT → RC07-RECOVERY → RC08-PRODUCTION`。在真实证据形成前,内部受控试点和公众开放均保持 `NO_GO`;不得把本地测试、AI 自动审核或模拟证据描述为法律批准、第三方存证或公众生产放行。效率规则不构成生产操作的长期授权;生产部署、迁移、回退、切流、真实凭据或数据使用、风险接受及法律签署仍须具名授权人明确批准。
@@ -67,21 +67,21 @@
- 每场景三个自动质量字段必须显式为 true,human/legal 字段必须明确保持未完成,`not_legal_approval=true`。
- 历史 `release_eligible` 仅接受 provider succeeded、非 timeout、business succeeded/resolved。
- 冻结源码和数据传递闭包先以安全文件描述符固定到私有临时树,再从固定字节加载执行;不再执行校验后的可变工作树模块。
- v3 只接受陈钰麒对绑定真实 60 资产、14 Prompt、31 项处置及候选/RC-05 身份的一个批次作一次 Ed25519 签名批准;审批 keyring 必须由冻结 pin 对应的离线根密钥签发,发布执行过程须由冻结 pin 对应的服务密钥签名 74 项 apply result 和在线 hash。验证器逐项核验,旧 schema、无根信任、无服务签名或其他审核人均硬拒绝。
- approval envelope v4 / payload v3 只接受陈钰麒对绑定真实 60 资产、14 Prompt、31 项处置及候选/RC-05 身份的一个批次作一次 Ed25519 签名批准;签名同时绑定 manifest 原始文件 SHA、payload SHA、确定性单页审阅摘要 SHA、候选精确 keyring epoch 和 root 签 keyring payload SHA。审批 keyring 必须由冻结 pin 对应的离线根密钥签发,并在根签 payload 中授权该候选的精确 manifest 原始 SHA;源码只固定长期 root/apply pin 和候选精确 epoch,不把候选专属 keyring payload 回写源码形成哈希循环。任何 keyring 轮换或撤销都必须提升 epoch、作废原候选并重新冻结。发布执行过程须由冻结 pin 对应的服务密钥签名 74 项 apply result 和在线 hash。验证器逐项核验,旧 schema、无根信任、跨候选 keyring、无服务签名或其他审核人均硬拒绝。
- 单审核人本机工具提供两个无复杂参数入口:`Initialize-ReleaseSigner.cmd` 仅首次生成加密 PKCS#8 审批密钥,`Approve-ReleaseCandidate.cmd` 自动发现唯一待审请求、展示候选/60+14+31/RC-05 摘要、要求 6 位批准码和本人口令,签后立即调用正式验证器自验。入口只选取带 Python Software Foundation 有效签名并通过密码库预检的本机离线运行时,以 `-I -S -B` 隔离启动;20 字符长句口令、私钥及锁文件 owner/DACL、原子禁止覆盖写入、过期请求自动归档、签后请求归档及重复点击复验均由工具处理。该脚本工具不宣称抵御已控制当前 Windows 账户的恶意代码;正式操作仍以干净离线主机和固定 Python/Python DLL/cryptography 闭包 digest 为外部运行环境门禁。私钥、口令、真实签名和收据不进入源码树;根密钥和 apply 服务密钥仍是用途隔离的技术设施,不是额外审核人。操作说明见 `project-docs/RC06-single-reviewer-one-click-signing-runbook-2026-09-27.md`。
### 验证
- Windows RC-06/RC-07 联合套件:64 passed,1 skipped,0 failed。
- Linux `192.168.3.62`:RC-06 安全读取器符号链接回归 1/1 passed。
- Linux 使用的最终文件 SHA-256:
- `build-rc06-publication-batch.py`: `92d1138478c16c6ea2da57715848d0727992bf922ce2c495bc36206fc0b8efa8`
- `test_rc06_publication_batch.py`: `2bccb26b9a7fd3509b1c6550eea426ac7e940db3b90c3b923204cfa57221a2e6`
- 当前开发态 Windows 定向回归:RC-06+release manifest 共 101 passed,1 个 Windows 不支持符号链接的条件用例 skipped,0 failed;这不是冻结候选的正式证据。
- Linux `192.168.3.62` 的既有 RC-06 安全读取器符号链接回归曾为 1/1 passed;新候选形成后必须对同一不可变文件重新执行并记录正式 evidence。
- 当前仍在 BUILD-05 源码收口,按强制交付规则不记录“最终文件 SHA”或生成不可变证据;只在唯一候选重新冻结后生成。
### 未完成
- RC-05 正式真实矩阵终态不存在。
- 陈钰麒对 60 资产+14 Prompt 精确 hash 的一次批次签名批准尚不存在,系统据此生成的 74 项 apply receipt 和在线 hash 快照也不存在。
- RC-06 离线根公钥、当前审批 keyring payload 和 apply 服务公钥的冻结 pin 尚未配置;在新候选冻结前验证器会保持 fail-closed。
- RC-06 离线根公钥、候选精确 keyring epoch 和 apply 服务公钥的冻结配置,以及根签候选专属 keyring,均尚未形成;在新候选冻结和 manifest 形成前验证器会保持 fail-closed。任何 keyring 轮换或撤销都必须变更精确 epoch、作废原候选并重新冻结,旧 epoch 不可重放。
- 一键工具已具备初始化、系统准备待审请求、单页摘要、交互签署与自验能力,但本轮未运行真实初始化或签署;当前不存在可签的正式待审请求。
- 1 个起草 Prompt+8 个复核 Prompt 的真实运行时可执行快照不存在。
- 管理员+2 名普通成员、2 个工作区的完整 API/UI UAT 未执行。
@@ -0,0 +1,75 @@
# RC-06 单审核人一键初始化与签署操作说明
更新时间:2026-09-27
## 1. 适用范围与当前状态
本工具只处理 RC-06 的一个精确发布批次:60 个合同资产、14 个 Prompt 模块和 31 项处置结论。唯一人工审核人为陈钰麒(总经理)。离线根密钥和 apply 服务密钥由系统按用途隔离管理,它们不是人工审核人。
当前没有生成真实审核私钥、正式签名、候选 tag、发布收据或生产授权。内部试点、UAT、生产及公众开放继续 `NO_GO`。一次 RC-06 签名不等于资产已经发布,也不等于授权公众生产切流。
## 2. 审核人只需要执行的两个入口
### 2.1 首次初始化
候选冻结前,由陈钰麒在受控 Windows 电脑上双击:
`yuqei-infra\scripts\Initialize-ReleaseSigner.cmd`
工具会:
1. 将加密 Ed25519 审批私钥保存在当前 Windows 用户的 `%LOCALAPPDATA%\Yuqei\ReleaseSigner\keys`;
2. 要求输入并再次确认不少于 20 个字符、非纯数字且不可过于简单的长句口令;
3. 生成可交给系统使用的公钥注册材料和公钥指纹;
4. 拒绝把私钥写入源码仓库、OneDrive、网络目录、符号链接或不属于当前账户的目录,并将目录、私钥和操作锁的 owner/DACL 收紧到当前账户与 SYSTEM;
5. 重复运行时验证已有密钥,不覆盖或偷偷换钥。
口令只在本机遮罩输入,不通过命令行、环境变量、密码文件、聊天或日志传递。私钥不得上传仓库、服务器、邮件、聊天、共享盘或 CI artifact。
双击入口只选择本机已安装、带 Python Software Foundation 有效签名且具备所需密码库的离线 Python 运行时;以 `-I -S -B` 隔离模式启动,忽略 `PYTHONPATH`、user-site、`sitecustomize` 和安装器别名,不联网安装或更新运行时。若不存在合格运行时,工具会在输入口令前停止。
### 2.2 最终批次签署
只有在系统已配置长期 root/apply-service 公钥指纹和候选精确 keyring epoch、形成唯一 commit/tag/source manifest、由离线根签发绑定该 manifest 原始 SHA 的候选专属 keyring,并完成同一候选 BUILD 与 RC-05 后,系统才会在本机 signer inbox 放入唯一待审请求。届时由陈钰麒双击:
`yuqei-infra\scripts\Approve-ReleaseCandidate.cmd`
工具会自动校验候选、root 签名 keyring、keyring 对精确 manifest 原始 SHA 的授权、冻结 root/apply pin、epoch、时窗、60/14/31 清单及 RC-05 终态,然后显示一页中文摘要。陈钰麒只需:
1. 核对候选 commit/tag、manifest 原始 SHA、payload SHA、60/14/31 数量和 RC-05 状态;
2. 输入摘要显示的 6 位批准码;
3. 输入本人审核密钥口令一次。
工具在批准码和口令输入完成后重新取得当前时间并重读全部材料,生成最长 24 小时的批准,再自动裁剪到请求、审批密钥、keyring 和全部风险接受的最早到期时间;用户不能手工填写审批时间或身份。签名写出前会调用正式 RC-06 验证器自验,并以完整 staging+禁止覆盖的原子发布写出收据。系统会先认证并归档不同候选留下的过期请求;失败、取消、错误口令、文件漂移、多个仍有效请求或 pin 未配置都不会留下正式收据。
成功后待审请求自动移入 `processed`,不会阻塞下一候选。重复双击会自动复验已有收据并提示“此前已签署,无需重复操作”,不会再次签名或覆盖文件。
## 3. 系统自动完成的工作
- 生成并管理与审核密钥不同的离线根密钥和 apply 服务密钥;
- 在源码冻结前固定长期 root 公钥、候选精确 keyring epoch 和 apply 服务公钥指纹;任何 keyring 轮换或撤销都必须使原候选失效并重新冻结;
- 在 manifest 形成后,用根密钥签发只包含陈钰麒审批公钥、并授权该 manifest 原始 SHA 的候选专属 trusted keyring;keyring payload 不写回源码,避免候选 commit 与 keyring 形成哈希循环;
- 生成不可变 RC-06 manifest 和待审请求;
- 用户签名后验证 approval v4 / payload v3;payload 同时绑定候选精确 keyring epoch 和 root 签 keyring payload SHA;
- 后续通过业务 API 应用 74 项内容,并由服务密钥签署 74 项机器结果和在线 hash;
- 继续验证 1 个起草+8 个审查运行时 Prompt 快照以及 RC-06 UAT。
## 4. 不得执行的操作
- 不得手工编辑 manifest、request、keyring、approval、SHA 或签名 JSON;
- 不得把 payload SHA 当作 manifest 原始文件 SHA;
- 不得在候选冻结后修改 pin 或源码;
- 不得复用审核私钥作为离线根密钥或 apply 服务密钥;
- 不得把本地初始化、自动测试或一次 RC-06 签名描述为正式政策批准、第三方存证、司法效力证明或公众生产放行。
## 5. 运行环境信任边界
`-I -S -B`、Python Software Foundation 签名检查和本机 ACL 用于减少错误运行时、环境变量注入、跨账户读取及普通文件漂移;它们不等同于受操作系统保护的代码签名发布程序,也不能抵御已经控制当前 Windows 账户、能够键盘注入或篡改用户可写 Python/密码库的恶意进程。
因此,正式初始化和签署必须在发布负责人确认的干净离线 Windows 主机上执行,并在候选证据中记录实际 Python、Python DLL 和 cryptography 完整导入闭包的固定 digest。若要把“当前账户已失陷”纳入防护范围,必须另行交付代码签名 EXE/MSI 并安装到受保护目录;本 CMD/PowerShell/Python 工具不得被描述为具备该防护能力。
## 6. 正确顺序
`审核密钥初始化 → 固定长期 root/apply pin 与候选精确 epoch → 唯一 commit/tag 冻结 → BUILD → RC05-RUN → manifest 形成 → 系统根签候选专属 keyring 与待审请求 → 陈钰麒一次签署 → 自动验签和 74 项应用证据 → RC06-UAT`
若 inbox 没有请求,工具不会生成批准;若存在不同候选的旧过期请求,工具会认证后自动归档;若仍存在多个有效请求,工具必须拒绝猜测。陈钰麒不需要手工配置或删除文件。
@@ -0,0 +1,17 @@
@echo off
setlocal
chcp 65001 >nul
set "launcher=%~dp0Launch-ReleaseSigner.ps1"
set "powershell=%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe"
if not exist "%powershell%" (
echo 启动失败:系统缺少受信任的 Windows PowerShell。
echo 未创建候选批准,请将此窗口截图交给系统处理。
pause
exit /b 2
)
"%powershell%" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%launcher%" sign
set "result=%ERRORLEVEL%"
echo.
if not "%result%"=="0" echo 签署未完成,未创建新的候选批准。
pause
exit /b %result%
@@ -0,0 +1,17 @@
@echo off
setlocal
chcp 65001 >nul
set "launcher=%~dp0Launch-ReleaseSigner.ps1"
set "powershell=%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe"
if not exist "%powershell%" (
echo 启动失败:系统缺少受信任的 Windows PowerShell。
echo 未创建审核密钥,请将此窗口截图交给系统处理。
pause
exit /b 2
)
"%powershell%" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%launcher%" initialize
set "result=%ERRORLEVEL%"
echo.
if not "%result%"=="0" echo 初始化未完成,未创建审核密钥或候选批准。
pause
exit /b %result%
@@ -0,0 +1,90 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[ValidateSet("initialize", "sign", "runtime-check")]
[string]$Command
)
$ErrorActionPreference = "Stop"
$env:PSModulePath = @(
(Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\Modules")
(Join-Path $env:ProgramFiles "WindowsPowerShell\Modules")
) -join ";"
function Get-TrustedPythonCandidates {
$candidatePaths = [System.Collections.Generic.List[string]]::new()
foreach ($pattern in @(
(Join-Path $env:LOCALAPPDATA "Python\pythoncore-*\python.exe")
(Join-Path $env:LOCALAPPDATA "Programs\Python\Python*\python.exe")
(Join-Path $env:ProgramFiles "Python*\python.exe")
)) {
Get-ChildItem -Path $pattern -File -ErrorAction SilentlyContinue |
ForEach-Object { $candidatePaths.Add($_.FullName) }
}
foreach ($registryRoot in @(
"Registry::HKEY_CURRENT_USER\Software\Python\PythonCore"
"Registry::HKEY_LOCAL_MACHINE\Software\Python\PythonCore"
)) {
Get-ChildItem -LiteralPath $registryRoot -ErrorAction SilentlyContinue |
ForEach-Object {
$properties = Get-ItemProperty -LiteralPath (Join-Path $_.PSPath "InstallPath") -ErrorAction SilentlyContinue
if ($properties.ExecutablePath) {
$candidatePaths.Add([string]$properties.ExecutablePath)
} elseif ($properties.'(default)') {
$candidatePaths.Add((Join-Path ([string]$properties.'(default)') "python.exe"))
}
}
}
$trusted = foreach ($candidatePath in $candidatePaths | Sort-Object -Unique) {
if (-not (Test-Path -LiteralPath $candidatePath -PathType Leaf)) { continue }
$item = Get-Item -LiteralPath $candidatePath -Force
if (($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) { continue }
if ($item.FullName -like "*\Microsoft\WindowsApps\*") { continue }
$version = [version]::new(
[Math]::Max(0, $item.VersionInfo.FileMajorPart),
[Math]::Max(0, $item.VersionInfo.FileMinorPart),
[Math]::Max(0, $item.VersionInfo.FileBuildPart),
[Math]::Max(0, $item.VersionInfo.FilePrivatePart)
)
if ($version -lt [version]"3.11") { continue }
$signature = Get-AuthenticodeSignature -LiteralPath $item.FullName
if (
$signature.Status -ne [System.Management.Automation.SignatureStatus]::Valid -or
$null -eq $signature.SignerCertificate -or
$signature.SignerCertificate.Subject -notlike "*CN=Python Software Foundation*"
) { continue }
[pscustomobject]@{ Path = $item.FullName; Version = $version }
}
return $trusted | Sort-Object Version -Descending
}
try {
$signerScript = Join-Path $PSScriptRoot "rc06-single-reviewer-signing.py"
if (-not (Test-Path -LiteralPath $signerScript -PathType Leaf)) {
throw "The release signer program is missing"
}
Remove-Item Env:PYTHONPATH -ErrorAction SilentlyContinue
Remove-Item Env:PYTHONHOME -ErrorAction SilentlyContinue
Remove-Item Env:PYTHONSTARTUP -ErrorAction SilentlyContinue
Remove-Item Env:PYTHONUSERBASE -ErrorAction SilentlyContinue
$runtime = $null
$ErrorActionPreference = "Continue"
foreach ($candidate in @(Get-TrustedPythonCandidates)) {
$preflightOutput = @(& $candidate.Path -I -S -B $signerScript runtime-check 2>&1)
if ($LASTEXITCODE -eq 0) {
$runtime = $candidate
break
}
}
if ($null -eq $runtime) {
$ErrorActionPreference = "Stop"
throw "No trusted offline Python runtime has the required cryptography dependency"
}
& $runtime.Path -I -S -B $signerScript $Command
exit $LASTEXITCODE
} catch {
Write-Host ("Signer startup failed: " + $_.Exception.Message) -ForegroundColor Red
Write-Host "No reviewer key or candidate approval was created."
exit 2
}
@@ -31,20 +31,22 @@ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
SCHEMA_VERSION = "yuqei.rc06-publication-batch.v3"
DISPOSITION_SCHEMA_VERSION = "yuqei.rc06-golden-dispositions.v2"
IMAGE_SCHEMA_VERSION = "yuqei.rc06-image-identities.v1"
APPROVAL_SCHEMA_VERSION = "yuqei.rc06-publication-batch-approval.v3"
APPROVAL_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-publication-batch-approval-payload.v1"
APPROVAL_KEYRING_SCHEMA_VERSION = "yuqei.rc06-publication-approval-keyring.v2"
APPROVAL_SCHEMA_VERSION = "yuqei.rc06-publication-batch-approval.v4"
APPROVAL_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-publication-batch-approval-payload.v3"
APPROVAL_REVIEW_SUMMARY_SCHEMA_VERSION = "yuqei.rc06-single-reviewer-summary.v1"
APPROVAL_KEYRING_SCHEMA_VERSION = "yuqei.rc06-publication-approval-keyring.v3"
APPLY_SCHEMA_VERSION = "yuqei.rc06-publication-system-item-apply-receipt.v3"
APPLY_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-publication-system-item-apply-payload.v1"
APPROVAL_SIGNATURE_DOMAIN = b"YUQEI_RC06_PUBLICATION_BATCH_APPROVAL_V1\0"
APPROVAL_KEYRING_SIGNATURE_DOMAIN = b"YUQEI_RC06_APPROVAL_KEYRING_V1\0"
APPLY_SIGNATURE_DOMAIN = b"YUQEI_RC06_SYSTEM_APPLY_RECEIPT_V1\0"
TRUSTED_APPROVAL_ROOT_KEY_ID = "yuqei-rc06-approval-root-v1"
# Provision these immutable pins only when the source candidate is frozen. Empty
# values deliberately keep approval/apply validation fail-closed in development.
# Provision the long-lived root/apply pins and exact candidate keyring epoch
# before source freeze. A root-signed keyring then authorizes the exact frozen
# manifest raw SHA without creating a source/keyring hash cycle. Rotation or
# revocation requires a new epoch and therefore a new frozen candidate.
TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256 = ""
TRUSTED_APPROVAL_KEYRING_PAYLOAD_SHA256 = ""
MIN_APPROVAL_KEYRING_EPOCH = 0
FROZEN_APPROVAL_KEYRING_EPOCH = 0
TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256 = ""
RC05_SUMMARY_SCHEMA_VERSION = "multiscene-evaluation-run.v1"
RC05_LEDGER_SCHEMA_VERSION = "multiscene-call-ledger.v1"
@@ -131,6 +133,7 @@ GOLDEN_INVENTORY_PATH = (
)
FROZEN_IMPLEMENTATION_PATHS = (
"yuqei-infra/scripts/build-rc06-publication-batch.py",
"yuqei-infra/scripts/rc06-single-reviewer-signing.py",
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api/contract_templates.py",
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api/contract_scene_assets.py",
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api/template_inputs.py",
@@ -2376,16 +2379,198 @@ def validate_manifest(payload: Any) -> dict[str, Any]:
return manifest
def build_approval_review_summary(
payload: Any,
*,
manifest_raw_sha256: str,
) -> dict[str, Any]:
"""Build the exact, human-readable projection approved by the sole reviewer."""
manifest = validate_manifest(payload)
candidate = manifest["candidate"]
terminal = candidate["rc05_terminal_evidence"]
manifest_raw_sha256 = _require_sha(
manifest_raw_sha256,
"publication batch raw SHA-256",
)
summary = {
"schema_version": APPROVAL_REVIEW_SUMMARY_SCHEMA_VERSION,
"decision_scope": "approve_exact_rc06_publication_batch",
"reviewer": dict(SOLE_RELEASE_REVIEWER),
"candidate": {
"commit": candidate["commit"],
"tag": candidate["tag"],
"source_manifest_sha256": candidate["source_manifest_sha256"],
"source_manifest_payload_sha256": candidate["source_manifest_payload_sha256"],
"image_identities_sha256": candidate["image_identities_sha256"],
"image_identity_set_sha256": candidate["image_identity_set_sha256"],
"rc05_plan_sha256": candidate["rc05_plan_sha256"],
"rc05_summary_raw_sha256": terminal["summary_raw_sha256"],
"rc05_ledger_identity_raw_sha256": terminal["ledger_identity_raw_sha256"],
"rc05_campaign_identity_raw_sha256": terminal["campaign_identity_raw_sha256"],
"rc05_complete_real_green": terminal["complete_real_green"],
},
"batch": {
"asset_count": manifest["asset_batch"]["count"],
"asset_inventory_sha256": manifest["asset_batch"]["inventory_sha256"],
"prompt_module_count": manifest["prompt_module_batch"]["count"],
"prompt_module_inventory_sha256": manifest["prompt_module_batch"]["inventory_sha256"],
"golden_disposition_count": manifest["golden_dispositions"]["count"],
"golden_disposition_counts_by_status": manifest["golden_dispositions"]["counts_by_status"],
"golden_disposition_inventory_sha256": manifest["golden_dispositions"]["inventory_sha256"],
},
"manifest_raw_sha256": manifest_raw_sha256,
"manifest_payload_sha256": manifest["manifest_payload_sha256"],
"approval_validity_max_hours": int(MAX_APPROVAL_WINDOW.total_seconds() // 3600),
"remaining_controls_after_approval": list(BLOCKED_CONTROLS[1:]),
"claims_not_made": [
"This approval does not itself publish any asset or Prompt module.",
"This approval does not authorize public production traffic cutover.",
"System apply evidence and executable runtime Prompt snapshots remain separate gates.",
],
}
_assert_no_secret_material(summary, "approval review summary")
return summary
def _approval_risk_acceptance_deadline(manifest: Mapping[str, Any]) -> datetime | None:
"""Return the earliest expiry across scoped Golden risk acceptances."""
deadlines = [
_parse_time(
item["risk_acceptance"]["expires_at"],
f"Golden disposition {item['sample_id']} risk acceptance expires_at",
)
for item in manifest["golden_dispositions"]["items"]
if item["status"] == "scoped_internal_risk_acceptance"
]
return min(deadlines) if deadlines else None
def _validate_disposition_approval_window(
manifest: Mapping[str, Any],
*,
approved_at: datetime,
expires_at: datetime,
) -> None:
"""Ensure every disposition decision and exception covers the approval window."""
for item in manifest["golden_dispositions"]["items"]:
if item["status"] == "unresolved":
raise PublicationBatchError(
"approval cannot release a batch with unresolved Golden dispositions"
)
decided_at = _parse_time(
item["decided_at"],
f"Golden disposition {item['sample_id']} decided_at",
)
if decided_at > approved_at:
raise PublicationBatchError(
f"Golden disposition {item['sample_id']} was decided after the approval time"
)
if item["status"] != "scoped_internal_risk_acceptance":
continue
risk_expires_at = _parse_time(
item["risk_acceptance"]["expires_at"],
f"Golden disposition {item['sample_id']} risk acceptance expires_at",
)
if approved_at >= risk_expires_at:
raise PublicationBatchError(
f"Golden disposition {item['sample_id']} risk acceptance expired before approval"
)
if expires_at > risk_expires_at:
raise PublicationBatchError(
f"approval validity exceeds Golden disposition {item['sample_id']} risk acceptance"
)
def build_approval_payload(
manifest: Any,
*,
manifest_raw_sha256: str,
key_id: str,
approval_keyring_epoch: int,
approval_keyring_payload_sha256: str,
approved_at: datetime,
expires_at: datetime,
) -> dict[str, Any]:
"""Build the only approval payload accepted for the exact validated batch."""
validated = validate_manifest(manifest)
normalized_key_id = _require_string(key_id, "approval key_id", max_length=128)
if not STABLE_ID_RE.fullmatch(normalized_key_id):
raise PublicationBatchError("approval key_id is invalid")
if (
not isinstance(approval_keyring_epoch, int)
or isinstance(approval_keyring_epoch, bool)
or approval_keyring_epoch < 1
):
raise PublicationBatchError("approval keyring epoch is invalid")
normalized_keyring_payload_sha256 = _require_sha(
approval_keyring_payload_sha256,
"approval keyring payload SHA-256",
)
if approved_at.tzinfo is None or approved_at.utcoffset() is None:
raise PublicationBatchError("approval approved_at must include a timezone")
if expires_at.tzinfo is None or expires_at.utcoffset() is None:
raise PublicationBatchError("approval expires_at must include a timezone")
if expires_at <= approved_at or expires_at - approved_at > MAX_APPROVAL_WINDOW:
raise PublicationBatchError(
"approval validity must be greater than zero and no longer than seven days"
)
if not validated["publication_control"]["golden_dispositions_complete"]:
raise PublicationBatchError("approval cannot release a batch with unresolved Golden dispositions")
_validate_disposition_approval_window(
validated,
approved_at=approved_at,
expires_at=expires_at,
)
manifest_raw_sha256 = _require_sha(
manifest_raw_sha256,
"publication batch raw SHA-256",
)
review_summary = build_approval_review_summary(
validated,
manifest_raw_sha256=manifest_raw_sha256,
)
return {
"schema_version": APPROVAL_PAYLOAD_SCHEMA_VERSION,
"batch_manifest_raw_sha256": manifest_raw_sha256,
"batch_manifest_payload_sha256": validated["manifest_payload_sha256"],
"decision": "approved",
"approved_at": approved_at.isoformat(timespec="seconds"),
"expires_at": expires_at.isoformat(timespec="seconds"),
"key_id": normalized_key_id,
"approval_keyring_epoch": approval_keyring_epoch,
"approval_keyring_payload_sha256": normalized_keyring_payload_sha256,
"approver": {**SOLE_RELEASE_REVIEWER, "human_confirmed": True},
"asset_payload_sha256s": {
item["template_id"]: item["asset_payload_sha256"]
for item in validated["asset_batch"]["items"]
},
"prompt_module_payload_sha256s": {
item["key"]: item["module_payload_sha256"]
for item in validated["prompt_module_batch"]["items"]
},
"golden_disposition_inventory_sha256": validated["golden_dispositions"][
"inventory_sha256"
],
"review_summary_sha256": _sha256_json(review_summary),
}
def _require_sole_release_reviewer(value: Any, label: str) -> dict[str, Any]:
reviewer = _require_keys(
value,
label,
("approver_id", "name", "role", "organization", "human_confirmed"),
)
actual = {
field: _require_string(reviewer[field], f"{label} {field}", max_length=256)
for field in ("approver_id", "name", "role", "organization")
}
actual = {}
for field in ("approver_id", "name", "role", "organization"):
normalized = _require_string(reviewer[field], f"{label} {field}", max_length=256)
if reviewer[field] != normalized:
raise PublicationBatchError(f"{label} {field} must be exact canonical text")
actual[field] = normalized
if actual != SOLE_RELEASE_REVIEWER:
raise PublicationBatchError(f"{label} must be the configured sole release reviewer")
if reviewer["human_confirmed"] is not True:
@@ -2422,7 +2607,8 @@ def _validate_approval_keyring(
keyring,
"approval keyring",
(
"schema_version", "root_key_id", "epoch", "issued_at", "expires_at", "keys",
"schema_version", "root_key_id", "epoch", "issued_at", "expires_at",
"authorized_batch_manifest_raw_sha256", "keys",
"keyring_payload_sha256", "root_signature_base64",
),
)
@@ -2431,9 +2617,14 @@ def _validate_approval_keyring(
unsigned = {
field: trusted[field]
for field in (
"schema_version", "root_key_id", "epoch", "issued_at", "expires_at", "keys"
"schema_version", "root_key_id", "epoch", "issued_at", "expires_at",
"authorized_batch_manifest_raw_sha256", "keys",
)
}
_require_sha(
trusted["authorized_batch_manifest_raw_sha256"],
"approval keyring authorized batch manifest raw SHA-256",
)
payload_sha256 = _require_sha(
trusted["keyring_payload_sha256"],
"approval keyring payload SHA-256",
@@ -2444,10 +2635,6 @@ def _validate_approval_keyring(
raise PublicationBatchError("approval root public key pin is not provisioned")
if _sha256_bytes(_public_key_raw(root_public_key)) != TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256:
raise PublicationBatchError("approval root public key does not match the frozen pin")
if not HEX64_RE.fullmatch(TRUSTED_APPROVAL_KEYRING_PAYLOAD_SHA256):
raise PublicationBatchError("approval keyring payload pin is not provisioned")
if payload_sha256 != TRUSTED_APPROVAL_KEYRING_PAYLOAD_SHA256:
raise PublicationBatchError("approval keyring is not the currently trusted revocation state")
if trusted["root_key_id"] != TRUSTED_APPROVAL_ROOT_KEY_ID:
raise PublicationBatchError("approval keyring uses the wrong root key")
epoch = trusted["epoch"]
@@ -2455,13 +2642,13 @@ def _validate_approval_keyring(
not isinstance(epoch, int)
or isinstance(epoch, bool)
or epoch < 1
or not isinstance(MIN_APPROVAL_KEYRING_EPOCH, int)
or isinstance(MIN_APPROVAL_KEYRING_EPOCH, bool)
or MIN_APPROVAL_KEYRING_EPOCH < 1
or not isinstance(FROZEN_APPROVAL_KEYRING_EPOCH, int)
or isinstance(FROZEN_APPROVAL_KEYRING_EPOCH, bool)
or FROZEN_APPROVAL_KEYRING_EPOCH < 1
):
raise PublicationBatchError("approval keyring epoch policy is not provisioned")
if epoch < MIN_APPROVAL_KEYRING_EPOCH:
raise PublicationBatchError("approval keyring epoch is older than the trusted minimum")
if epoch != FROZEN_APPROVAL_KEYRING_EPOCH:
raise PublicationBatchError("approval keyring epoch does not match the frozen candidate")
issued_at = _parse_time(trusted["issued_at"], "approval keyring issued_at")
expires_at = _parse_time(trusted["expires_at"], "approval keyring expires_at")
if expires_at <= issued_at or approved_at < issued_at or approved_at >= expires_at:
@@ -2535,6 +2722,7 @@ def _validate_approval_keyring(
def validate_approval_receipt(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
receipt: Any,
keyring: Any,
root_public_key: Ed25519PublicKey,
@@ -2550,16 +2738,24 @@ def validate_approval_receipt(
envelope["payload"],
"approval payload",
(
"schema_version", "batch_manifest_payload_sha256", "decision", "approved_at",
"expires_at", "key_id", "approver", "asset_payload_sha256s",
"schema_version", "batch_manifest_raw_sha256", "batch_manifest_payload_sha256",
"decision", "approved_at", "expires_at", "key_id",
"approval_keyring_epoch", "approval_keyring_payload_sha256", "approver",
"asset_payload_sha256s",
"prompt_module_payload_sha256s", "golden_disposition_inventory_sha256",
"evidence_sha256",
"review_summary_sha256",
),
)
if payload["schema_version"] != APPROVAL_PAYLOAD_SCHEMA_VERSION or payload["decision"] != "approved":
raise PublicationBatchError("approval receipt is not an approved RC-06 batch receipt")
if payload["batch_manifest_payload_sha256"] != manifest["manifest_payload_sha256"]:
raise PublicationBatchError("approval receipt is not bound to this batch")
normalized_manifest_raw_sha256 = _require_sha(
manifest_raw_sha256,
"publication batch raw SHA-256",
)
if payload["batch_manifest_raw_sha256"] != normalized_manifest_raw_sha256:
raise PublicationBatchError("approval receipt is not bound to the exact manifest file")
approved_at = _parse_time(payload["approved_at"], "approval approved_at")
expires_at = _parse_time(payload["expires_at"], "approval expires_at")
if expires_at <= approved_at or expires_at - approved_at > MAX_APPROVAL_WINDOW:
@@ -2579,15 +2775,43 @@ def validate_approval_receipt(
raise PublicationBatchError("approval receipt Prompt identities drift")
if payload["golden_disposition_inventory_sha256"] != manifest["golden_dispositions"]["inventory_sha256"]:
raise PublicationBatchError("approval receipt Golden disposition identity drift")
_require_sha(payload["evidence_sha256"], "approval evidence SHA-256")
review_summary_sha256 = _require_sha(
payload["review_summary_sha256"],
"approval review summary SHA-256",
)
expected_review_summary_sha256 = _sha256_json(
build_approval_review_summary(
manifest,
manifest_raw_sha256=normalized_manifest_raw_sha256,
)
)
if review_summary_sha256 != expected_review_summary_sha256:
raise PublicationBatchError("approval receipt does not match the exact review summary")
if not manifest["publication_control"]["golden_dispositions_complete"]:
raise PublicationBatchError("approval cannot release a batch with unresolved Golden dispositions")
_validate_disposition_approval_window(
manifest,
approved_at=approved_at,
expires_at=expires_at,
)
trusted_keys = _validate_approval_keyring(
keyring,
root_public_key=root_public_key,
approved_at=approved_at,
)
if payload["approval_keyring_epoch"] != keyring["epoch"]:
raise PublicationBatchError("approval receipt keyring epoch drift")
if _require_sha(
payload["approval_keyring_payload_sha256"],
"approval receipt keyring payload SHA-256",
) != keyring["keyring_payload_sha256"]:
raise PublicationBatchError("approval receipt keyring payload identity drift")
if keyring["authorized_batch_manifest_raw_sha256"] != normalized_manifest_raw_sha256:
raise PublicationBatchError("approval keyring does not authorize the exact batch manifest")
keyring_expires_at = _parse_time(keyring["expires_at"], "approval keyring expires_at")
if expires_at > keyring_expires_at:
raise PublicationBatchError("approval validity exceeds the trusted keyring window")
key_id = _require_string(payload["key_id"], "approval key_id", max_length=128)
matches = [
item
@@ -2617,6 +2841,7 @@ def validate_approval_receipt(
def validate_apply_receipt(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval: Mapping[str, Any],
approval_keyring: Mapping[str, Any],
approval_root_public_key: Ed25519PublicKey,
@@ -2626,6 +2851,7 @@ def validate_apply_receipt(
) -> dict[str, Any]:
validate_approval_receipt(
manifest,
manifest_raw_sha256,
approval,
approval_keyring,
approval_root_public_key,
@@ -2655,7 +2881,7 @@ def validate_apply_receipt(
_require_string(row["environment_id"], "apply environment_id", max_length=256)
applied_at = _parse_time(row["applied_at"], "apply applied_at")
approval_payload = approval["payload"]
if applied_at < _parse_time(approval_payload["approved_at"], "approval approved_at") or applied_at > _parse_time(
if applied_at < _parse_time(approval_payload["approved_at"], "approval approved_at") or applied_at >= _parse_time(
approval_payload["expires_at"], "approval expires_at"
):
raise PublicationBatchError("apply receipt was generated outside the approval window")
@@ -2871,7 +3097,7 @@ def main(argv: list[str] | None = None) -> int:
approval_parser = subparsers.add_parser("validate-approval", help="validate a separate approval receipt")
approval_parser.add_argument("--manifest", type=Path, required=True)
approval_parser.add_argument("--manifest-sha256")
approval_parser.add_argument("--manifest-sha256", required=True)
approval_parser.add_argument("--approval", type=Path, required=True)
approval_parser.add_argument("--approval-sha256", required=True)
approval_parser.add_argument("--approval-keyring", type=Path, required=True)
@@ -2880,7 +3106,7 @@ def main(argv: list[str] | None = None) -> int:
apply_parser = subparsers.add_parser("validate-apply", help="validate a separate apply receipt")
apply_parser.add_argument("--manifest", type=Path, required=True)
apply_parser.add_argument("--manifest-sha256")
apply_parser.add_argument("--manifest-sha256", required=True)
apply_parser.add_argument("--approval", type=Path, required=True)
apply_parser.add_argument("--approval-sha256", required=True)
apply_parser.add_argument("--approval-keyring", type=Path, required=True)
@@ -2906,7 +3132,7 @@ def main(argv: list[str] | None = None) -> int:
"service_writes": 0,
}
elif args.command == "validate-approval":
manifest, _ = _load_manifest(args.manifest, args.manifest_sha256)
manifest, manifest_raw_sha = _load_manifest(args.manifest, args.manifest_sha256)
approval, raw_sha = secure_read_json(args.approval, "approval receipt", args.approval_sha256)
approval_keyring, _ = secure_read_json(
args.approval_keyring,
@@ -2920,6 +3146,7 @@ def main(argv: list[str] | None = None) -> int:
)
validate_approval_receipt(
manifest,
manifest_raw_sha,
approval,
approval_keyring,
approval_root_public_key,
@@ -2933,7 +3160,7 @@ def main(argv: list[str] | None = None) -> int:
"service_writes": 0,
}
else:
manifest, _ = _load_manifest(args.manifest, args.manifest_sha256)
manifest, manifest_raw_sha = _load_manifest(args.manifest, args.manifest_sha256)
approval, approval_raw = secure_read_json(
args.approval, "approval receipt", args.approval_sha256
)
@@ -2954,6 +3181,7 @@ def main(argv: list[str] | None = None) -> int:
)
validate_approval_receipt(
manifest,
manifest_raw_sha,
approval,
approval_keyring,
approval_root_public_key,
@@ -2963,6 +3191,7 @@ def main(argv: list[str] | None = None) -> int:
)
validate_apply_receipt(
manifest,
manifest_raw_sha,
approval,
approval_keyring,
approval_root_public_key,
@@ -66,6 +66,11 @@ RELEASE_CONTROL_PATHS = (
"yuqei-infra/scripts/build-installable-release.py",
"yuqei-infra/scripts/build-infrastructure-image-bundle.py",
"yuqei-infra/scripts/build-third-party-materials.py",
"yuqei-infra/scripts/build-rc06-publication-batch.py",
"yuqei-infra/scripts/rc06-single-reviewer-signing.py",
"yuqei-infra/scripts/Launch-ReleaseSigner.ps1",
"yuqei-infra/scripts/Initialize-ReleaseSigner.cmd",
"yuqei-infra/scripts/Approve-ReleaseCandidate.cmd",
"yuqei-infra/tests/test_production_compose_preflight.py",
"yuqei-infra/tests/test_production_compose_merge_gate.py",
"yuqei-infra/tests/test_release_package_executor.py",
@@ -76,6 +81,7 @@ RELEASE_CONTROL_PATHS = (
"yuqei-infra/tests/test_rollback_rehearsal_planner.py",
"yuqei-infra/tests/test_third_party_materials.py",
"yuqei-infra/tests/test_release_candidate_manifest_tools.py",
"yuqei-infra/tests/test_rc06_publication_batch.py",
)
CONTRACT_LOCK_PATH = REQUIREMENT_LOCK_PATHS[0]
CONTRACT_DOCKERFILE_PATH = "yuqei-infra/docker/contract-api.Dockerfile"
@@ -31,6 +31,7 @@ CLOSEOUT_PREFIX = "docs/qa/multiscene-closeout-20260910/"
MAIN_PLAN = "project-docs/AI合同平台-多场景完整交付与开发收口方案-2026-09-10.md"
CURRENT_RELEASE_CONTEXT_DOCS = {
"project-docs/上线收口-执行约束-2026-09-10.md",
"project-docs/RC06-single-reviewer-one-click-signing-runbook-2026-09-27.md",
}
HISTORICAL_PROJECT_DOCS = {
"project-docs/V4-website-shell-redesign-2026-08-28.md",
@@ -94,6 +95,11 @@ RUNTIME_COMPONENTS = {
"yuqei-infra/scripts/build-installable-release.py",
"yuqei-infra/scripts/build-infrastructure-image-bundle.py",
"yuqei-infra/scripts/build-third-party-materials.py",
"yuqei-infra/scripts/build-rc06-publication-batch.py",
"yuqei-infra/scripts/rc06-single-reviewer-signing.py",
"yuqei-infra/scripts/Launch-ReleaseSigner.ps1",
"yuqei-infra/scripts/Initialize-ReleaseSigner.cmd",
"yuqei-infra/scripts/Approve-ReleaseCandidate.cmd",
"yuqei-infra/scripts/build-release-candidate-manifest.py",
"yuqei-infra/scripts/build-release-worktree-ownership.py",
"yuqei-infra/tests/test_installable_release_assembler_hardening.py",
@@ -103,6 +109,7 @@ RUNTIME_COMPONENTS = {
"yuqei-infra/tests/test_third_party_materials.py",
"yuqei-infra/tests/test_release_package_executor.py",
"yuqei-infra/tests/test_release_candidate_manifest_tools.py",
"yuqei-infra/tests/test_rc06_publication_batch.py",
"yuqei-infra/tests/test_production_compose_preflight.py",
"yuqei-infra/tests/test_production_compose_merge_gate.py",
"yuqei-infra/tests/test_linux_release_build_tools.py",
@@ -150,6 +157,11 @@ REQUIRED_WORKTREE_ANCHORS = (
"yuqei-infra/scripts/build-installable-release.py",
"yuqei-infra/scripts/build-infrastructure-image-bundle.py",
"yuqei-infra/scripts/build-third-party-materials.py",
"yuqei-infra/scripts/build-rc06-publication-batch.py",
"yuqei-infra/scripts/rc06-single-reviewer-signing.py",
"yuqei-infra/scripts/Launch-ReleaseSigner.ps1",
"yuqei-infra/scripts/Initialize-ReleaseSigner.cmd",
"yuqei-infra/scripts/Approve-ReleaseCandidate.cmd",
"yuqei-infra/tests/test_production_compose_preflight.py",
"yuqei-infra/tests/test_production_compose_merge_gate.py",
"yuqei-infra/tests/test_release_package_executor.py",
@@ -160,6 +172,7 @@ REQUIRED_WORKTREE_ANCHORS = (
"yuqei-infra/tests/test_rollback_rehearsal_planner.py",
"yuqei-infra/tests/test_third_party_materials.py",
"yuqei-infra/tests/test_release_candidate_manifest_tools.py",
"yuqei-infra/tests/test_rc06_publication_batch.py",
)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -300,7 +300,15 @@ RUN python -c "import platform; name, version = platform.libc_ver(); minimum=(2,
("project-docs/report-TP03-run.json", "generated_evidence_retain_exclude"),
("project-docs/V4-website-shell-redesign-2026-08-28.md", "generated_evidence_retain_exclude"),
("project-docs/上线收口-执行约束-2026-09-10.md", "release_evidence_compact_include"),
(
"project-docs/RC06-single-reviewer-one-click-signing-runbook-2026-09-27.md",
"release_evidence_compact_include",
),
("project-docs/unreviewed-plan.md", "needs_manual_review"),
("yuqei-infra/scripts/rc06-single-reviewer-signing.py", "release_source_include"),
("yuqei-infra/scripts/Launch-ReleaseSigner.ps1", "release_source_include"),
("yuqei-infra/scripts/Initialize-ReleaseSigner.cmd", "release_source_include"),
("yuqei-infra/scripts/Approve-ReleaseCandidate.cmd", "release_source_include"),
("yuqei-infra/config/.env.example", "release_source_include"),
(
"yuqei-infra/release-trust/third-party-materials-baseline.json",