From a8a8e9d022cd2c7d3a041b644d149553cfdd5d60 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 May 2026 20:54:44 +0800 Subject: [PATCH] feat(web): show GitHub readiness in IwoooS --- apps/web/messages/en.json | 38 ++++++ apps/web/messages/zh-TW.json | 38 ++++++ apps/web/src/app/[locale]/iwooos/page.tsx | 69 ++++++++++ docs/LOGBOOK.md | 14 ++ .../iwooos_posture_projection_v1.schema.json | 75 +++++++++++ docs/security/IWOOOS-POSTURE-PROJECTION.md | 17 +++ .../security/SECURITY-MIRROR-STATUS-ROLLUP.md | 2 + .../SECURITY-SUPPLY-CHAIN-PROGRESS.md | 6 +- .../iwooos-posture-projection.snapshot.json | 98 ++++++++++++++ ...ecurity-mirror-status-rollup.snapshot.json | 31 ++++- .../security-mirror-progress-guard.py | 121 ++++++++++++++++++ 11 files changed, 506 insertions(+), 3 deletions(-) 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('gateLabel')} +
+ {item.gate} +
+
+ {item.value} +
+

+ {t(`items.${item.key}.title` as never)} +

+

+ {t(`items.${item.key}.body` as never)} +

+
+
{t('guardLabel')}
+
+ {t(`items.${item.key}.guard` as never)} +
+
+
+ ) +} + function S49OwnerResponsePreflightCard({ item }: { item: S49OwnerResponsePreflightCheck }) { const t = useTranslations('iwooos.s49OwnerResponsePreflight') const Icon = item.icon @@ -2400,6 +2449,26 @@ export default function IwoooSPage({ params }: { params: { locale: string } }) { +
+
+

{t('sourceControlReadiness.title')}

+

+ {t('sourceControlReadiness.subtitle')} +

+
+
+ {sourceControlReadinessItems.map(item => ( + + ))} +
+
+

{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"])