fix(iwooos): require ledger receipts for security closure
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m36s
CD Pipeline / build-and-deploy (push) Successful in 5m15s
CD Pipeline / post-deploy-checks (push) Successful in 3m44s

This commit is contained in:
ogt
2026-07-10 20:05:19 +08:00
parent 43ceb3b259
commit a5ff039803
5 changed files with 150 additions and 5 deletions

View File

@@ -17,6 +17,17 @@ from src.services.snapshot_paths import default_evaluations_dir, default_securit
_DEFAULT_SECURITY_DIR = default_security_dir(Path(__file__))
_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__))
_SCHEMA_VERSION = "iwooos_security_control_coverage_v1"
_REQUIRED_CONTROLLED_APPLY_STAGES = [
"sensor_source_receipt",
"normalized_asset_identity",
"source_truth_diff",
"ai_decision_candidate_action",
"risk_policy_decision",
"check_mode_dry_run_receipt",
"bounded_execution_receipt",
"independent_post_verifier",
"km_rag_mcp_playbook_write_ack",
]
_SECURITY_SNAPSHOTS = {
"asset_ledger": "security-asset-control-ledger.snapshot.json",
@@ -88,7 +99,7 @@ def load_latest_iwooos_security_control_coverage(
"no_false_green_rules": [
"納管覆蓋總表只代表 committed snapshot 可讀,不代表所有主機已被 Wazuh manager registry 驗收。",
"route 200、transport observed、UI 可見、一般工作批准都不能當成 runtime 授權。",
"IwoooS ledger 的 owner response received / accepted、live evidence accepted、active scan、active response、Telegram send、host write 仍維持 0 / false這不阻擋 AwoooP allowlisted controlled apply。",
"IwoooS ledger 的 owner response received / accepted、live evidence accepted、active scan、active response、Telegram send、host write 仍維持 0 / false這不阻擋 AwoooP allowlisted controlled apply 執行候選,但任何閉環宣稱都必須寫回 IWOOOS / AISOC ledger receipt",
"Nginx、Firewall、Workflow、Secret、K8s、Docker、systemd、AI Agent provider 變更都必須先進 execution packet、check-mode、rollback、verifier 與 KM / PlayBook trust不得繞過受控路由。",
],
"source_refs": [
@@ -378,75 +389,111 @@ def _build_summary(snapshots: dict[str, dict[str, Any]], domains: list[dict[str,
"agent_bounty_product_surface_count": len(snapshots["agent_bounty"].get("product_surfaces") or []),
"ai_agent_asset_count": len(snapshots["ai_agent_automation"].get("assets") or []),
"all_scope_runtime_controlled": False,
"allowlisted_controlled_apply_bypasses_iwooos_ledger": True,
"allowlisted_controlled_apply_bypasses_iwooos_ledger": False,
"allowlisted_controlled_apply_requires_iwooos_ledger_receipt": True,
"controlled_apply_ledger_contract": "same_run_iwooos_aisoc_trace_required",
"controlled_apply_policy": "low_medium_high_allowed_after_allowlist_check_mode_rollback_verifier_km",
"critical_break_glass_required": True,
}
def _build_p0_next_actions() -> list[dict[str, str]]:
return [
def _build_p0_next_actions() -> list[dict[str, Any]]:
actions: list[dict[str, Any]] = [
{
"priority": "P0-01",
"title": "全域資安完成口徑與 owner closure",
"required_evidence": "每個主機、服務、產品、網站、工具、套件與 AI Agent 都要有 scope、owner、risk、verifier、runtime acceptance 欄位UI / API / CD 綠燈不得算完成。",
"asset_scope_ids": ["hosts", "services", "products", "websites", "tools", "packages", "ai_agents"],
"next_executable_action": "bind_security_program_queue_to_same_run_runtime_receipt_contract",
},
{
"priority": "P0-02",
"title": "全資產 / 全主機 / 全服務 scope truth",
"required_evidence": "Gitea source truth、runtime surface inventory、host/service live hash、公開入口、runner、backup、AI tool 權限與缺口清單;不得用單一 dashboard 代表全域。",
"asset_scope_ids": ["hosts", "services", "products", "websites"],
"next_executable_action": "reconcile_committed_inventory_with_production_readback_and_create_gap_work_items",
},
{
"priority": "P0-03",
"title": "Wazuh manager registry、FIM、弱點與告警 receipt",
"required_evidence": "manager registry parity、agent active/disconnected rollup、FIM baseline、vulnerability detection rollup、alert sample receipt、TLS/RBAC readback、缺席主機 decision。",
"asset_scope_ids": ["hosts", "services", "tools", "observability_and_security"],
"next_executable_action": "attach_wazuh_fim_vulnerability_alert_case_and_post_verifier_receipts",
},
{
"priority": "P0-04",
"title": "Host / Docker / systemd 入侵與鑑識基線",
"required_evidence": "auth、sudo、process、network、persistence、package、service、Docker event 的脫敏 readback所有 remediation 先進 check-mode、rollback、post-verifier。",
"asset_scope_ids": ["hosts", "services", "packages"],
"next_executable_action": "build_public_safe_host_service_forensics_baseline_and_ansible_check_mode_candidates",
},
{
"priority": "P0-05",
"title": "Nginx / Gateway / SSH / Firewall / K8s network",
"required_evidence": "source-to-live diff、nginx -t 或等價檢核、route smoke、before/after actor、NetworkPolicy / firewall diff、rollback owner。",
"asset_scope_ids": ["hosts", "services", "websites"],
"next_executable_action": "stage_network_gateway_source_live_diff_check_mode_and_rollback_verifiers",
},
{
"priority": "P0-06",
"title": "Web / API / AppSec / webhook 防護",
"required_evidence": "auth、authorization、session、rate limit、CORS、security headers、webhook abuse case、ASVS mapping、desktop/mobile smoke 與 no sensitive copy。",
"asset_scope_ids": ["products", "websites", "services"],
"next_executable_action": "create_bounded_appsec_canary_and_webhook_abuse_regression_receipts",
},
{
"priority": "P0-07",
"title": "套件 / container / workflow supply-chain",
"required_evidence": "SBOM、lockfile diff、image scan、KEV/EPSS priority、runner/workflow diff、artifact provenance、signature verification、package SLA。",
"asset_scope_ids": ["products", "packages", "tools"],
"next_executable_action": "attach_sbom_image_scan_workflow_provenance_and_no_secret_output_receipts",
},
{
"priority": "P0-08",
"title": "SIEM / SOAR / Monitoring 告警閉環",
"required_evidence": "Wazuh / Alertmanager / Telegram / OCSF / Sigma normalized event、dedupe、noise budget、case id、receiver receipt、operator acknowledgment。",
"asset_scope_ids": ["observability_and_security", "tools", "ai_agents"],
"next_executable_action": "normalize_alert_events_to_cases_and_queue_controlled_response_candidates",
},
{
"priority": "P0-09",
"title": "Backup / restore / forensic retention",
"required_evidence": "restore drill、offsite/escrow、chain of custody、retention policy、backup freshness、rollback proof、post-restore smoke。",
"asset_scope_ids": ["data_and_backup", "products", "services"],
"next_executable_action": "bind_backup_restore_drill_receipts_to_security_incident_closure",
},
{
"priority": "P0-10",
"title": "AI Agent / MCP / RAG permission gate",
"required_evidence": "tool allowlist、prompt redaction、secret boundary、RAG source trust、MCP connector scope、cost cap、replay/shadow/canary、KM / PlayBook writeback。",
"asset_scope_ids": ["ai_agents", "tools", "data_and_backup"],
"next_executable_action": "build_cross_product_mcp_rag_capability_registry_and_runtime_receipt_gate",
},
{
"priority": "P0-11",
"title": "AISOC 管理者 UI / UX 控制室",
"required_evidence": "單一風險地圖、目前 P0、blocked reason、next executable action、tool coverage、host/service/product/package drilldown避免以大段文字取代狀態。",
"asset_scope_ids": ["websites", "products", "observability_and_security"],
"next_executable_action": "replace_text_wall_with_first_viewport_risk_map_queue_and_drilldown_cockpit",
},
{
"priority": "P0-12",
"title": "Controlled apply deployment 與 production readback",
"required_evidence": "target selector、source-of-truth diff、check-mode/dry-run、rollback、post-apply verifier、runtime readback、KM / PlayBook trust、deploy marker。",
"asset_scope_ids": ["hosts", "services", "products", "tools", "ai_agents"],
"next_executable_action": "run_allowlisted_same_run_controlled_apply_chain_and_write_iwooos_ledger_receipt",
},
]
for action in actions:
action["work_item_id"] = f"IWOOOS-SEC-{action['priority']}"
action["status"] = "runtime_closure_required"
action["source_truth_layer"] = "production_runtime_receipt_first"
action["runtime_credit_policy"] = "no_credit_until_same_run_iwooos_aisoc_receipts_exist"
action["requires_iwooos_ledger_receipt"] = True
action["required_controlled_apply_stages"] = list(_REQUIRED_CONTROLLED_APPLY_STAGES)
action["critical_break_glass_required"] = True
action["controlled_apply_allowed_risk_levels"] = ["low", "medium", "high"]
return actions
def _build_professional_security_governance_review(

View File

@@ -548,9 +548,16 @@ def _next_executable_queue(
"track_id": "wazuh_detection_response",
"state": registry_gate,
"next_action": wazuh_next_action,
"next_executable_action": wazuh_next_action,
"ready_signal_count": _int(
wazuh_verifier.get("verifier_ready_signal_count")
),
"required_signal_count": 6,
"missing_signal_count": max(
6 - _int(wazuh_verifier.get("verifier_ready_signal_count")),
0,
),
"required_verifier": "wazuh_registry_fim_vulnerability_alert_receipt_post_verifier",
"controlled_apply_policy_allowed": True,
},
{
@@ -558,6 +565,11 @@ def _next_executable_queue(
"track_id": "supply_chain_sbom_scan",
"state": "sbom_and_scan_artifacts_missing",
"next_action": "stage_trivy_syft_grype_check_mode_reports",
"next_executable_action": "stage_trivy_syft_grype_check_mode_reports",
"ready_signal_count": 0,
"required_signal_count": 5,
"missing_signal_count": 5,
"required_verifier": "sbom_vulnerability_artifact_post_verifier",
"controlled_apply_policy_allowed": True,
},
{
@@ -565,10 +577,21 @@ def _next_executable_queue(
"track_id": "ai_agent_controlled_apply",
"state": "preflight_ready_for_controlled_policy_check",
"next_action": "connect_target_selector_diff_check_mode_rollback_post_verifier_km",
"next_executable_action": "connect_target_selector_diff_check_mode_rollback_post_verifier_km",
"ready_signal_count": _int(
controlled_apply.get("controlled_apply_preflight_ready_count")
)
+ _int(dry_run.get("dry_run_result_ref_count")),
"required_signal_count": 9,
"missing_signal_count": max(
9
- (
_int(controlled_apply.get("controlled_apply_preflight_ready_count"))
+ _int(dry_run.get("dry_run_result_ref_count"))
),
0,
),
"required_verifier": "ai_controlled_apply_same_run_post_verifier_km_writeback",
"controlled_apply_policy_allowed": True,
},
]

View File

@@ -1,5 +1,9 @@
from __future__ import annotations
import os
os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test")
from fastapi import FastAPI
from fastapi.testclient import TestClient
@@ -107,7 +111,11 @@ def test_iwooos_security_control_coverage_keeps_runtime_gates_closed() -> None:
assert summary["agent_bounty_runtime_gate_open_count"] == 0
assert summary["ai_agent_runtime_write_gate_open_count"] == 0
assert summary["all_scope_runtime_controlled"] is False
assert summary["allowlisted_controlled_apply_bypasses_iwooos_ledger"] is True
assert summary["allowlisted_controlled_apply_bypasses_iwooos_ledger"] is False
assert summary["allowlisted_controlled_apply_requires_iwooos_ledger_receipt"] is True
assert summary["controlled_apply_ledger_contract"] == (
"same_run_iwooos_aisoc_trace_required"
)
assert (
summary["controlled_apply_policy"]
== "low_medium_high_allowed_after_allowlist_check_mode_rollback_verifier_km"
@@ -135,3 +143,23 @@ def test_iwooos_security_control_coverage_api_is_public_safe() -> None:
assert "runtime_control_blocked" not in response.text
assert "工作視窗" not in response.text
assert "批准!繼續" not in response.text
def test_iwooos_security_control_coverage_p0_actions_are_executable_contracts() -> None:
payload = load_latest_iwooos_security_control_coverage()
actions = payload["p0_next_actions"]
assert len(actions) == 12
assert all(action["work_item_id"].startswith("IWOOOS-SEC-P0-") for action in actions)
assert all(action["requires_iwooos_ledger_receipt"] is True for action in actions)
assert all(action["next_executable_action"] for action in actions)
assert all(action["asset_scope_ids"] for action in actions)
assert all(
action["runtime_credit_policy"]
== "no_credit_until_same_run_iwooos_aisoc_receipts_exist"
for action in actions
)
assert all(
"bounded_execution_receipt" in action["required_controlled_apply_stages"]
for action in actions
)

View File

@@ -1,5 +1,9 @@
from __future__ import annotations
import os
os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test")
from fastapi import FastAPI
from fastapi.testclient import TestClient
@@ -106,6 +110,22 @@ def test_iwooos_security_tool_closure_readback_marks_partial_vs_missing_tracks()
assert tracks["ai_agent_controlled_apply"]["missing_signal_count"] >= 0
def test_iwooos_security_tool_closure_queue_has_executable_receipt_contract() -> None:
payload = load_latest_iwooos_security_tool_closure_readback()
queue = {item["queue_id"]: item for item in payload["next_executable_queue"]}
assert set(queue) == {"P0-03", "P0-07", "P0-08"}
assert queue["P0-03"]["track_id"] == "wazuh_detection_response"
assert queue["P0-03"]["required_signal_count"] == 6
assert queue["P0-03"]["missing_signal_count"] >= 0
assert queue["P0-03"]["required_verifier"] == (
"wazuh_registry_fim_vulnerability_alert_receipt_post_verifier"
)
assert all(item["next_executable_action"] for item in queue.values())
assert all(item["required_signal_count"] > 0 for item in queue.values())
assert all(item["controlled_apply_policy_allowed"] is True for item in queue.values())
def test_iwooos_security_tool_closure_readback_accepts_alert_receipt_signal() -> None:
payload = load_latest_iwooos_security_tool_closure_readback(
alert_receipt_readback={

View File

@@ -682,6 +682,16 @@ export interface IwoooSSecurityControlCoverageProfessionalReview {
priority: string
title: string
required_evidence: string
work_item_id?: string
status?: string
source_truth_layer?: string
runtime_credit_policy?: string
requires_iwooos_ledger_receipt?: boolean
asset_scope_ids?: string[]
next_executable_action?: string
required_controlled_apply_stages?: string[]
critical_break_glass_required?: boolean
controlled_apply_allowed_risk_levels?: string[]
}>
security_tool_integration_matrix: IwoooSSecurityControlCoverageToolTrack[]
ai_automation_closure_loop: IwoooSSecurityControlCoverageAiLoopStage[]
@@ -730,6 +740,9 @@ export interface IwoooSSecurityControlCoverageResponse {
full_scope_contract_count: number
ui_ux_control_room_requirement_count: number
all_scope_runtime_controlled: boolean
allowlisted_controlled_apply_bypasses_iwooos_ledger?: boolean
allowlisted_controlled_apply_requires_iwooos_ledger_receipt?: boolean
controlled_apply_ledger_contract?: string
}
domains: IwoooSSecurityControlCoverageDomain[]
professional_review: IwoooSSecurityControlCoverageProfessionalReview
@@ -737,6 +750,16 @@ export interface IwoooSSecurityControlCoverageResponse {
priority: string
title: string
required_evidence: string
work_item_id?: string
status?: string
source_truth_layer?: string
runtime_credit_policy?: string
requires_iwooos_ledger_receipt?: boolean
asset_scope_ids?: string[]
next_executable_action?: string
required_controlled_apply_stages?: string[]
critical_break_glass_required?: boolean
controlled_apply_allowed_risk_levels?: string[]
}>
no_false_green_rules: string[]
source_refs: string[]
@@ -784,7 +807,11 @@ export interface IwoooSSecurityToolClosureQueueItem {
track_id: IwoooSSecurityToolClosureTrack['track_id']
state: string
next_action: string
next_executable_action?: string
ready_signal_count?: number
required_signal_count?: number
missing_signal_count?: number
required_verifier?: string
controlled_apply_policy_allowed: boolean
}