feat(iwooos): commit wazuh live metadata readiness
Some checks failed
CD Pipeline / tests (push) Waiting to run
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
Code Review / ai-code-review (push) Successful in 10s
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-28 15:53:17 +08:00
parent b419634843
commit 27a7190c2c
9 changed files with 213 additions and 86 deletions

View File

@@ -94,6 +94,15 @@ def load_latest_iwooos_runtime_security_readback(
dispatch_summary = _summary(snapshots["owner_dispatch"])
intrusion_summary = _summary(snapshots["intrusion_prevention"])
live_wazuh = _wazuh_live_summary(wazuh_live_status, wazuh_live_http_status)
live_metadata_gate_ready = all(
_int(live_metadata_gate_summary.get(key)) == 1
for key in (
"live_metadata_owner_response_accepted_count",
"secret_source_metadata_accepted_count",
"wazuh_manager_health_ref_accepted_count",
"readonly_account_scope_accepted_count",
)
)
source_refs = [f"docs/security/{filename}" for filename in _SNAPSHOT_FILES.values()]
runtime_gate_count = _max_summary_count(
@@ -345,9 +354,13 @@ def load_latest_iwooos_runtime_security_readback(
snapshots["wazuh_live_metadata_gate"].get(
"status", "blocked_waiting_live_metadata_owner_response"
),
0,
"locked",
"補齊負責人回覆、機密中繼資料、管理節點健康、唯讀範圍與啟用後讀回",
40 if live_metadata_gate_ready else 0,
"steady" if live_metadata_gate_ready else "locked",
(
"進入 server-side env enable controlled review 與 post-enable readbacklive query 仍未授權"
if live_metadata_gate_ready
else "補齊負責人回覆、機密中繼資料、管理節點健康、唯讀範圍與啟用後讀回"
),
{
"route_readback": live_metadata_gate_summary.get(
"production_route_readback_passed_count", 0

View File

@@ -408,8 +408,16 @@ def _items(summary: dict[str, Any]) -> list[dict[str, Any]]:
_item(
"server_env_owner",
"ENV-2",
"waiting_owner_response",
"locked",
(
"owner_metadata_accepted"
if summary["live_metadata_owner_response_accepted_count"]
else "waiting_owner_response"
),
(
"steady"
if summary["live_metadata_owner_response_accepted_count"]
else "locked"
),
{
"owner_received": summary["live_metadata_owner_response_received_count"],
"owner_accepted": summary["live_metadata_owner_response_accepted_count"],
@@ -418,15 +426,23 @@ def _items(summary: dict[str, Any]) -> list[dict[str, Any]]:
_item(
"secret_metadata",
"ENV-3",
"metadata_only_waiting_acceptance",
"locked",
(
"secret_metadata_accepted"
if summary["secret_source_metadata_accepted_count"]
else "metadata_only_waiting_acceptance"
),
"steady" if summary["secret_source_metadata_accepted_count"] else "locked",
{"secret_metadata_accepted": summary["secret_source_metadata_accepted_count"]},
),
_item(
"manager_health",
"ENV-4",
"waiting_manager_health_ref",
"warn",
(
"manager_health_ref_accepted"
if summary["wazuh_manager_health_ref_accepted_count"]
else "waiting_manager_health_ref"
),
"steady" if summary["wazuh_manager_health_ref_accepted_count"] else "warn",
{
"manager_health_accepted": summary["wazuh_manager_health_ref_accepted_count"],
"live_route_degraded": summary["wazuh_live_route_degraded_count"],
@@ -435,8 +451,12 @@ def _items(summary: dict[str, Any]) -> list[dict[str, Any]]:
_item(
"readonly_scope",
"ENV-5",
"waiting_readonly_scope_ref",
"warn",
(
"readonly_scope_ref_accepted"
if summary["readonly_account_scope_accepted_count"]
else "waiting_readonly_scope_ref"
),
"steady" if summary["readonly_account_scope_accepted_count"] else "warn",
{"readonly_scope_accepted": summary["readonly_account_scope_accepted_count"]},
),
_item(
@@ -678,11 +698,42 @@ def _first_blocking_lane(findings: list[dict[str, Any]]) -> str | None:
def _require_boundaries(payload: dict[str, Any]) -> None:
summary = _summary(payload)
readiness_counts = {
"live_metadata_owner_response_received_count": _int(
summary.get("live_metadata_owner_response_received_count")
),
"live_metadata_owner_response_accepted_count": _int(
summary.get("live_metadata_owner_response_accepted_count")
),
"secret_source_metadata_accepted_count": _int(
summary.get("secret_source_metadata_accepted_count")
),
"wazuh_manager_health_ref_accepted_count": _int(
summary.get("wazuh_manager_health_ref_accepted_count")
),
"readonly_account_scope_accepted_count": _int(
summary.get("readonly_account_scope_accepted_count")
),
}
for key, count in readiness_counts.items():
if count not in {0, 1}:
raise ValueError(
f"Wazuh 即時中繼資料閘門 summary.{key} 必須維持 0 或 1"
)
accepted_count = readiness_counts["live_metadata_owner_response_accepted_count"]
if accepted_count > readiness_counts["live_metadata_owner_response_received_count"]:
raise ValueError("Wazuh 即時中繼資料閘門 accepted 不得大於 received")
for key in (
"live_metadata_owner_response_accepted_count",
"secret_source_metadata_accepted_count",
"wazuh_manager_health_ref_accepted_count",
"readonly_account_scope_accepted_count",
):
if readiness_counts[key] > accepted_count:
raise ValueError(
f"Wazuh 即時中繼資料閘門 summary.{key} 不得超過 owner accepted"
)
for key in (
"post_enable_readback_passed_count",
"wazuh_api_live_query_authorized_count",
"wazuh_active_response_authorized_count",

View File

@@ -113,17 +113,17 @@ def test_iwooos_runtime_security_readback_preserves_zero_runtime_gates() -> None
assert payload["summary"]["wazuh_live_route_degraded_count"] == 1
assert payload["summary"]["wazuh_live_readonly_api_enabled_count"] == 0
assert payload["summary"]["wazuh_live_metadata_available_count"] == 0
assert payload["summary"]["wazuh_live_metadata_gate_owner_accepted_count"] == 0
assert payload["summary"]["wazuh_live_metadata_gate_owner_accepted_count"] == 1
assert (
payload["summary"]["wazuh_live_metadata_gate_secret_source_accepted_count"] == 0
payload["summary"]["wazuh_live_metadata_gate_secret_source_accepted_count"] == 1
)
assert (
payload["summary"]["wazuh_live_metadata_gate_manager_health_accepted_count"]
== 0
== 1
)
assert (
payload["summary"]["wazuh_live_metadata_gate_readonly_scope_accepted_count"]
== 0
== 1
)
assert (
payload["summary"]["wazuh_live_metadata_gate_post_enable_readback_count"] == 0
@@ -209,7 +209,13 @@ def test_iwooos_runtime_security_readback_lanes_are_candidate_only() -> None:
for lane in payload["lanes"]
)
assert all(
lane["lane_id"] != "wazuh_live_metadata_gate" or lane["completion_percent"] == 0
lane["lane_id"] != "wazuh_live_metadata_gate"
or (
lane["completion_percent"] == 40
and lane["metrics"]["owner_accepted"] == 1
and lane["metrics"]["secret_metadata_accepted"] == 1
and lane["metrics"]["post_enable_readback"] == 0
)
for lane in payload["lanes"]
)
assert all(
@@ -252,6 +258,7 @@ def test_iwooos_runtime_security_readback_api_is_public_safe(monkeypatch) -> Non
assert data["summary"]["wazuh_live_route_http_status"] == 200
assert data["summary"]["wazuh_live_route_degraded_count"] == 1
assert data["summary"]["wazuh_live_metadata_available_count"] == 0
assert data["summary"]["wazuh_live_metadata_gate_owner_accepted_count"] == 1
assert data["summary"]["wazuh_live_metadata_gate_live_query_authorized_count"] == 0
assert data["summary"]["wazuh_owner_evidence_accepted_count"] == 0
assert data["summary"]["wazuh_owner_evidence_runtime_gate_count"] == 0
@@ -330,11 +337,13 @@ def test_iwooos_wazuh_live_metadata_gate_api_is_public_safe(monkeypatch) -> None
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "iwooos_wazuh_live_metadata_gate_readback_v1"
assert data["status"] == "blocked_waiting_live_metadata_owner_response"
assert data["status"] == "ready_for_server_side_env_enable_review_no_secret_collection"
assert data["summary"]["production_route_readback_passed_count"] == 1
assert data["summary"]["live_metadata_owner_response_accepted_count"] == 0
assert data["summary"]["secret_source_metadata_accepted_count"] == 0
assert data["summary"]["readonly_account_scope_accepted_count"] == 0
assert data["summary"]["live_metadata_owner_response_received_count"] == 1
assert data["summary"]["live_metadata_owner_response_accepted_count"] == 1
assert data["summary"]["secret_source_metadata_accepted_count"] == 1
assert data["summary"]["wazuh_manager_health_ref_accepted_count"] == 1
assert data["summary"]["readonly_account_scope_accepted_count"] == 1
assert data["summary"]["post_enable_readback_passed_count"] == 0
assert data["summary"]["wazuh_api_live_query_authorized_count"] == 0
assert data["summary"]["wazuh_active_response_authorized_count"] == 0

View File

@@ -20929,8 +20929,8 @@
},
"wazuhLiveMetadataEnvGate": {
"eyebrow": "Wazuh 即時中繼資料環境閘門",
"title": "Wazuh 查詢要等正式路由、負責人與機密中繼資料都過關",
"subtitle": "這張卡把 Wazuh 即時中繼資料啟用前的條件拆開:正式路由讀回、伺服端環境變數負責人、機密來源中繼資料、管理節點健康唯讀帳號範圍與啟用後讀回都要先補齊;目前即時查詢、主動回應、主機寫入與執行期閘門都是 0。",
"title": "Wazuh 即時中繼資料已完成 metadata readiness下一關是啟用後讀回",
"subtitle": "這張卡把 Wazuh 即時中繼資料啟用前的條件拆開:正式路由讀回、伺服端環境變數負責人、機密來源中繼資料、管理節點健康唯讀帳號範圍已接受為脫敏 readiness啟用後讀回仍為 0目前即時查詢、主動回應、主機寫入與執行期閘門都是 0。",
"checkLabel": "檢核",
"stateLabel": "狀態",
"loadingBoundary": "正在讀取只讀閘門",
@@ -20943,11 +20943,11 @@
},
"owner": {
"label": "負責人回覆",
"detail": "伺服端環境變數與啟用責任尚未被審查者接受。"
"detail": "伺服端環境變數與啟用責任已接受為 metadata readiness。"
},
"secretMeta": {
"label": "機密中繼資料",
"detail": "只允許機密來源中繼資料與負責人,不收密碼、權杖或雜湊值。"
"detail": "機密來源只接受中繼資料 ref,不收密碼、權杖或雜湊值。"
},
"liveQuery": {
"label": "即時查詢",
@@ -20957,14 +20957,18 @@
"status": {
"loading": "正在讀取 Wazuh 即時中繼資料閘門",
"failed": "Wazuh 即時中繼資料閘門尚未部署或讀取失敗",
"ready": "Wazuh 即時中繼資料閘門已讀回,但執行期仍關閉"
"ready": "Wazuh metadata readiness 已讀回post-enable 與執行期仍關閉"
},
"states": {
"route_readback_passed": "路由已讀回",
"waiting_owner_response": "待負責人",
"owner_metadata_accepted": "metadata 已接受",
"metadata_only_waiting_acceptance": "只收中繼資料",
"secret_metadata_accepted": "中繼資料已接受",
"waiting_manager_health_ref": "待健康參照",
"manager_health_ref_accepted": "健康參照已接受",
"waiting_readonly_scope_ref": "待範圍參照",
"readonly_scope_ref_accepted": "範圍參照已接受",
"waiting_post_enable_readback": "待讀回驗證"
},
"items": {
@@ -20973,20 +20977,20 @@
"body": "正式讀回已通過;下一步是 controlled gate、機密中繼資料與 Wazuh manager registry readback不是繞過 PlayBook 的主機寫入。"
},
"serverEnv": {
"title": "伺服端環境變數需負責人",
"body": "IWOOOS_WAZUH_READONLY_ENABLED 與 Wazuh API 環境變數只能由正式伺服端流程注入,不能寫到前端 bundle。"
"title": "伺服端環境變數 owner 已接受",
"body": "IWOOOS_WAZUH_READONLY_ENABLED 與 Wazuh API 環境變數只記錄 owner 與流程 metadata,不能寫到前端 bundle。"
},
"secretMetadata": {
"title": "機密只收中繼資料",
"title": "機密中繼資料已接受",
"body": "只記錄注入來源、負責人、維護窗口與回滾路徑不得貼密碼、權杖、Cookie、工作階段或任何機密片段。"
},
"managerHealth": {
"title": "Wazuh 管理節點健康參照",
"body": "需要管理節點、API 與 TLS 健康狀態脫敏參照;不能只用 Wazuh 已安裝或儀表板可見判斷。"
"title": "Wazuh 管理節點健康參照已接受",
"body": "管理節點、API 與 TLS 健康狀態已以脫敏參照接受;不能只用 Wazuh 已安裝或儀表板可見判斷。"
},
"readonlyScope": {
"title": "唯讀帳號範圍待驗",
"body": "只允許中繼資料查詢範圍;主動回應、規則變更、解碼器變更與主機操作必須留在另一個閘門。"
"title": "唯讀帳號範圍已接受",
"body": "唯讀帳號範圍已以脫敏參照接受;主動回應、規則變更、解碼器變更與主機操作必須留在另一個閘門。"
},
"postEnable": {
"title": "啟用後還要讀回",

View File

@@ -20929,8 +20929,8 @@
},
"wazuhLiveMetadataEnvGate": {
"eyebrow": "Wazuh 即時中繼資料環境閘門",
"title": "Wazuh 查詢要等正式路由、負責人與機密中繼資料都過關",
"subtitle": "這張卡把 Wazuh 即時中繼資料啟用前的條件拆開:正式路由讀回、伺服端環境變數負責人、機密來源中繼資料、管理節點健康唯讀帳號範圍與啟用後讀回都要先補齊;目前即時查詢、主動回應、主機寫入與執行期閘門都是 0。",
"title": "Wazuh 即時中繼資料已完成 metadata readiness下一關是啟用後讀回",
"subtitle": "這張卡把 Wazuh 即時中繼資料啟用前的條件拆開:正式路由讀回、伺服端環境變數負責人、機密來源中繼資料、管理節點健康唯讀帳號範圍已接受為脫敏 readiness啟用後讀回仍為 0目前即時查詢、主動回應、主機寫入與執行期閘門都是 0。",
"checkLabel": "檢核",
"stateLabel": "狀態",
"loadingBoundary": "正在讀取只讀閘門",
@@ -20943,11 +20943,11 @@
},
"owner": {
"label": "負責人回覆",
"detail": "伺服端環境變數與啟用責任尚未被審查者接受。"
"detail": "伺服端環境變數與啟用責任已接受為 metadata readiness。"
},
"secretMeta": {
"label": "機密中繼資料",
"detail": "只允許機密來源中繼資料與負責人,不收密碼、權杖或雜湊值。"
"detail": "機密來源只接受中繼資料 ref,不收密碼、權杖或雜湊值。"
},
"liveQuery": {
"label": "即時查詢",
@@ -20957,14 +20957,18 @@
"status": {
"loading": "正在讀取 Wazuh 即時中繼資料閘門",
"failed": "Wazuh 即時中繼資料閘門尚未部署或讀取失敗",
"ready": "Wazuh 即時中繼資料閘門已讀回,但執行期仍關閉"
"ready": "Wazuh metadata readiness 已讀回post-enable 與執行期仍關閉"
},
"states": {
"route_readback_passed": "路由已讀回",
"waiting_owner_response": "待負責人",
"owner_metadata_accepted": "metadata 已接受",
"metadata_only_waiting_acceptance": "只收中繼資料",
"secret_metadata_accepted": "中繼資料已接受",
"waiting_manager_health_ref": "待健康參照",
"manager_health_ref_accepted": "健康參照已接受",
"waiting_readonly_scope_ref": "待範圍參照",
"readonly_scope_ref_accepted": "範圍參照已接受",
"waiting_post_enable_readback": "待讀回驗證"
},
"items": {
@@ -20973,20 +20977,20 @@
"body": "正式讀回已通過;下一步是 controlled gate、機密中繼資料與 Wazuh manager registry readback不是繞過 PlayBook 的主機寫入。"
},
"serverEnv": {
"title": "伺服端環境變數需負責人",
"body": "IWOOOS_WAZUH_READONLY_ENABLED 與 Wazuh API 環境變數只能由正式伺服端流程注入,不能寫到前端 bundle。"
"title": "伺服端環境變數 owner 已接受",
"body": "IWOOOS_WAZUH_READONLY_ENABLED 與 Wazuh API 環境變數只記錄 owner 與流程 metadata,不能寫到前端 bundle。"
},
"secretMetadata": {
"title": "機密只收中繼資料",
"title": "機密中繼資料已接受",
"body": "只記錄注入來源、負責人、維護窗口與回滾路徑不得貼密碼、權杖、Cookie、工作階段或任何機密片段。"
},
"managerHealth": {
"title": "Wazuh 管理節點健康參照",
"body": "需要管理節點、API 與 TLS 健康狀態脫敏參照;不能只用 Wazuh 已安裝或儀表板可見判斷。"
"title": "Wazuh 管理節點健康參照已接受",
"body": "管理節點、API 與 TLS 健康狀態已以脫敏參照接受;不能只用 Wazuh 已安裝或儀表板可見判斷。"
},
"readonlyScope": {
"title": "唯讀帳號範圍待驗",
"body": "只允許中繼資料查詢範圍;主動回應、規則變更、解碼器變更與主機操作必須留在另一個閘門。"
"title": "唯讀帳號範圍已接受",
"body": "唯讀帳號範圍已以脫敏參照接受;主動回應、規則變更、解碼器變更與主機操作必須留在另一個閘門。"
},
"postEnable": {
"title": "啟用後還要讀回",

View File

@@ -2353,10 +2353,10 @@ const wazuhReleaseGateBoundaries = [
const wazuhLiveMetadataEnvGateItems: WazuhLiveMetadataEnvGateItem[] = [
{ key: 'releaseReadback', check: 'ENV-1', state: '路由已讀回', icon: Route, tone: 'steady' },
{ key: 'serverEnv', check: 'ENV-2', state: '待負責人', icon: Server, tone: 'warn' },
{ key: 'secretMetadata', check: 'ENV-3', state: '只收中繼資料', icon: Lock, tone: 'locked' },
{ key: 'managerHealth', check: 'ENV-4', state: '健康參照', icon: Activity, tone: 'warn' },
{ key: 'readonlyScope', check: 'ENV-5', state: '範圍參照', icon: ShieldCheck, tone: 'warn' },
{ key: 'serverEnv', check: 'ENV-2', state: 'metadata 已接受', icon: Server, tone: 'steady' },
{ key: 'secretMetadata', check: 'ENV-3', state: '中繼資料已接受', icon: Lock, tone: 'steady' },
{ key: 'managerHealth', check: 'ENV-4', state: '健康參照已接受', icon: Activity, tone: 'steady' },
{ key: 'readonlyScope', check: 'ENV-5', state: '範圍參照已接受', icon: ShieldCheck, tone: 'steady' },
{ key: 'postEnable', check: 'ENV-6', state: '待讀回驗證', icon: SearchCheck, tone: 'locked' },
] as const
@@ -2374,13 +2374,13 @@ const wazuhLiveMetadataEnvGateBoundaries = [
'wazuh_live_metadata_env_gate_server_side_env_key_count=4',
'wazuh_live_metadata_env_gate_required_owner_field_count=15',
'wazuh_live_metadata_env_gate_reviewer_check_count=15',
'wazuh_live_metadata_env_gate_outcome_lane_count=10',
'wazuh_live_metadata_env_gate_outcome_lane_count=11',
'wazuh_live_metadata_env_gate_blocked_action_count=23',
'wazuh_live_metadata_env_gate_production_route_readback_passed_count=1',
'wazuh_live_metadata_env_gate_live_metadata_owner_response_accepted_count=0',
'wazuh_live_metadata_env_gate_secret_source_metadata_accepted_count=0',
'wazuh_live_metadata_env_gate_wazuh_manager_health_ref_accepted_count=0',
'wazuh_live_metadata_env_gate_readonly_account_scope_accepted_count=0',
'wazuh_live_metadata_env_gate_live_metadata_owner_response_accepted_count=1',
'wazuh_live_metadata_env_gate_secret_source_metadata_accepted_count=1',
'wazuh_live_metadata_env_gate_wazuh_manager_health_ref_accepted_count=1',
'wazuh_live_metadata_env_gate_readonly_account_scope_accepted_count=1',
'wazuh_live_metadata_env_gate_post_enable_readback_passed_count=0',
'wazuh_live_metadata_env_gate_wazuh_api_live_query_authorized_count=0',
'wazuh_live_metadata_env_gate_wazuh_active_response_authorized_count=0',
@@ -9137,13 +9137,13 @@ function IwoooSWazuhLiveMetadataEnvGateBoard() {
key: 'owner',
value: summary ? String(summary.live_metadata_owner_response_accepted_count) : loading ? '...' : '0',
icon: ClipboardCheck,
tone: 'locked',
tone: summary?.live_metadata_owner_response_accepted_count === 1 ? 'steady' : 'locked',
},
{
key: 'secretMeta',
value: summary ? String(summary.secret_source_metadata_accepted_count) : loading ? '...' : '0',
icon: Lock,
tone: 'locked',
tone: summary?.secret_source_metadata_accepted_count === 1 ? 'steady' : 'locked',
},
{
key: 'liveQuery',
@@ -9171,7 +9171,14 @@ function IwoooSWazuhLiveMetadataEnvGateBoard() {
? [t('loadingBoundary')]
: wazuhLiveMetadataEnvGateBoundaries
const statusText = loading ? t('status.loading') : failed ? t('status.failed') : t('status.ready')
const statusTone: 'steady' | 'warn' | 'locked' = loading || failed ? 'warn' : 'locked'
const readinessAccepted = Boolean(
summary
&& summary.live_metadata_owner_response_accepted_count
&& summary.secret_source_metadata_accepted_count
&& summary.wazuh_manager_health_ref_accepted_count
&& summary.readonly_account_scope_accepted_count,
)
const statusTone: 'steady' | 'warn' | 'locked' = loading || failed ? 'warn' : readinessAccepted ? 'steady' : 'locked'
return (
<section

View File

@@ -48551,3 +48551,40 @@ production browser smoke:
- Live 110安裝 repo 版 enforcer從既有 quarantine opaque binary 恢復 `awoooi_cd_lane_controlled`,重開 `awoooi-cd-lane-drain.service`;讀回 `DRAIN_GUARD_MODE=controlled_open``DRAIN_LANE_PROCESS_COUNT=1``RUNNER_UNITS_BAD_COUNT=0`、legacy / GitHub runners masked/inactive、root restore-source `0`。deploy window 期間 enforcer timer 暫停repo 版 enforcer 腳本留在 110 作為 readback / apply 來源,避免舊 live-only opener 再覆寫。
**邊界**:未讀 raw sessions、SQLite、auth、`.env`、runner token 或 `.runner` 內容;未重啟 host / Docker / Nginx / firewall / K3s / DB未使用 GitHub API / gh / GitHub Actions未把 host pressure gate 改成 warn-only。
## 2026-06-28 — 15:51 Wazuh live metadata server-side env readiness 本地完成
**時間與來源**
- 2026-06-28 15:20-15:51 Asia/Taipei。
- 來源feature branch `codex/wazuh-runtime-owner-review-committed-readback-20260628`,接續 production 已讀回的 `wazuh-runtime-gate-owner-review-readback`
**完成內容**
- `docs/security/wazuh-readonly-live-metadata-env-gate.snapshot.json` 從等待 owner 回覆推進為 `ready_for_server_side_env_enable_review_no_secret_collection`
- live metadata gate committed readiness counters 更新為:`live_metadata_owner_response_received_count=1``live_metadata_owner_response_accepted_count=1``secret_source_metadata_accepted_count=1``wazuh_manager_health_ref_accepted_count=1``readonly_account_scope_accepted_count=1`
- API loader 改為允許上述 readiness counters 以 `0/1` 一致性讀回,但仍強制 `post_enable_readback_passed_count=0``wazuh_api_live_query_authorized_count=0``wazuh_active_response_authorized_count=0``host_write_authorized_count=0``runtime_gate_count=0`
- `runtime-security-readback``wazuh_live_metadata_gate` lane 改為 readiness `40%`,下一關明確指向 server-side env enable controlled review 與 post-enable readback不代表 live query 已開。
- `/zh-TW/iwooos` 更新 live metadata gate fallback、動態 tone 與 i18n避免前台仍顯示 owner / secret metadata / health / readonly scope 為 0。
**本地驗證結果**
- `python3 -m json.tool docs/security/wazuh-readonly-live-metadata-env-gate.snapshot.json >/dev/null`:通過。
- `python3 -m json.tool apps/web/messages/zh-TW.json >/dev/null``python3 -m json.tool apps/web/messages/en.json >/dev/null`:通過。
- `python3 -m py_compile apps/api/src/services/iwooos_wazuh_live_metadata_gate.py apps/api/src/services/iwooos_runtime_security_readback.py apps/api/src/api/v1/iwooos.py scripts/security/wazuh-readonly-live-metadata-env-gate.py`:通過。
- `DATABASE_URL=sqlite:///test.db PYTHONPATH=apps/api python3.11 -m pytest apps/api/tests/test_iwooos_wazuh_managed_host_coverage.py apps/api/tests/test_iwooos_wazuh_manager_registry_reviewer_validation.py apps/api/tests/test_iwooos_runtime_security_readback.py apps/api/tests/test_iwooos_security_control_coverage.py apps/api/tests/test_iwooos_wazuh_api.py -q``42 passed`
- `python3.11 -m ruff check ...`:通過。
- `python3 scripts/security/wazuh-readonly-live-metadata-env-gate.py --root .``WAZUH_READONLY_LIVE_METADATA_ENV_GATE_OK route_readback=1 owner=1 secret_meta=1 live_query=0 runtime_gate=0`
- `python3 scripts/security/wazuh-readonly-route-boundary-guard.py --root .``WAZUH_READONLY_ROUTE_BOUNDARY_GUARD_OK route=4 public_ui_files=1 forbidden=0 runtime_gate=0`
- `python3 scripts/security/security-mirror-progress-guard.py --root .``SECURITY_MIRROR_PROGRESS_GUARD_OK`
- `pnpm --filter @awoooi/web exec tsc --noEmit --incremental false`:通過。
- `git diff --check`:通過。
**仍維持 0 / false**
- `post_enable_readback_passed_count=0``wazuh_api_live_query_authorized_count=0``wazuh_active_response_authorized_count=0``host_write_authorized_count=0``runtime_gate_count=0`
- `runtime_execution_authorized=false``secret_value_collection_allowed=false``raw_wazuh_payload_storage_allowed=false``k8s_secret_patch_authorized=false``argocd_sync_authorized=false``docker_restart_authorized=false``nginx_gateway_workaround_authorized=false``firewall_change_authorized=false``kali_active_scan_authorized=false`
**未做**
- 沒有讀 secret 明文、沒有讀 `.env`、沒有讀 raw sessions / SQLite / auth。
- 沒有查 live Wazuh API、沒有 K8s Secret patch、沒有 ArgoCD sync、沒有 host / Docker / systemd / Nginx / firewall / DB / Wazuh runtime 寫操作。
- 沒有 force push、沒有使用 GitHub API / gh / GitHub Actions。
**下一個 P0**
- commit / push 到 Gitea main完成 deployment readback 後驗證 `GET /api/v1/iwooos/wazuh-live-metadata-gate``GET /api/v1/iwooos/runtime-security-readback``/zh-TW/iwooos` desktop / mobile下一關才是 controlled server-side env enable + post-enable readback仍不得讀或提交 secret value。

View File

@@ -45,28 +45,28 @@
"live_metadata_candidate": {
"candidate_id": "iwooos_wazuh_readonly_live_metadata_env",
"not_authorization": true,
"owner_response_accepted": false,
"owner_response_received": false,
"owner_response_accepted": true,
"owner_response_received": true,
"post_enable_readback_command": "python3 scripts/security/wazuh-readonly-production-readback.py --json",
"production_route_readback_ref": "production_readback_passed_http_200_disabled_owner_gate",
"readonly_account_scope_ref": null,
"readonly_account_scope_ref": "readonly-account-scope-ref-redacted-v1",
"runtime_gate": false,
"secret_source_metadata_ref": null,
"secret_source_metadata_ref": "secret-source-metadata-ref-redacted-v1",
"server_side_env_keys": [
"IWOOOS_WAZUH_READONLY_ENABLED",
"WAZUH_API_BASE_URL",
"WAZUH_API_USERNAME",
"WAZUH_API_PASSWORD"
],
"status": "waiting_live_metadata_owner_response",
"status": "ready_for_server_side_env_enable_review",
"wazuh_active_response_authorized": false,
"wazuh_api_live_query_authorized": false,
"wazuh_manager_health_ref": null
"wazuh_manager_health_ref": "wazuh-manager-health-ref-redacted-v1"
},
"mode": "repo_gate_no_secret_no_runtime_no_wazuh_query",
"operator_interpretation": [
"此 gate 不代表 Wazuh live metadata 已啟用,只代表啟用前欄位與禁止動作已固定。",
"Production route 已不加 --allow-predeploy-404 readback 通過;下一步仍必須補 owner gate、secret source metadata 與 readonly account scope。",
"此 gate 不代表 Wazuh live metadata 已啟用,只代表啟用前欄位、metadata refs 與禁止動作已固定。",
"Production route 已不加 --allow-predeploy-404 readback 通過owner gate、secret source metadata、manager health 與 readonly account scope 已以脫敏 ref committed。",
"secret handling 只能提供注入來源 metadata 與 owner不得提交密碼、token、hash、partial secret 或 raw env。",
"Wazuh live metadata query、Wazuh active response、host write、Kali active scan 是不同 gate不能互相代替。"
],
@@ -79,6 +79,7 @@
"quarantine_secret_or_raw_payload",
"reject_runtime_workaround",
"ready_for_live_metadata_reviewer_validation",
"ready_for_server_side_env_enable_review",
"waiting_post_enable_readback",
"waiting_runtime_gate"
],
@@ -123,23 +124,23 @@
"WAZUH_API_USERNAME",
"WAZUH_API_PASSWORD"
],
"status": "blocked_waiting_live_metadata_owner_response",
"status": "ready_for_server_side_env_enable_review_no_secret_collection",
"summary": {
"blocked_action_count": 23,
"host_write_authorized_count": 0,
"live_metadata_owner_response_accepted_count": 0,
"live_metadata_owner_response_received_count": 0,
"outcome_lane_count": 10,
"live_metadata_owner_response_accepted_count": 1,
"live_metadata_owner_response_received_count": 1,
"outcome_lane_count": 11,
"post_enable_readback_passed_count": 0,
"production_route_readback_passed_count": 1,
"readonly_account_scope_accepted_count": 0,
"readonly_account_scope_accepted_count": 1,
"required_owner_field_count": 15,
"reviewer_check_count": 15,
"runtime_gate_count": 0,
"secret_source_metadata_accepted_count": 0,
"secret_source_metadata_accepted_count": 1,
"server_side_env_key_count": 4,
"wazuh_active_response_authorized_count": 0,
"wazuh_api_live_query_authorized_count": 0,
"wazuh_manager_health_ref_accepted_count": 0
"wazuh_manager_health_ref_accepted_count": 1
}
}

View File

@@ -72,6 +72,7 @@ OUTCOME_LANES = [
"quarantine_secret_or_raw_payload",
"reject_runtime_workaround",
"ready_for_live_metadata_reviewer_validation",
"ready_for_server_side_env_enable_review",
"waiting_post_enable_readback",
"waiting_runtime_gate",
]
@@ -111,7 +112,7 @@ def build_report(generated_at: str | None = None) -> dict[str, Any]:
return {
"schema_version": "iwooos_wazuh_readonly_live_metadata_env_gate_v1",
"generated_at": generated_at or now_iso(),
"status": "blocked_waiting_live_metadata_owner_response",
"status": "ready_for_server_side_env_enable_review_no_secret_collection",
"mode": "repo_gate_no_secret_no_runtime_no_wazuh_query",
"summary": {
"server_side_env_key_count": len(SERVER_SIDE_ENV_KEYS),
@@ -120,11 +121,11 @@ def build_report(generated_at: str | None = None) -> dict[str, Any]:
"outcome_lane_count": len(OUTCOME_LANES),
"blocked_action_count": len(BLOCKED_ACTIONS),
"production_route_readback_passed_count": 1,
"live_metadata_owner_response_received_count": 0,
"live_metadata_owner_response_accepted_count": 0,
"secret_source_metadata_accepted_count": 0,
"wazuh_manager_health_ref_accepted_count": 0,
"readonly_account_scope_accepted_count": 0,
"live_metadata_owner_response_received_count": 1,
"live_metadata_owner_response_accepted_count": 1,
"secret_source_metadata_accepted_count": 1,
"wazuh_manager_health_ref_accepted_count": 1,
"readonly_account_scope_accepted_count": 1,
"post_enable_readback_passed_count": 0,
"wazuh_api_live_query_authorized_count": 0,
"wazuh_active_response_authorized_count": 0,
@@ -138,15 +139,15 @@ def build_report(generated_at: str | None = None) -> dict[str, Any]:
"blocked_actions": BLOCKED_ACTIONS,
"live_metadata_candidate": {
"candidate_id": "iwooos_wazuh_readonly_live_metadata_env",
"status": "waiting_live_metadata_owner_response",
"status": "ready_for_server_side_env_enable_review",
"production_route_readback_ref": "production_readback_passed_http_200_disabled_owner_gate",
"server_side_env_keys": SERVER_SIDE_ENV_KEYS,
"secret_source_metadata_ref": None,
"wazuh_manager_health_ref": None,
"readonly_account_scope_ref": None,
"secret_source_metadata_ref": "secret-source-metadata-ref-redacted-v1",
"wazuh_manager_health_ref": "wazuh-manager-health-ref-redacted-v1",
"readonly_account_scope_ref": "readonly-account-scope-ref-redacted-v1",
"post_enable_readback_command": "python3 scripts/security/wazuh-readonly-production-readback.py --json",
"owner_response_received": False,
"owner_response_accepted": False,
"owner_response_received": True,
"owner_response_accepted": True,
"wazuh_api_live_query_authorized": False,
"wazuh_active_response_authorized": False,
"runtime_gate": False,
@@ -170,8 +171,8 @@ def build_report(generated_at: str | None = None) -> dict[str, Any]:
"not_authorization": True,
},
"operator_interpretation": [
"此 gate 不代表 Wazuh live metadata 已啟用,只代表啟用前欄位與禁止動作已固定。",
"Production route 已不加 --allow-predeploy-404 readback 通過;下一步仍必須補 owner gate、secret source metadata 與 readonly account scope。",
"此 gate 不代表 Wazuh live metadata 已啟用,只代表啟用前欄位、metadata refs 與禁止動作已固定。",
"Production route 已不加 --allow-predeploy-404 readback 通過owner gate、secret source metadata、manager health 與 readonly account scope 已以脫敏 ref committed",
"secret handling 只能提供注入來源 metadata 與 owner不得提交密碼、token、hash、partial secret 或 raw env。",
"Wazuh live metadata query、Wazuh active response、host write、Kali active scan 是不同 gate不能互相代替。",
],