diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json
index 0751408e..cc3c4185 100644
--- a/apps/web/messages/en.json
+++ b/apps/web/messages/en.json
@@ -2837,6 +2837,44 @@
}
}
},
+ "sourceControlReadiness": {
+ "title": "GitHub Primary Readiness",
+ "subtitle": "The long-term Gitea-to-GitHub direction is shown as read-only readiness: candidate repos, owner responses, refs truth, workflow / secret names, and rollback ADR must all be present before primary_ready_count can be reviewed.",
+ "gateLabel": "Readiness gate",
+ "guardLabel": "Still forbidden",
+ "items": {
+ "candidateRepos": {
+ "title": "Candidate repo inventory",
+ "body": "8 candidate repos and 7 in-scope repos are visible for inventory and owner-evidence alignment only.",
+ "guard": "No GitHub repo creation or visibility changes."
+ },
+ "primaryReady": {
+ "title": "primary_ready_count remains 0",
+ "body": "No repo has passed target, refs, workflow / secret name, and rollback readiness yet.",
+ "guard": "No GitHub primary switch and no Gitea disablement."
+ },
+ "ownerResponses": {
+ "title": "Owner responses are still waiting",
+ "body": "S4.9-S4.12 include 22 templates; received=0 and accepted=0.",
+ "guard": "Do not treat request-ready as response accepted."
+ },
+ "refsTruth": {
+ "title": "Refs truth is not accepted",
+ "body": "main / dev truth, release tags, and deprecated refs still need owner decisions.",
+ "guard": "No refs push, delete, or force push."
+ },
+ "workflowSecrets": {
+ "title": "Workflow / secret names are incomplete",
+ "body": "Workflow, runner, webhook, and secret-name parity evidence is still missing for 7 in-scope repos.",
+ "guard": "Collect names and owners only, never secret values."
+ },
+ "rollbackAdr": {
+ "title": "Rollback ADR is not approved",
+ "body": "Rollback owner, validation window, and trigger details still need human review for 7 in-scope repos.",
+ "guard": "No cutover dry-run and no primary switch."
+ }
+ }
+ },
"awooopReadOnlyLandingReadiness": {
"title": "AwoooP Read-Only Landing Readiness",
"subtitle": "S2.51 turns the AwoooP main-line read-only consumption path for IwoooS / security mirror state into an intake readiness board. This is landing readiness, not production_landing_enabled, and it does not connect an execution router.",
diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json
index 537deec0..aecf3b90 100644
--- a/apps/web/messages/zh-TW.json
+++ b/apps/web/messages/zh-TW.json
@@ -2838,6 +2838,44 @@
}
}
},
+ "sourceControlReadiness": {
+ "title": "GitHub Primary Readiness",
+ "subtitle": "把 Gitea 轉 GitHub 的長期方向拆成只讀 readiness:候選 repo、owner response、refs truth、workflow / secret 名稱與 rollback ADR 都要到齊,才會重估 primary_ready_count。",
+ "gateLabel": "Readiness gate",
+ "guardLabel": "仍禁止",
+ "items": {
+ "candidateRepos": {
+ "title": "候選 repo 清冊",
+ "body": "8 個 candidate repos、7 個 in-scope,目前只做清冊與 owner evidence 對齊。",
+ "guard": "不建立 GitHub repo、不改 visibility。"
+ },
+ "primaryReady": {
+ "title": "primary_ready_count 仍為 0",
+ "body": "尚無 repo 通過 target、refs、workflow / secret 名稱與 rollback readiness。",
+ "guard": "不切 GitHub primary、不停用 Gitea。"
+ },
+ "ownerResponses": {
+ "title": "Owner response 仍等待",
+ "body": "S4.9-S4.12 共 22 個 templates,目前 received=0、accepted=0。",
+ "guard": "不把 request-ready 當 response accepted。"
+ },
+ "refsTruth": {
+ "title": "Refs truth 尚未接受",
+ "body": "main / dev truth、release tags、deprecated refs 仍需 owner 判定。",
+ "guard": "不 push、delete、force push refs。"
+ },
+ "workflowSecrets": {
+ "title": "Workflow / secret 名稱未完成",
+ "body": "7 個 in-scope repos 的 workflow、runner、webhook、secret name parity 還缺 evidence。",
+ "guard": "只收名稱與 owner,不收 secret value。"
+ },
+ "rollbackAdr": {
+ "title": "Rollback ADR 未批准",
+ "body": "7 個 in-scope repos 的 rollback owner、驗證窗口與 trigger 尚待人工審查。",
+ "guard": "不 dry-run cutover、不切 primary。"
+ }
+ }
+ },
"awooopReadOnlyLandingReadiness": {
"title": "AwoooP 只讀 Landing Readiness",
"subtitle": "S2.51 把 AwoooP 主線要如何只讀消費 IwoooS / security mirror 狀態整理成接入準備面板。這是 landing readiness,不是 production landing enabled,也不接 execution router。",
diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx
index ccd0d1da..efe7a6a5 100644
--- a/apps/web/src/app/[locale]/iwooos/page.tsx
+++ b/apps/web/src/app/[locale]/iwooos/page.tsx
@@ -66,6 +66,14 @@ type OwnerResponseNextActionFocusItem = {
tone: 'steady' | 'warn' | 'locked'
}
+type SourceControlReadinessItem = {
+ key: string
+ gate: string
+ value: string
+ icon: typeof ShieldCheck
+ tone: 'steady' | 'warn' | 'locked'
+}
+
type S49OwnerResponsePreflightCheck = {
key: string
check: string
@@ -406,6 +414,15 @@ const ownerResponseNextActionFocusItems: OwnerResponseNextActionFocusItem[] = [
{ key: 'workflowSecretOwnerResponse', focus: 'S4.12', icon: Lock, tone: 'locked' },
]
+const sourceControlReadinessItems: SourceControlReadinessItem[] = [
+ { key: 'candidateRepos', gate: 'S4.0', value: '8 / 7', icon: GitBranch, tone: 'warn' },
+ { key: 'primaryReady', gate: 'S4.0', value: '0', icon: Lock, tone: 'locked' },
+ { key: 'ownerResponses', gate: 'S4.13', value: '0 / 22', icon: ClipboardCheck, tone: 'warn' },
+ { key: 'refsTruth', gate: 'S4.11', value: '0', icon: SearchCheck, tone: 'locked' },
+ { key: 'workflowSecrets', gate: 'S4.12', value: '0 / 7', icon: FileWarning, tone: 'warn' },
+ { key: 'rollbackAdr', gate: 'S4.4', value: '0', icon: FileText, tone: 'locked' },
+]
+
const s49OwnerResponsePreflightChecks: S49OwnerResponsePreflightCheck[] = [
{ key: 'knownAttestationItem', check: 'P1', icon: SearchCheck, tone: 'warn' },
{ key: 'requiredOwnerFields', check: 'P2', icon: ListChecks, tone: 'warn' },
@@ -1075,6 +1092,38 @@ function OwnerResponseNextActionFocusCard({ item }: { item: OwnerResponseNextAct
)
}
+function SourceControlReadinessCard({ item }: { item: SourceControlReadinessItem }) {
+ const t = useTranslations('iwooos.sourceControlReadiness')
+ const Icon = item.icon
+ const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const }
+ return (
+
{t('awooopReadOnlyLandingReadiness.title')}
diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md
index de59301e..49f093fa 100644
--- a/docs/LOGBOOK.md
+++ b/docs/LOGBOOK.md
@@ -1,3 +1,17 @@
+## 2026-05-20 | 資安供應鏈 S2.63:IwoooS GitHub Primary Readiness Board
+
+**背景**:統帥已同意長期將本地 Gitea 的專案版本完整轉移到 GitHub;S2.62 已讓使用者看見既有資安頁面如何連回 IwoooS,本輪把 Gitea → GitHub 的 source-control readiness 缺口也集中顯示在 `/iwooos`,避免「已決定長期方向」被誤讀成「已可切 primary」。
+
+**完成**:
+- `/iwooos` 新增 GitHub Primary Readiness 只讀狀態板,顯示 candidate repos=8、in-scope=7、primary_ready_count=0、owner response 0/22、refs truth accepted=0、workflow inventory complete=0/7、rollback ADR approved=0。
+- `iwooos_posture_projection_v1` schema / snapshot 新增 `source_control_primary_readiness_items` 與 `source_control_primary_readiness_item_count=6`。
+- `security_mirror_status_rollup_v1` micro progress ledger 新增 `s2_63_iwooos_github_primary_readiness_board`,並新增 `show_iwooos_github_primary_readiness_board` next safe action。
+- `security-mirror-progress-guard.py` 開始驗證 GitHub readiness board、6 個 source-control readiness items、0 counters、false 邊界、forbidden outputs 與 i18n 文案。
+
+**仍禁止**:
+- S2.63 的 readiness board 不代表 owner response received / accepted、runtime authorization、active runtime gate、repo creation、visibility change、refs sync / delete / force push、workflow / secret modification、secret value collection、GitHub primary switch、Gitea disablement、Kali `/execute`、SSH 登入、主機更新或 blocking control。
+- 整體資安網 headline 仍是 58%;框架 / 治理 / 文件 / schema / read-only evidence 仍約 80-85%;真正落地執行 / runtime ingestion / GitHub primary / AwoooP production landing 仍約 35-40%。
+
## 2026-05-20 | 資安供應鏈 S2.62:IwoooS Frontend Surface Connection Board
**背景**:S2.59-S2.61 已把既有安全 / 合規、告警 / 錯誤 / 授權 / 治理、稽核 / 工程審查頁面逐步反向接回 IwoooS;本輪把 10 個既有資安入口的連接方式集中顯示在 `/iwooos`,讓使用者直接看見哪些頁面已 direct bridge、哪些是 embedded bridge、哪些是 AwoooP read-only candidate。
diff --git a/docs/schemas/iwooos_posture_projection_v1.schema.json b/docs/schemas/iwooos_posture_projection_v1.schema.json
index 63432c68..119ab0aa 100644
--- a/docs/schemas/iwooos_posture_projection_v1.schema.json
+++ b/docs/schemas/iwooos_posture_projection_v1.schema.json
@@ -19,6 +19,7 @@
"progress_hold_movement_gates",
"progress_acceleration_lanes",
"owner_response_next_action_focus_items",
+ "source_control_primary_readiness_items",
"s4_9_owner_response_preflight_checks",
"s4_9_owner_response_request_templates",
"posture_pillars",
@@ -114,6 +115,7 @@
"owner_response_validation_received_count",
"owner_response_validation_accepted_count",
"github_primary_ready_count",
+ "source_control_primary_readiness_item_count",
"existing_frontend_surface_count",
"frontend_surface_reverse_bridge_status_count",
"frontend_surface_coverage_group_count",
@@ -205,6 +207,10 @@
"type": "integer",
"const": 0
},
+ "source_control_primary_readiness_item_count": {
+ "type": "integer",
+ "const": 6
+ },
"action_buttons_allowed": {
"type": "boolean",
"const": false
@@ -4400,6 +4406,75 @@
"additionalProperties": false
}
},
+ "source_control_primary_readiness_items": {
+ "type": "array",
+ "minItems": 6,
+ "maxItems": 6,
+ "items": {
+ "type": "object",
+ "required": [
+ "item_id",
+ "display_order",
+ "gate_id",
+ "readiness_state",
+ "display_mode",
+ "primary_ready_count",
+ "owner_response_received_count",
+ "owner_response_accepted_count",
+ "github_primary_switch_authorized",
+ "runtime_execution_authorized",
+ "action_buttons_allowed",
+ "not_authorization"
+ ],
+ "properties": {
+ "item_id": {
+ "type": "string"
+ },
+ "display_order": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "gate_id": {
+ "type": "string"
+ },
+ "readiness_state": {
+ "type": "string"
+ },
+ "display_mode": {
+ "const": "github_primary_readiness_only"
+ },
+ "primary_ready_count": {
+ "type": "integer",
+ "const": 0
+ },
+ "owner_response_received_count": {
+ "type": "integer",
+ "const": 0
+ },
+ "owner_response_accepted_count": {
+ "type": "integer",
+ "const": 0
+ },
+ "github_primary_switch_authorized": {
+ "type": "boolean",
+ "const": false
+ },
+ "runtime_execution_authorized": {
+ "type": "boolean",
+ "const": false
+ },
+ "action_buttons_allowed": {
+ "type": "boolean",
+ "const": false
+ },
+ "not_authorization": {
+ "type": "boolean",
+ "const": true
+ }
+ },
+ "additionalProperties": false
+ }
+ },
"s4_9_owner_response_request_templates": {
"type": "array",
"minItems": 5,
diff --git a/docs/security/IWOOOS-POSTURE-PROJECTION.md b/docs/security/IWOOOS-POSTURE-PROJECTION.md
index 56c82e00..057f5715 100644
--- a/docs/security/IWOOOS-POSTURE-PROJECTION.md
+++ b/docs/security/IWOOOS-POSTURE-PROJECTION.md
@@ -24,6 +24,7 @@ IwoooS 首版只讀取或對齊以下已提交 evidence:
| `security_mirror_status_rollup_v1` | 58% headline、36 contracts、0 active runtime gates、下一個高層 gate |
| `security_rollout_policy_v1` | 7 條 low-friction non-blocking lanes |
| `source_control_owner_response_validation_rollup_v1` | owner response 仍為 0、S4.9 下一個收件候選 |
+| `source_control_primary_readiness_gate_v1` | GitHub primary readiness 仍為 0、候選 repo 與切換前置缺口 |
| `kali_integration_status_v1` | Kali 112 observe-only 整合態勢 |
| `/iwooos` 前端路由 | 顯示入口,不提供執行按鈕 |
| 既有前端資安頁面 | 只讀索引,不搬移原頁責任邊界、不新增執行控制 |
@@ -81,6 +82,7 @@ IwoooS 首版只讀取或對齊以下已提交 evidence:
49. 6 個 AwoooP read-only landing readiness items,整理 AwoooP 主線只讀接入前要消費的 snapshot、evidence refs、guard checks、route groups、forbidden outputs 與 production handoff pending,但不標記 production landing enabled、不接 execution router。
50. 6 個 AwoooP cross-session handoff packets,固定另一個 AwoooP Session 接手前要確認的 PR / branch、進度語義、guard commands、runtime 禁止動作、只讀輸入與下一個協調 gate,但不把 handoff 當 merge、deploy、primary switch、refs mutation、guard skip 或 production consumption。
51. 10 個 frontend surface reverse bridge statuses,顯示既有資安入口目前是 embedded bridge、direct bridge 或 AwoooP read-only candidate;這只是連接狀態,不代表 owner response、runtime authorization、Code Review blocker、Gitea/GitHub action 或任何執行控制。
+52. 6 個 source control primary readiness items,顯示 GitHub primary 前置缺口:candidate repo inventory、primary ready counter、owner response validation、refs truth、workflow / secret name inventory、rollback ADR;這只是 readiness,不代表 repo 建立、visibility 變更、refs mutation、secret value collection、primary switch 或 Gitea 停用。
## 3.1 既有前端資安頁面整合
@@ -116,6 +118,21 @@ S2.62 追加「前端資安頁面連接狀態板」,讓使用者可以直接
| `/awooop/approvals` | AwoooP read-only candidate | 顯示 owner response 只讀候選,不等於資安批准或 runtime gate |
| `/code-review` | direct bridge visible | 顯示深色只讀橋接,不把 Code Review 當 deploy approval 或 Gitea/GitHub action |
+### 3.1.1 GitHub Primary Readiness Board
+
+S2.63 追加 GitHub Primary Readiness 只讀狀態板,讓使用者理解「長期考量轉回 GitHub」仍需要哪些 evidence,而不是把方向共識誤讀成已可切換 primary。
+
+| 項目 | 目前值 | 邊界 |
+|------|--------|------|
+| candidate repo inventory | 8 個 candidate、7 個 in-scope | 只顯示清冊與 owner evidence 缺口,不建立 GitHub repo、不改 visibility |
+| primary ready counter | `primary_ready_count=0` | 不切 GitHub primary、不停用 Gitea |
+| owner response validation | `received=0`、`accepted=0`、22 templates | 不把 request-ready、template 或前端顯示當 owner response accepted |
+| refs truth | accepted=0 | 不 push、delete、force push refs |
+| workflow / secret name inventory | complete=0/7 | 只收名稱與 owner evidence,不收 secret value |
+| rollback ADR | approved=0、dry-run=0 | 不 dry-run cutover、不執行 rollback、不切 primary |
+
+這個 board 的唯一允許輸出是 `display_source_control_primary_readiness_board`。所有 repo、refs、workflow、secret、runner、primary switch 與 Gitea disablement 都仍必須留在後續人工 gate。
+
## 3.2 覆蓋與邊界矩陣
S2.11 將 10 個既有前端資安頁面分成四個責任面,讓使用者看懂「訊號在哪裡、人工控制在哪裡、治理稽核在哪裡、工程審查在哪裡」。
diff --git a/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md b/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md
index 20999ee5..5f6d679f 100644
--- a/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md
+++ b/docs/security/SECURITY-MIRROR-STATUS-ROLLUP.md
@@ -44,6 +44,7 @@
| Security control pages IwoooS reverse bridge | S2.60 已把 `/alerts`、`/errors`、`/authorizations` 與 `/governance` 反向接上 IwoooS 只讀橋接;headline=58%、framework=80-85%、runtime gates=0、action buttons=0;仍不新增 alert blocker、scan、repair、approve、deploy 或 blocking control |
| Audit / engineering pages IwoooS reverse bridge | S2.61 已把 `/alert-operation-logs` 與 `/code-review` 反向接上 IwoooS 深色只讀橋接;headline=58%、framework=80-85%、runtime gates=0、action buttons=0;仍不新增 Code Review blocker、Gitea/GitHub action、scan、repair、approve、deploy 或 blocking control |
| IwoooS frontend surface connection board | S2.62 已在 `/iwooos` 顯示 10 個既有資安入口的連接狀態,區分 embedded bridge、direct bridge 與 AwoooP read-only candidate;frontend_surface_reverse_bridge_status_count=10;仍不新增授權、阻擋、scan、repair、approve、deploy、Code Review blocker 或 Gitea/GitHub action |
+| IwoooS GitHub primary readiness board | S2.63 已在 `/iwooos` 顯示 GitHub Primary Readiness 只讀狀態板;candidate repos=8、in-scope=7、primary_ready_count=0、owner response 0/22、workflow inventory complete=0/7、rollback ADR approved=0;仍不建立 repo、不改 visibility、不改 refs、不收 secret value、不切 primary |
| Dry-run | `contract_defined_not_executed`;已納入 `CHECK_PROGRESS_GUARD` 與 `CHECK_OWNER_RESPONSE_GUARD`,latest local validation 為 `repo_snapshot_guard_pass`,仍不代表 production ingestion |
| Runtime actions | `false` |
| Payload ingestion | `false` |
@@ -154,6 +155,7 @@
| S2.60 security control pages IwoooS reverse bridge | framework detail | 0 | 只把 `/alerts`、`/errors`、`/authorizations` 與 `/governance` 反向接上 IwoooS 只讀橋接;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把告警、錯誤、授權或治理頁面的可見性當 owner response、runtime gate、掃描、修復、批准、部署或 blocking control |
| S2.61 audit engineering pages IwoooS reverse bridge | framework detail | 0 | 只把 `/alert-operation-logs` 與 `/code-review` 反向接上 IwoooS 深色只讀橋接;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把稽核或工程審查頁面的可見性當 owner response、runtime gate、掃描、修復、批准、部署、Code Review blocker 或 Gitea/GitHub action |
| S2.62 IwoooS frontend surface connection board | framework detail | 0 | 只在 `/iwooos` 顯示 10 個既有資安入口的 embedded bridge、direct bridge 與 AwoooP read-only candidate 連接狀態;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把連接狀態當 owner response、runtime gate、掃描、修復、批准、部署、Code Review blocker 或 Gitea/GitHub action |
+| S2.63 IwoooS GitHub primary readiness board | framework detail | 0 | 只在 `/iwooos` 顯示 GitHub Primary Readiness 缺口:candidate repos=8、in-scope=7、primary_ready_count=0、owner response 0/22、refs truth accepted=0、workflow inventory complete=0/7、rollback ADR approved=0;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不建立 GitHub repo、不改 visibility、不 sync / delete / force push refs、不收 secret value、不切 primary、不停用 Gitea |
headline 進度要再往上,至少需要下列任一高層 gate 有實質 evidence:
diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md
index 9b99ce99..3e835181 100644
--- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md
+++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md
@@ -5,7 +5,7 @@
| 日期 | 2026-05-17 |
| 狀態 | S0/S1 read-only evidence 建置中 |
| 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 |
-| 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP Run 監控 IwoooS Run State 只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 |
+| 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP Run 監控 IwoooS Run State 只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub Primary Readiness 只讀狀態板 |
| 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary |
## 0. 本階段完成後整體進度
@@ -28,7 +28,7 @@ python3 scripts/security/security-mirror-progress-guard.py
### 0.2 Headline 58% 不代表停滯
-近期 S4.10 request packet、template status ledger、audit event templates、redaction examples、collection checks、intake preflight checks、S4.11 request packet / template status ledger / audit event templates / redaction examples / collection checks / intake preflight checks、S4.12 request packet / template status ledger / audit event templates / redaction examples / collection checks / intake preflight checks、S4.13 evidence routing rules / display sections / state transition rules / reviewer checklist / reviewer outcome lanes / reviewer audit event templates / reviewer audit display sections / reviewer audit collection checks / reviewer audit redaction examples / reviewer audit retention rules / reviewer audit retention checks / reviewer audit handoff packets / reviewer audit handoff checks / parallel session sync checks / parallel session conflict lanes / parallel session recovery checks / recovery outcome lanes、S1.3 non-blocking escalation lanes、S2.8 IwoooS frontend posture entry,以及 S2.9-S2.62 IwoooS / AwoooP security projection contract 都是有效進展,但它們是 framework detail,不是 owner response、runtime gate、production ingestion 或 GitHub primary readiness。因此 headline 仍維持 58%,避免把只讀框架誤算成已落地執行。
+近期 S4.10 request packet、template status ledger、audit event templates、redaction examples、collection checks、intake preflight checks、S4.11 request packet / template status ledger / audit event templates / redaction examples / collection checks / intake preflight checks、S4.12 request packet / template status ledger / audit event templates / redaction examples / collection checks / intake preflight checks、S4.13 evidence routing rules / display sections / state transition rules / reviewer checklist / reviewer outcome lanes / reviewer audit event templates / reviewer audit display sections / reviewer audit collection checks / reviewer audit redaction examples / reviewer audit retention rules / reviewer audit retention checks / reviewer audit handoff packets / reviewer audit handoff checks / parallel session sync checks / parallel session conflict lanes / parallel session recovery checks / recovery outcome lanes、S1.3 non-blocking escalation lanes、S2.8 IwoooS frontend posture entry,以及 S2.9-S2.63 IwoooS / AwoooP security projection contract 都是有效進展,但它們是 framework detail,不是 owner response、runtime gate、production ingestion 或 GitHub primary readiness。因此 headline 仍維持 58%,避免把只讀框架誤算成已落地執行。
S2.50 也把「為什麼 58% 還不動」拆成五個可見 gate:owner response accepted、redacted payload ingestion、active runtime gate、GitHub primary ready、AwoooP read-only landing。這五個 gate 目前仍全部是 0 / false,所以 headline 不應被灌水提高。
@@ -125,6 +125,7 @@ S2.50 也把「為什麼 58% 還不動」拆成五個可見 gate:owner respons
| S2.60 security control pages IwoooS reverse bridge | 已完成草案,將 `/alerts`、`/errors`、`/authorizations` 與 `/governance` 反向顯示 IwoooS 只讀納管狀態;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false | 0 |
| S2.61 audit engineering pages IwoooS reverse bridge | 已完成草案,將 `/alert-operation-logs` 與 `/code-review` 反向顯示 IwoooS 深色只讀納管狀態;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false | 0 |
| S2.62 IwoooS frontend surface connection board | 已完成草案,在 `/iwooos` 顯示 10 個既有資安入口的 embedded bridge、direct bridge 與 AwoooP read-only candidate 連接狀態;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false | 0 |
+| S2.63 IwoooS GitHub primary readiness board | 已完成草案,在 `/iwooos` 顯示 candidate repos=8、in-scope=7、primary_ready_count=0、owner response 0/22、refs truth accepted=0、workflow inventory complete=0/7、rollback ADR approved=0;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false | 0 |
headline 要再往上,需要 S4.9 / S4.10 / S4.11 / S4.12 任一 owner response 收到並通過脫敏驗收,或人工批准後出現 active runtime gate、redacted payload ingestion、GitHub primary readiness 這類落地 evidence。
@@ -206,6 +207,7 @@ headline 要再往上,需要 S4.9 / S4.10 / S4.11 / S4.12 任一 owner respons
| S2.60 Security Control Pages IwoooS Reverse Bridge | 完成草案 | `/alerts`、`/errors`、`/authorizations` 與 `/governance` 新增 IwoooS 只讀橋接,顯示 58%、80-85%、runtime gates=0、action buttons=0,並連到 `/iwooos` | 使用者能在告警、錯誤、授權與治理流程中看見資安網邊界;橋接仍不是 alert blocker、owner response、runtime authorization、scan、repair、approve、deploy 或 blocking control |
| S2.61 Audit / Engineering Pages IwoooS Reverse Bridge | 完成草案 | `/alert-operation-logs` 與 `/code-review` 新增 IwoooS 深色只讀橋接,顯示 58%、80-85%、runtime gates=0、action buttons=0,並連到 `/iwooos` | 使用者能在稽核操作日誌與 Code Review 控制面看見資安網邊界;橋接仍不是 Code Review blocker、Gitea/GitHub action、owner response、runtime authorization、scan、repair、approve、deploy 或 blocking control |
| S2.62 IwoooS Frontend Surface Connection Board | 完成草案 | `/iwooos` 新增 10 個既有資安入口的連接狀態板,區分 embedded bridge、direct bridge 與 AwoooP read-only candidate | 使用者能直接看見資安頁面目前怎麼接回 IwoooS;連接狀態仍不是 owner response、runtime authorization、Code Review blocker、Gitea/GitHub action、scan、repair、approve、deploy 或 blocking control |
+| S2.63 IwoooS GitHub Primary Readiness Board | 完成草案 | `/iwooos` 新增 GitHub Primary Readiness 只讀狀態板,顯示 candidate repos=8、in-scope=7、primary_ready_count=0、owner response 0/22、refs truth accepted=0、workflow inventory complete=0/7、rollback ADR approved=0 | 使用者能理解 Gitea 長期轉 GitHub 的 readiness 缺口;狀態板仍不是 repo creation、visibility change、refs mutation、secret value collection、primary switch、Gitea disablement 或 runtime 授權 |
| S3 approval gate | 進行中 | `security_approval_gate_v1` 已建立 8 個人工 gate items:7 pending、1 block candidate、0 approved | 不得繞過人工批准;批准後仍需 follow-up runtime gate |
| S3.0 人工批准 Gate 契約 | 完成草案 | 定義批准範圍、決策選項、required reviewers、still forbidden 與 follow-up runtime gate | AwoooP 可記錄決策,不可執行 gate item |
| S3.1 人工決策紀錄契約 | 完成草案 | `security_approval_decision_record_v1` 已建立;目前 0 筆 decision records、0 個 runtime action 授權 | AwoooP 可稽核決策,不可把決策當執行 |
diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json
index 84f9b39a..d483d2cf 100644
--- a/docs/security/iwooos-posture-projection.snapshot.json
+++ b/docs/security/iwooos-posture-projection.snapshot.json
@@ -9,6 +9,7 @@
"docs/security/security-mirror-status-rollup.snapshot.json",
"docs/security/security-rollout-policy.snapshot.json",
"docs/security/source-control-owner-response-validation-rollup.snapshot.json",
+ "docs/security/source-control-primary-readiness-gate.snapshot.json",
"docs/security/kali-integration-status.snapshot.json",
"apps/web/src/app/[locale]/iwooos/page.tsx",
"apps/web/src/app/[locale]/security-compliance/page.tsx",
@@ -34,6 +35,7 @@
"owner_response_validation_received_count": 0,
"owner_response_validation_accepted_count": 0,
"github_primary_ready_count": 0,
+ "source_control_primary_readiness_item_count": 6,
"action_buttons_allowed": false,
"existing_frontend_surface_count": 10,
"frontend_surface_reverse_bridge_status_count": 10,
@@ -137,11 +139,98 @@
"lane-workflow-secret-name-gap",
"lane-progress-display-holding"
],
+ "source_control_primary_readiness_items": [
+ {
+ "item_id": "candidate_repo_inventory",
+ "display_order": 1,
+ "gate_id": "S4.0",
+ "readiness_state": "candidate_repo_count_8_in_scope_7",
+ "display_mode": "github_primary_readiness_only",
+ "primary_ready_count": 0,
+ "owner_response_received_count": 0,
+ "owner_response_accepted_count": 0,
+ "github_primary_switch_authorized": false,
+ "runtime_execution_authorized": false,
+ "action_buttons_allowed": false,
+ "not_authorization": true
+ },
+ {
+ "item_id": "primary_ready_counter_locked",
+ "display_order": 2,
+ "gate_id": "S4.0",
+ "readiness_state": "primary_ready_count_0",
+ "display_mode": "github_primary_readiness_only",
+ "primary_ready_count": 0,
+ "owner_response_received_count": 0,
+ "owner_response_accepted_count": 0,
+ "github_primary_switch_authorized": false,
+ "runtime_execution_authorized": false,
+ "action_buttons_allowed": false,
+ "not_authorization": true
+ },
+ {
+ "item_id": "owner_response_validation_waiting",
+ "display_order": 3,
+ "gate_id": "S4.13",
+ "readiness_state": "owner_response_received_0_accepted_0_templates_22",
+ "display_mode": "github_primary_readiness_only",
+ "primary_ready_count": 0,
+ "owner_response_received_count": 0,
+ "owner_response_accepted_count": 0,
+ "github_primary_switch_authorized": false,
+ "runtime_execution_authorized": false,
+ "action_buttons_allowed": false,
+ "not_authorization": true
+ },
+ {
+ "item_id": "refs_truth_waiting_owner",
+ "display_order": 4,
+ "gate_id": "S4.11",
+ "readiness_state": "refs_truth_owner_response_accepted_0",
+ "display_mode": "github_primary_readiness_only",
+ "primary_ready_count": 0,
+ "owner_response_received_count": 0,
+ "owner_response_accepted_count": 0,
+ "github_primary_switch_authorized": false,
+ "runtime_execution_authorized": false,
+ "action_buttons_allowed": false,
+ "not_authorization": true
+ },
+ {
+ "item_id": "workflow_secret_name_inventory_missing",
+ "display_order": 5,
+ "gate_id": "S4.12",
+ "readiness_state": "workflow_secret_inventory_complete_0_missing_7",
+ "display_mode": "github_primary_readiness_only",
+ "primary_ready_count": 0,
+ "owner_response_received_count": 0,
+ "owner_response_accepted_count": 0,
+ "github_primary_switch_authorized": false,
+ "runtime_execution_authorized": false,
+ "action_buttons_allowed": false,
+ "not_authorization": true
+ },
+ {
+ "item_id": "rollback_adr_waiting_owner_approval",
+ "display_order": 6,
+ "gate_id": "S4.4",
+ "readiness_state": "rollback_owner_approved_0_dry_run_0",
+ "display_mode": "github_primary_readiness_only",
+ "primary_ready_count": 0,
+ "owner_response_received_count": 0,
+ "owner_response_accepted_count": 0,
+ "github_primary_switch_authorized": false,
+ "runtime_execution_authorized": false,
+ "action_buttons_allowed": false,
+ "not_authorization": true
+ }
+ ],
"evidence_refs": [
"docs/security/iwooos-posture-projection.snapshot.json",
"docs/security/security-rollout-policy.snapshot.json",
"docs/security/security-mirror-status-rollup.snapshot.json",
"docs/security/source-control-owner-response-validation-rollup.snapshot.json",
+ "docs/security/source-control-primary-readiness-gate.snapshot.json",
"docs/security/kali-integration-status.snapshot.json"
],
"allowed_frontend_outputs": [
@@ -194,6 +283,7 @@
"display_host_owner_decision_record_human_record_owner_review_preparation_packets",
"display_host_owner_decision_record_human_record_owner_review_preparation_checklist",
"display_owner_response_next_action_focus",
+ "display_source_control_primary_readiness_board",
"display_s4_9_owner_response_preflight_checks",
"display_s4_9_owner_response_request_templates"
],
@@ -390,6 +480,14 @@
"sync_refs_from_s4_9_template",
"switch_primary_from_s4_9_template",
"collect_token_from_s4_9_template",
+ "create_github_repo_from_primary_readiness_board",
+ "change_repo_visibility_from_primary_readiness_board",
+ "sync_refs_from_primary_readiness_board",
+ "delete_refs_from_primary_readiness_board",
+ "force_push_from_primary_readiness_board",
+ "switch_github_primary_from_primary_readiness_board",
+ "collect_secret_value_from_primary_readiness_board",
+ "disable_gitea_from_primary_readiness_board",
"treat_progress_hold_gate_as_percent_increase",
"increase_headline_without_gate_evidence",
"mark_owner_response_received_from_hold_gate",
diff --git a/docs/security/security-mirror-status-rollup.snapshot.json b/docs/security/security-mirror-status-rollup.snapshot.json
index a3792bfd..cb862a0f 100644
--- a/docs/security/security-mirror-status-rollup.snapshot.json
+++ b/docs/security/security-mirror-status-rollup.snapshot.json
@@ -1214,6 +1214,18 @@
"runtime_delta": false,
"execution_authorized": false,
"not_authorization": true
+ },
+ {
+ "delta_id": "s2_63_iwooos_github_primary_readiness_board",
+ "display_order": 92,
+ "completed_stage": "S2.63 IwoooS GitHub primary readiness board",
+ "progress_axis": "framework_detail",
+ "headline_percent_delta": 0,
+ "framework_delta_visible": true,
+ "why_headline_unchanged": "IwoooS 只新增 GitHub Primary Readiness 狀態板,顯示 candidate repos=8、in-scope=7、primary_ready_count=0、owner response 0/22、workflow inventory complete=0;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false,沒有建立 GitHub repo、修改 visibility、sync / delete / force push refs、收 secret value、切 primary 或停用 Gitea。",
+ "runtime_delta": false,
+ "execution_authorized": false,
+ "not_authorization": true
}
],
"next_safe_actions": [
@@ -1410,6 +1422,22 @@
"把 embedded bridge、direct bridge 或 AwoooP read-only candidate 當成 owner response received / accepted"
]
},
+ {
+ "action_id": "show_iwooos_github_primary_readiness_board",
+ "title": "IwoooS 顯示 GitHub Primary Readiness 只讀狀態板",
+ "mode": "observe",
+ "source_contract": "iwooos_posture_projection_v1",
+ "allowed_processing": [
+ "在 /iwooos 顯示 candidate repos=8、in-scope repos=7、primary_ready_count=0",
+ "顯示 owner response 0/22、refs truth accepted=0、workflow inventory complete=0/7、rollback ADR approved=0",
+ "只協助使用者理解 Gitea 長期轉 GitHub 的 evidence 缺口,不新增任何 repo、refs、workflow、secret 或 primary action"
+ ],
+ "blocked_processing": [
+ "從 readiness board 建立 GitHub repo 或改 visibility",
+ "從 readiness board sync、delete 或 force push refs",
+ "從 readiness board 收 secret value、切 GitHub primary、停用 Gitea 或把 request-ready 當 owner response accepted"
+ ]
+ },
{
"action_id": "mirror_low_friction_non_blocking_lanes",
"title": "AwoooP 顯示低摩擦非阻擋升級分流",
@@ -1785,7 +1813,8 @@
"S2.59 新增既有安全 / 合規頁面 IwoooS reverse bridge;SecurityPanel、CompliancePanel、standalone /security 與 /compliance 反向顯示 IwoooS 只讀納管狀態、headline 58%、framework 80-85%、runtime gates=0、action buttons=0;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把既有頁面的可見性當 owner response、runtime gate、掃描、修復、批准或部署。",
"S2.60 新增資安控制頁面 IwoooS reverse bridge;/alerts、/errors、/authorizations 與 /governance 反向顯示 IwoooS 只讀納管狀態、headline 58%、framework 80-85%、runtime gates=0、action buttons=0;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把告警、錯誤、授權或治理頁面的可見性當 owner response、runtime gate、掃描、修復、批准、部署或 blocking control。",
"S2.61 新增稽核與工程審查頁面 IwoooS reverse bridge;/alert-operation-logs 與 /code-review 以深色只讀橋接顯示 IwoooS 納管狀態、headline 58%、framework 80-85%、runtime gates=0、action buttons=0;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把稽核或工程審查頁面的可見性當 owner response、runtime gate、掃描、修復、批准、部署、Code Review blocker 或 Gitea/GitHub action。",
- "S2.62 新增 IwoooS frontend surface connection board;/iwooos 顯示 10 個既有資安入口的連接狀態,區分 embedded bridge、direct bridge 與 AwoooP read-only candidate;frontend_surface_reverse_bridge_status_count=10、runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把連接狀態當 owner response、runtime gate、掃描、修復、批准、部署、Code Review blocker 或 Gitea/GitHub action。"
+ "S2.62 新增 IwoooS frontend surface connection board;/iwooos 顯示 10 個既有資安入口的連接狀態,區分 embedded bridge、direct bridge 與 AwoooP read-only candidate;frontend_surface_reverse_bridge_status_count=10、runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不把連接狀態當 owner response、runtime gate、掃描、修復、批准、部署、Code Review blocker 或 Gitea/GitHub action。",
+ "S2.63 新增 IwoooS GitHub Primary Readiness 只讀狀態板;/iwooos 顯示 candidate repos=8、in-scope=7、primary_ready_count=0、owner response 0/22、refs truth accepted=0、workflow inventory complete=0/7、rollback ADR approved=0;runtime_execution_authorized=false、active_runtime_gate_count=0、action_buttons_allowed=false、not_authorization=true,不建立 GitHub repo、不改 visibility、不 sync/delete/force push refs、不收 secret value、不切 primary、不停用 Gitea。"
],
"forbidden_actions": [
"start_kali_scan",
diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py
index 496334f2..8b47368c 100755
--- a/scripts/security/security-mirror-progress-guard.py
+++ b/scripts/security/security-mirror-progress-guard.py
@@ -275,6 +275,7 @@ def validate(root: Path) -> None:
"s2_60_security_control_pages_iwooos_reverse_bridge",
"s2_61_audit_engineering_pages_iwooos_reverse_bridge",
"s2_62_iwooos_frontend_surface_connection_board",
+ "s2_63_iwooos_github_primary_readiness_board",
]
assert_equal(
"progress_delta_ledger.delta_ids",
@@ -354,6 +355,11 @@ def validate(root: Path) -> None:
[item["action_id"] for item in rollup["next_safe_actions"] if isinstance(item, dict)],
"show_iwooos_frontend_surface_connection_board",
)
+ assert_contains(
+ "rollup.next_safe_actions.action_ids",
+ [item["action_id"] for item in rollup["next_safe_actions"] if isinstance(item, dict)],
+ "show_iwooos_github_primary_readiness_board",
+ )
assert_equal("rollout_policy.schema_version", rollout_policy["schema_version"], "security_rollout_policy_v1")
assert_equal("rollout_policy.default_mode", rollout_policy["default_mode"], "observe")
@@ -445,6 +451,19 @@ def validate(root: Path) -> None:
iwooos_projection["summary"]["github_primary_ready_count"],
rollup_summary["github_primary_ready_count"],
)
+ expected_iwooos_source_control_primary_readiness_item_ids = [
+ "candidate_repo_inventory",
+ "primary_ready_counter_locked",
+ "owner_response_validation_waiting",
+ "refs_truth_waiting_owner",
+ "workflow_secret_name_inventory_missing",
+ "rollback_adr_waiting_owner_approval",
+ ]
+ assert_equal(
+ "iwooos_projection.summary.source_control_primary_readiness_item_count",
+ iwooos_projection["summary"]["source_control_primary_readiness_item_count"],
+ len(expected_iwooos_source_control_primary_readiness_item_ids),
+ )
assert_false("iwooos_projection.summary.action_buttons_allowed", iwooos_projection["summary"]["action_buttons_allowed"])
expected_iwooos_surface_ids = [
"security_compliance",
@@ -1461,6 +1480,59 @@ def validate(root: Path) -> None:
f"iwooos_projection.owner_response_next_action_focus_items.{item['focus_id']}.not_authorization",
item["not_authorization"],
)
+ source_control_readiness_items = iwooos_projection["source_control_primary_readiness_items"]
+ assert_equal(
+ "iwooos_projection.source_control_primary_readiness_items.ids",
+ [item["item_id"] for item in source_control_readiness_items],
+ expected_iwooos_source_control_primary_readiness_item_ids,
+ )
+ assert_equal(
+ "iwooos_projection.source_control_primary_readiness_items.display_order",
+ [item["display_order"] for item in source_control_readiness_items],
+ list(range(1, len(expected_iwooos_source_control_primary_readiness_item_ids) + 1)),
+ )
+ assert_equal(
+ "iwooos_projection.source_control_primary_readiness_items.gate_ids",
+ [item["gate_id"] for item in source_control_readiness_items],
+ ["S4.0", "S4.0", "S4.13", "S4.11", "S4.12", "S4.4"],
+ )
+ for item in source_control_readiness_items:
+ assert_equal(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.display_mode",
+ item["display_mode"],
+ "github_primary_readiness_only",
+ )
+ assert_equal(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.primary_ready_count",
+ item["primary_ready_count"],
+ 0,
+ )
+ assert_equal(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.owner_response_received_count",
+ item["owner_response_received_count"],
+ 0,
+ )
+ assert_equal(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.owner_response_accepted_count",
+ item["owner_response_accepted_count"],
+ 0,
+ )
+ assert_false(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.github_primary_switch_authorized",
+ item["github_primary_switch_authorized"],
+ )
+ assert_false(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.runtime_execution_authorized",
+ item["runtime_execution_authorized"],
+ )
+ assert_false(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.action_buttons_allowed",
+ item["action_buttons_allowed"],
+ )
+ assert_true(
+ f"iwooos_projection.source_control_primary_readiness_items.{item['item_id']}.not_authorization",
+ item["not_authorization"],
+ )
expected_s4_9_owner_response_request_template_ids = [
"response-public-only-vs-local-gitea-gap",
"response-org-user-endpoint-identity",
@@ -4720,6 +4792,7 @@ def validate(root: Path) -> None:
"display_host_owner_decision_record_human_record_owner_review_preparation_checklist",
"display_evidence_refs",
"display_forbidden_actions",
+ "display_source_control_primary_readiness_board",
]:
assert_contains("iwooos_projection.allowed_frontend_outputs", iwooos_projection["allowed_frontend_outputs"], output)
for output in [
@@ -4930,6 +5003,14 @@ def validate(root: Path) -> None:
"sync_refs_from_s4_9_template",
"switch_primary_from_s4_9_template",
"collect_token_from_s4_9_template",
+ "create_github_repo_from_primary_readiness_board",
+ "change_repo_visibility_from_primary_readiness_board",
+ "sync_refs_from_primary_readiness_board",
+ "delete_refs_from_primary_readiness_board",
+ "force_push_from_primary_readiness_board",
+ "switch_github_primary_from_primary_readiness_board",
+ "collect_secret_value_from_primary_readiness_board",
+ "disable_gitea_from_primary_readiness_board",
"apply_runtime_blocking_control",
"switch_github_primary",
"production_deploy",
@@ -5199,6 +5280,13 @@ def validate(root: Path) -> None:
assert_text_contains("iwooos_page.surface_connection_embedded", iwooos_projection_page, "embeddedBridge")
assert_text_contains("iwooos_page.surface_connection_direct", iwooos_projection_page, "directBridge")
assert_text_contains("iwooos_page.surface_connection_awooop", iwooos_projection_page, "awooopCandidate")
+ assert_text_contains("iwooos_page.source_control_readiness_board", iwooos_projection_page, "sourceControlReadinessItems")
+ assert_text_contains(
+ "iwooos_page.source_control_readiness_testid",
+ iwooos_projection_page,
+ 'data-testid="iwooos-source-control-readiness-board"',
+ )
+ assert_text_contains("iwooos_page.source_control_readiness_component", iwooos_projection_page, "SourceControlReadinessCard")
for key in [
"title",
"subtitle",
@@ -5275,6 +5363,35 @@ def validate(root: Path) -> None:
list(web_messages_en["iwooos"]["surfaceConnections"]["items"].keys()),
key,
)
+ for key in ["title", "subtitle", "gateLabel", "guardLabel", "items"]:
+ assert_contains(
+ "web_messages.zh-TW.iwooos.sourceControlReadiness",
+ list(web_messages_zh["iwooos"]["sourceControlReadiness"].keys()),
+ key,
+ )
+ assert_contains(
+ "web_messages.en.iwooos.sourceControlReadiness",
+ list(web_messages_en["iwooos"]["sourceControlReadiness"].keys()),
+ key,
+ )
+ for key in [
+ "candidateRepos",
+ "primaryReady",
+ "ownerResponses",
+ "refsTruth",
+ "workflowSecrets",
+ "rollbackAdr",
+ ]:
+ assert_contains(
+ "web_messages.zh-TW.iwooos.sourceControlReadiness.items",
+ list(web_messages_zh["iwooos"]["sourceControlReadiness"]["items"].keys()),
+ key,
+ )
+ assert_contains(
+ "web_messages.en.iwooos.sourceControlReadiness.items",
+ list(web_messages_en["iwooos"]["sourceControlReadiness"]["items"].keys()),
+ key,
+ )
owner_summary = owner_rollup["summary"]
assert_equal("owner_rollup.total_received_response_count", owner_summary["total_received_response_count"], 0)
@@ -5403,7 +5520,11 @@ def validate(root: Path) -> None:
assert_true("owner_rollup.latest_local_validation.not_authorization", owner_local_validation["not_authorization"])
primary_summary = primary_gate["summary"]
+ assert_equal("primary_gate.candidate_repo_count", primary_summary["candidate_repo_count"], 8)
+ assert_equal("primary_gate.in_scope_repo_count", primary_summary["in_scope_repo_count"], 7)
assert_equal("primary_gate.primary_ready_count", primary_summary["primary_ready_count"], 0)
+ assert_equal("primary_gate.blocked_in_scope_count", primary_summary["blocked_in_scope_count"], 7)
+ assert_equal("owner_rollup.total_response_template_count", owner_summary["total_response_template_count"], 22)
assert_false("primary_gate.runtime_actions_authorized", primary_summary["runtime_actions_authorized"])
assert_false("primary_gate.github_primary_switch_authorized", primary_summary["github_primary_switch_authorized"])
assert_false("primary_gate.action_buttons_allowed", primary_summary["action_buttons_allowed"])