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
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:
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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={
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user