649 lines
28 KiB
JSON
649 lines
28 KiB
JSON
{
|
||
"schema_version": "runtime_surface_inventory_v1",
|
||
"generated_at": "2026-06-05T09:47:25+08:00",
|
||
"program_status": {
|
||
"overall_completion_percent": 100,
|
||
"current_priority": "P1",
|
||
"current_task_id": "P1-001",
|
||
"next_task_id": "P1-002",
|
||
"read_only_mode": true
|
||
},
|
||
"source_refs": [
|
||
"docs/schemas/runtime_surface_inventory_v1.schema.json",
|
||
"k8s/awoooi-prod/kustomization.yaml",
|
||
"k8s/awoooi-prod/05-deployment-web.yaml",
|
||
"k8s/awoooi-prod/06-deployment-api.yaml",
|
||
"k8s/awoooi-prod/08-deployment-worker.yaml",
|
||
"k8s/awoooi-prod/10-deployment-auto-repair-canary.yaml",
|
||
"k8s/awoooi-prod/13-cronjob-k3s-report.yaml",
|
||
"k8s/awoooi-prod/14-cronjob-weekly-report.yaml",
|
||
"k8s/awoooi-prod/15-cronjob-km-vectorize.yaml",
|
||
"k8s/awoooi-prod/12-cronjob-drift-scanner.yaml",
|
||
"k8s/awoooi-prod/03-secrets.example.yaml",
|
||
"k8s/awoooi-prod/04-repair-ssh-key-template.yaml",
|
||
"k8s/awoooi-prod/04-repair-known-hosts-template.yaml",
|
||
"k8s/awoooi-prod/04-ssh-mcp-secret.example.yaml",
|
||
"k8s/awoooi-prod/07-rbac.yaml",
|
||
"k8s/awoooi-prod/09-pdb.yaml",
|
||
"k8s/awoooi-prod/11-vpa.yaml",
|
||
"k8s/awoooi-prod/12-hpa.yaml",
|
||
"k8s/awoooi-prod/02-network-policy.yaml",
|
||
".gitea/workflows/cd.yaml"
|
||
],
|
||
"rollups": {
|
||
"total_surfaces": 22,
|
||
"by_kind": {
|
||
"deployment": 4,
|
||
"service": 2,
|
||
"ingress": 1,
|
||
"cronjob": 4,
|
||
"configmap": 2,
|
||
"secret": 4,
|
||
"rbac": 1,
|
||
"policy": 2,
|
||
"autoscaler": 1,
|
||
"availability": 1
|
||
},
|
||
"by_status": {
|
||
"manifest_mapped": 16,
|
||
"action_required": 6
|
||
},
|
||
"by_evidence_level": {
|
||
"committed_manifest": 17,
|
||
"live_check_required": 4,
|
||
"missing_manifest": 1
|
||
},
|
||
"action_required_surface_ids": [
|
||
"external_nginx_gateway_route",
|
||
"awoooi_secrets",
|
||
"awoooi_repair_ssh_key_secret",
|
||
"awoooi_repair_known_hosts_secret",
|
||
"ssh_mcp_key_secret",
|
||
"hpa_vpa_autoscaler_contract"
|
||
],
|
||
"secret_surface_ids": [
|
||
"awoooi_secrets",
|
||
"awoooi_repair_ssh_key_secret",
|
||
"awoooi_repair_known_hosts_secret",
|
||
"ssh_mcp_key_secret"
|
||
],
|
||
"live_check_missing_surface_ids": [
|
||
"external_nginx_gateway_route",
|
||
"awoooi_secrets",
|
||
"awoooi_repair_ssh_key_secret",
|
||
"awoooi_repair_known_hosts_secret",
|
||
"ssh_mcp_key_secret",
|
||
"hpa_vpa_autoscaler_contract"
|
||
],
|
||
"total_source_components": 9,
|
||
"source_components_with_runtime_binding": 9
|
||
},
|
||
"runtime_surfaces": [
|
||
{
|
||
"surface_id": "awoooi_api_deployment",
|
||
"display_name": "AWOOOI API Deployment",
|
||
"kind": "deployment",
|
||
"manifest_ref": "k8s/awoooi-prod/06-deployment-api.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "high",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "Deployment/awoooi-api replicas=2 image=192.168.0.110:5000/library/api:IMAGE_TAG_PLACEHOLDER via kustomization images",
|
||
"health_contract": "liveness /api/v1/health/live;readiness /api/v1/health/ready;public health 由 CD 使用 https://awoooi.wooo.work/api/v1/health 驗證",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/06-deployment-api.yaml",
|
||
"k8s/awoooi-prod/kustomization.yaml",
|
||
".gitea/workflows/cd.yaml"
|
||
],
|
||
"next_action": "P1-002 盤點 runner / rollout evidence 時,只能讀取 rollout status 與健康證據,不得 restart、scale 或 patch。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_web_deployment",
|
||
"display_name": "AWOOOI Web Deployment",
|
||
"kind": "deployment",
|
||
"manifest_ref": "k8s/awoooi-prod/05-deployment-web.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "Deployment/awoooi-web replicas=2 image=192.168.0.110:5000/library/web:IMAGE_TAG_PLACEHOLDER via kustomization images",
|
||
"health_contract": "liveness /api/health;readiness /api/health;NEXT_PUBLIC_API_URL 必須為 https://awoooi.wooo.work",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/05-deployment-web.yaml",
|
||
"apps/web/src/app/api/health/route.ts",
|
||
"docs/HARD_RULES.md"
|
||
],
|
||
"next_action": "前端 runtime 只允許讀取健康與 UI 證據;不得把 NodePort / internal IP 寫回 NEXT_PUBLIC bundle。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_worker_deployment",
|
||
"display_name": "AWOOOI Signal Worker Deployment",
|
||
"kind": "deployment",
|
||
"manifest_ref": "k8s/awoooi-prod/08-deployment-worker.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "high",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "Deployment/awoooi-worker replicas=1 command=python -m src.workers.signal_worker",
|
||
"health_contract": "liveness 檢查 /tmp/worker-healthy mtime;readiness /tmp/worker-ready;Redis Streams consumer group awoooi-workers",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/08-deployment-worker.yaml",
|
||
"apps/api/src/workers/signal_worker.py",
|
||
"apps/api/tests/test_runtime_bootstrap_guards.py"
|
||
],
|
||
"next_action": "P1-002 / P1-003 只讀盤點 worker heartbeat 與 queue health,不得手動刪 Pod 或 rollout restart。"
|
||
},
|
||
{
|
||
"surface_id": "auto_repair_canary_deployment",
|
||
"display_name": "Auto Repair Canary Deployment",
|
||
"kind": "deployment",
|
||
"manifest_ref": "k8s/awoooi-prod/10-deployment-auto-repair-canary.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "Deployment/awoooi-auto-repair-canary replicas=1;不承接流量、不掛 Secret、不暴露 Service",
|
||
"health_contract": "sleep loop 作為 live-fire target;只有批准後的低風險驗證可使用,不屬於本任務執行範圍",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/10-deployment-auto-repair-canary.yaml"
|
||
],
|
||
"next_action": "維持只讀標記;任何 canary 操作仍需明確批准。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_api_service",
|
||
"display_name": "AWOOOI API Service",
|
||
"kind": "service",
|
||
"manifest_ref": "k8s/awoooi-prod/06-deployment-api.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "high",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "Service/awoooi-api-svc NodePort 32334 targetPort 8000 selector app=awoooi-api",
|
||
"health_contract": "內部 CronJob 使用 http://awoooi-api-svc.awoooi-prod.svc.cluster.local:8000;外部 health 走正式域名",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/06-deployment-api.yaml",
|
||
"k8s/awoooi-prod/15-cronjob-km-vectorize.yaml",
|
||
"k8s/awoooi-prod/12-cronjob-drift-scanner.yaml"
|
||
],
|
||
"next_action": "只讀比對 Service selector / endpoint / public health,不得 patch Service 或改 NodePort。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_web_service",
|
||
"display_name": "AWOOOI Web Service",
|
||
"kind": "service",
|
||
"manifest_ref": "k8s/awoooi-prod/05-deployment-web.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "Service/awoooi-web-svc NodePort 32335 targetPort 3000 selector app=awoooi-web",
|
||
"health_contract": "public route /zh-TW/governance?tab=automation-inventory;web container health /api/health",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/05-deployment-web.yaml",
|
||
"apps/web/src/app/api/health/route.ts",
|
||
".gitea/workflows/cd.yaml"
|
||
],
|
||
"next_action": "只讀確認 public route 與 UI smoke;不得修改 Service 或 public routing。"
|
||
},
|
||
{
|
||
"surface_id": "external_nginx_gateway_route",
|
||
"display_name": "External Nginx / Domain Route",
|
||
"kind": "ingress",
|
||
"manifest_ref": "缺 Kubernetes Ingress manifest;由外部 gateway / public domain 與 NodePort health 證據承接",
|
||
"status": "action_required",
|
||
"risk_level": "high",
|
||
"evidence_level": "missing_manifest",
|
||
"runtime_binding": "https://awoooi.wooo.work -> external gateway -> NodePort 32334/32335;K8s repo 目前沒有 Ingress resource",
|
||
"health_contract": "CD 使用 public API health 與 production Playwright smoke;Ingress / gateway 設定仍需只讀外部路由盤點",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "required",
|
||
"evidence_refs": [
|
||
".gitea/workflows/cd.yaml",
|
||
"docs/HARD_RULES.md",
|
||
"k8s/awoooi-prod/05-deployment-web.yaml",
|
||
"k8s/awoooi-prod/06-deployment-api.yaml"
|
||
],
|
||
"next_action": "P1-002 只讀補 gateway / runner / DNS evidence;不得直接新增 Ingress 或改 Nginx。"
|
||
},
|
||
{
|
||
"surface_id": "k3s_status_report_cronjob",
|
||
"display_name": "K3s Status Report CronJob",
|
||
"kind": "cronjob",
|
||
"manifest_ref": "k8s/awoooi-prod/13-cronjob-k3s-report.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "CronJob/k3s-status-report schedule=0 1 * * * timeZone=Asia/Taipei command=python -m src.services.k3s_monitor_service",
|
||
"health_contract": "Telegram daily K3s status;成功不得即時洗版,失敗才需 action-required",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/13-cronjob-k3s-report.yaml",
|
||
"apps/api/src/services/k3s_monitor_service.py"
|
||
],
|
||
"next_action": "P1-002 讀取 CronJob last schedule / failure evidence;不得 create job 手動觸發。"
|
||
},
|
||
{
|
||
"surface_id": "weekly_report_cronjob",
|
||
"display_name": "Weekly Report CronJob",
|
||
"kind": "cronjob",
|
||
"manifest_ref": "k8s/awoooi-prod/14-cronjob-weekly-report.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "CronJob/weekly-report schedule=0 10 * * 5 timeZone=Asia/Taipei command=python -m src.services.weekly_report_service",
|
||
"health_contract": "每週報告;Telegram success noise suppression 必須保留",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/14-cronjob-weekly-report.yaml",
|
||
"apps/api/src/services/weekly_report_service.py"
|
||
],
|
||
"next_action": "只讀補 last run / failure-only notification evidence。"
|
||
},
|
||
{
|
||
"surface_id": "km_vectorize_cronjob",
|
||
"display_name": "KM Vectorize CronJob",
|
||
"kind": "cronjob",
|
||
"manifest_ref": "k8s/awoooi-prod/15-cronjob-km-vectorize.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "CronJob/km-vectorize schedule=0 19 * * * timeZone=Asia/Taipei command=python /app/scripts/cron_km_vectorize.py",
|
||
"health_contract": "呼叫 in-cluster API Service;failedJobsHistoryLimit=0,失敗證據應進 AwoooP/KM governance",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/15-cronjob-km-vectorize.yaml",
|
||
"scripts/cron_km_vectorize.py"
|
||
],
|
||
"next_action": "只讀確認 last schedule 與 failed row evidence,不得手動 vectorize 或重跑 job。"
|
||
},
|
||
{
|
||
"surface_id": "drift_scanner_cronjob",
|
||
"display_name": "Config Drift Scanner CronJob",
|
||
"kind": "cronjob",
|
||
"manifest_ref": "k8s/awoooi-prod/12-cronjob-drift-scanner.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "high",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "CronJob/drift-scanner schedule=0 * * * * command posts /api/v1/drift/internal/scan",
|
||
"health_contract": "只掃描 awoooi-prod;不得把 drift scan 當 active remediation 或自動 patch",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/12-cronjob-drift-scanner.yaml",
|
||
"apps/api/src/api/v1/drift.py"
|
||
],
|
||
"next_action": "P1-003 盤點 drift scanner last run / alert mapping;不得修改 alert rule 或 workflow。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_config_configmap",
|
||
"display_name": "AWOOOI ConfigMap",
|
||
"kind": "configmap",
|
||
"manifest_ref": "k8s/awoooi-prod/04-configmap.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "high",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "ConfigMap/awoooi-config mounted via envFrom in API / Web / Worker / CronJob",
|
||
"health_contract": "承載非機密 endpoint / feature flags;任何 provider order 或 internal IP 曝露需獨立審查",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/04-configmap.yaml",
|
||
"k8s/awoooi-prod/06-deployment-api.yaml",
|
||
"k8s/awoooi-prod/05-deployment-web.yaml"
|
||
],
|
||
"next_action": "P1-004 / P2 配置優化只能產 proposal;不得在本任務改 ConfigMap。"
|
||
},
|
||
{
|
||
"surface_id": "service_registry_configmap",
|
||
"display_name": "Service Registry ConfigMap",
|
||
"kind": "configmap",
|
||
"manifest_ref": "k8s/awoooi-prod/15-service-registry-configmap.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "high",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "ConfigMap/service-registry mounted at /app/ops/config/service-registry.yaml in API pod;CD 直接 apply",
|
||
"health_contract": "stateful_level BLOCK / CRITICAL_HITL / STANDARD_HITL / AUTO 是自動修復爆炸半徑守門依據",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/15-service-registry-configmap.yaml",
|
||
".gitea/workflows/cd.yaml"
|
||
],
|
||
"next_action": "只讀顯示服務分級;不得自動接受或修改 service stateful level。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_secrets",
|
||
"display_name": "AWOOOI Secrets",
|
||
"kind": "secret",
|
||
"manifest_ref": "k8s/awoooi-prod/03-secrets.example.yaml + .gitea/workflows/cd.yaml Secret injection",
|
||
"status": "action_required",
|
||
"risk_level": "critical",
|
||
"evidence_level": "live_check_required",
|
||
"runtime_binding": "Secret/awoooi-secrets referenced by API / Web / Worker / CronJob envFrom;payload 永遠不得進 snapshot",
|
||
"health_contract": "只允許 metadata / key existence / redacted policy;禁止讀取 secret 明文、base64 decode 或 log echo",
|
||
"secret_exposure": "template_only",
|
||
"live_check_status": "required",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/03-secrets.example.yaml",
|
||
".gitea/workflows/cd.yaml",
|
||
"docs/HARD_RULES.md"
|
||
],
|
||
"next_action": "P1-002 只能補 Secret metadata existence / age evidence;不得讀 payload。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_repair_ssh_key_secret",
|
||
"display_name": "Repair SSH Key Secret",
|
||
"kind": "secret",
|
||
"manifest_ref": "k8s/awoooi-prod/04-repair-ssh-key-template.yaml",
|
||
"status": "action_required",
|
||
"risk_level": "critical",
|
||
"evidence_level": "live_check_required",
|
||
"runtime_binding": "Secret/awoooi-repair-ssh-key mounted read-only into API pod /etc/repair-ssh",
|
||
"health_contract": "command= forced repair bot;只允許 template / metadata visibility;不得讀私鑰內容",
|
||
"secret_exposure": "template_only",
|
||
"live_check_status": "required",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/04-repair-ssh-key-template.yaml",
|
||
"k8s/awoooi-prod/06-deployment-api.yaml"
|
||
],
|
||
"next_action": "只讀確認 Secret 是否存在與 mount 是否健康;不得 ssh-keyscan、patch 或讀 key。"
|
||
},
|
||
{
|
||
"surface_id": "awoooi_repair_known_hosts_secret",
|
||
"display_name": "Repair known_hosts Secret",
|
||
"kind": "secret",
|
||
"manifest_ref": "k8s/awoooi-prod/04-repair-known-hosts-template.yaml + .gitea/workflows/cd.yaml",
|
||
"status": "action_required",
|
||
"risk_level": "high",
|
||
"evidence_level": "live_check_required",
|
||
"runtime_binding": "Secret/awoooi-repair-known-hosts mounted read-only into API pod /etc/repair-known-hosts",
|
||
"health_contract": "CD 需四台主機指紋完整才 patch;本任務不執行 ssh-keyscan、不更新 Secret",
|
||
"secret_exposure": "template_only",
|
||
"live_check_status": "required",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/04-repair-known-hosts-template.yaml",
|
||
".gitea/workflows/cd.yaml"
|
||
],
|
||
"next_action": "P1-002 只讀讀取 Secret metadata 與 CD evidence;不得重掃或 patch known_hosts。"
|
||
},
|
||
{
|
||
"surface_id": "ssh_mcp_key_secret",
|
||
"display_name": "SSH MCP Key Secret",
|
||
"kind": "secret",
|
||
"manifest_ref": "k8s/awoooi-prod/04-ssh-mcp-secret.example.yaml",
|
||
"status": "action_required",
|
||
"risk_level": "critical",
|
||
"evidence_level": "live_check_required",
|
||
"runtime_binding": "Secret/ssh-mcp-key mounted read-only into API pod /run/secrets/ssh_mcp_key 與 /etc/ssh-mcp/known_hosts",
|
||
"health_contract": "MCP SSH 診斷需 redaction / audit;本任務不得讀 key、不得建立 SSH session、不得修復主機",
|
||
"secret_exposure": "template_only",
|
||
"live_check_status": "required",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/04-ssh-mcp-secret.example.yaml",
|
||
"k8s/awoooi-prod/06-deployment-api.yaml"
|
||
],
|
||
"next_action": "只讀確認 metadata 與 mount path;任何 MCP SSH 執行仍需批准與 audit。"
|
||
},
|
||
{
|
||
"surface_id": "executor_rbac",
|
||
"display_name": "Executor RBAC",
|
||
"kind": "rbac",
|
||
"manifest_ref": "k8s/awoooi-prod/07-rbac.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "critical",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "ServiceAccount/awoooi-executor + ClusterRole/awoooi-executor-role + ClusterRoleBinding",
|
||
"health_contract": "允許讀取多類 K8s 資源;寫入權限限 pods delete、deployments patch、scale 等高風險操作,必須由 approval gate 阻擋",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/07-rbac.yaml",
|
||
"apps/api/src/services/executor.py"
|
||
],
|
||
"next_action": "P2 安全執行關卡前只做只讀 RBAC diff;不得修改 ClusterRole。"
|
||
},
|
||
{
|
||
"surface_id": "namespace_quota_limits",
|
||
"display_name": "Namespace Quota / LimitRange",
|
||
"kind": "policy",
|
||
"manifest_ref": "k8s/awoooi-prod/01-namespace-quota.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "Namespace/awoooi-prod + ResourceQuota/awoooi-prod-quota + LimitRange/awoooi-prod-limits",
|
||
"health_contract": "保護 namespace resource blast radius;任何 limit 調整屬 P2 proposal,不在本任務執行",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/01-namespace-quota.yaml"
|
||
],
|
||
"next_action": "只讀對齊 quota usage / HPA 建議;不得 patch quota。"
|
||
},
|
||
{
|
||
"surface_id": "network_policy_contract",
|
||
"display_name": "NetworkPolicy Contract",
|
||
"kind": "policy",
|
||
"manifest_ref": "k8s/awoooi-prod/02-network-policy.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "critical",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "NetworkPolicy/default-deny-all + allow-nginx-ingress + allow-required-egress;kustomization 註記由 CD 單獨 apply",
|
||
"health_contract": "預設拒絕;允許 Nginx gateway、K3s NodePort、Ollama proxy、monitoring、K8s API 與必要服務 egress",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/02-network-policy.yaml",
|
||
"k8s/awoooi-prod/kustomization.yaml",
|
||
"docs/HARD_RULES.md"
|
||
],
|
||
"next_action": "P1-003 / P2 只讀盤點 egress / alert chain evidence;不得 patch NetworkPolicy。"
|
||
},
|
||
{
|
||
"surface_id": "hpa_vpa_autoscaler_contract",
|
||
"display_name": "HPA / VPA Autoscaler Contract",
|
||
"kind": "autoscaler",
|
||
"manifest_ref": "k8s/awoooi-prod/12-hpa.yaml + k8s/awoooi-prod/11-vpa.yaml",
|
||
"status": "action_required",
|
||
"risk_level": "high",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "HPA api/web/worker 與 VPA api/web/worker manifests 存在,但 kustomization resources 未列入;需只讀確認實際 apply 路徑與 runtime 狀態",
|
||
"health_contract": "HPA/VPA 只能提供建議或已批准擴縮容;不得自動提升 runtime gate",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "required",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/12-hpa.yaml",
|
||
"k8s/awoooi-prod/11-vpa.yaml",
|
||
"k8s/awoooi-prod/kustomization.yaml"
|
||
],
|
||
"next_action": "P2 配置優化前只讀確認 HPA/VPA 是否實際存在;不得 apply 或 patch autoscaler。"
|
||
},
|
||
{
|
||
"surface_id": "pod_disruption_budget",
|
||
"display_name": "PodDisruptionBudget",
|
||
"kind": "availability",
|
||
"manifest_ref": "k8s/awoooi-prod/09-pdb.yaml",
|
||
"status": "manifest_mapped",
|
||
"risk_level": "medium",
|
||
"evidence_level": "committed_manifest",
|
||
"runtime_binding": "PDB/api minAvailable=1;PDB/web minAvailable=1;PDB/worker maxUnavailable=1",
|
||
"health_contract": "節點維護與 rollout availability guard;不得在本任務變更 maxUnavailable / minAvailable",
|
||
"secret_exposure": "none",
|
||
"live_check_status": "not_run",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/09-pdb.yaml",
|
||
"k8s/awoooi-prod/kustomization.yaml"
|
||
],
|
||
"next_action": "只讀確認 PDB health 與 rollout evidence;不得修改可用性策略。"
|
||
}
|
||
],
|
||
"source_runtime_components": [
|
||
{
|
||
"component_id": "api_fastapi_app",
|
||
"display_name": "FastAPI app",
|
||
"source_ref": "apps/api/src/main.py",
|
||
"component_kind": "api_process",
|
||
"runtime_binding": "Deployment/awoooi-api container api",
|
||
"status": "bound",
|
||
"next_action": "只讀 health / route inventory。"
|
||
},
|
||
{
|
||
"component_id": "api_health_routes",
|
||
"display_name": "API health routes",
|
||
"source_ref": "apps/api/src/routes/health.py",
|
||
"component_kind": "health_endpoint",
|
||
"runtime_binding": "Deployment/awoooi-api probes /api/v1/health/live and /api/v1/health/ready",
|
||
"status": "bound",
|
||
"next_action": "只讀確認 probe 與 public health 契約。"
|
||
},
|
||
{
|
||
"component_id": "web_next_app",
|
||
"display_name": "Next.js app",
|
||
"source_ref": "apps/web/src/app/",
|
||
"component_kind": "web_process",
|
||
"runtime_binding": "Deployment/awoooi-web container web",
|
||
"status": "bound",
|
||
"next_action": "只讀 UI smoke;不得改 public API route。"
|
||
},
|
||
{
|
||
"component_id": "web_health_route",
|
||
"display_name": "Web health route",
|
||
"source_ref": "apps/web/src/app/api/health/route.ts",
|
||
"component_kind": "health_endpoint",
|
||
"runtime_binding": "Deployment/awoooi-web probes /api/health",
|
||
"status": "bound",
|
||
"next_action": "只讀確認 web health。"
|
||
},
|
||
{
|
||
"component_id": "signal_worker",
|
||
"display_name": "Signal Worker",
|
||
"source_ref": "apps/api/src/workers/signal_worker.py",
|
||
"component_kind": "worker_process",
|
||
"runtime_binding": "Deployment/awoooi-worker command python -m src.workers.signal_worker",
|
||
"status": "bound",
|
||
"next_action": "只讀 queue / heartbeat evidence。"
|
||
},
|
||
{
|
||
"component_id": "k3s_monitor_service",
|
||
"display_name": "K3s monitor service",
|
||
"source_ref": "apps/api/src/services/k3s_monitor_service.py",
|
||
"component_kind": "scheduled_report",
|
||
"runtime_binding": "CronJob/k3s-status-report",
|
||
"status": "bound",
|
||
"next_action": "只讀 last schedule / failure evidence。"
|
||
},
|
||
{
|
||
"component_id": "weekly_report_service",
|
||
"display_name": "Weekly report service",
|
||
"source_ref": "apps/api/src/services/weekly_report_service.py",
|
||
"component_kind": "scheduled_report",
|
||
"runtime_binding": "CronJob/weekly-report",
|
||
"status": "bound",
|
||
"next_action": "保留 success-noise suppression。"
|
||
},
|
||
{
|
||
"component_id": "km_vectorize_script",
|
||
"display_name": "KM vectorize script",
|
||
"source_ref": "scripts/cron_km_vectorize.py",
|
||
"component_kind": "scheduled_job",
|
||
"runtime_binding": "CronJob/km-vectorize",
|
||
"status": "bound",
|
||
"next_action": "只讀確認 vectorize report;不得手動重跑。"
|
||
},
|
||
{
|
||
"component_id": "drift_internal_scan",
|
||
"display_name": "Drift internal scan endpoint",
|
||
"source_ref": "apps/api/src/api/v1/drift.py",
|
||
"component_kind": "internal_endpoint",
|
||
"runtime_binding": "CronJob/drift-scanner POST /api/v1/drift/internal/scan",
|
||
"status": "bound",
|
||
"next_action": "只讀盤點 drift evidence;不得自動 remediation。"
|
||
}
|
||
],
|
||
"evidence_gaps": [
|
||
{
|
||
"gap_id": "external_gateway_manifest_gap",
|
||
"severity": "high",
|
||
"status": "action_required",
|
||
"summary": "正式域名健康證據存在,但 repo 內沒有 Kubernetes Ingress manifest;外部 Nginx / gateway 路由仍需只讀盤點。",
|
||
"evidence_refs": [
|
||
".gitea/workflows/cd.yaml",
|
||
"k8s/awoooi-prod/05-deployment-web.yaml",
|
||
"k8s/awoooi-prod/06-deployment-api.yaml"
|
||
],
|
||
"next_action": "P1-002 盤點 gateway / runner / DNS evidence,不直接改 Nginx 或 Ingress。"
|
||
},
|
||
{
|
||
"gap_id": "secret_metadata_live_check_gap",
|
||
"severity": "critical",
|
||
"status": "action_required",
|
||
"summary": "四個 Secret surface 只能以 template / metadata 顯示;仍缺只讀 metadata existence / age evidence,禁止讀 payload。",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/03-secrets.example.yaml",
|
||
"k8s/awoooi-prod/04-repair-ssh-key-template.yaml",
|
||
"k8s/awoooi-prod/04-repair-known-hosts-template.yaml",
|
||
"k8s/awoooi-prod/04-ssh-mcp-secret.example.yaml"
|
||
],
|
||
"next_action": "P1-002 只讀補 Secret metadata,不 base64 decode、不輸出明文。"
|
||
},
|
||
{
|
||
"gap_id": "autoscaler_apply_path_gap",
|
||
"severity": "medium",
|
||
"status": "action_required",
|
||
"summary": "HPA / VPA manifest 存在,但未列入 kustomization resources;需只讀確認實際 apply path 與 runtime 狀態。",
|
||
"evidence_refs": [
|
||
"k8s/awoooi-prod/12-hpa.yaml",
|
||
"k8s/awoooi-prod/11-vpa.yaml",
|
||
"k8s/awoooi-prod/kustomization.yaml"
|
||
],
|
||
"next_action": "P2 配置優化前只讀確認,不在本任務 apply 或 patch。"
|
||
}
|
||
],
|
||
"operator_contract": {
|
||
"display_mode": "read_only_runtime_surface",
|
||
"must_not_interpret_as": [
|
||
"runtime 執行批准",
|
||
"rollout / restart / scale 批准",
|
||
"Secret payload 可讀批准",
|
||
"生產路由變更批准",
|
||
"HPA / VPA apply 批准",
|
||
"active scan 或 auto remediation 批准",
|
||
"runtime 執行授權",
|
||
"rollout / restart / scale / delete 批准",
|
||
"Secret 已驗證或可讀取",
|
||
"Ingress / DNS 可修改"
|
||
],
|
||
"secret_display_policy": "只顯示 template、metadata、引用路徑與 redacted policy;禁止 Secret 明文、base64 decode、token、key、password 或私鑰內容進入 snapshot/API/UI/log。"
|
||
},
|
||
"operation_boundaries": {
|
||
"read_only_api_allowed": true,
|
||
"live_k8s_query_allowed": false,
|
||
"kubectl_allowed": false,
|
||
"rollout_allowed": false,
|
||
"restart_allowed": false,
|
||
"scale_allowed": false,
|
||
"delete_allowed": false,
|
||
"secret_read_allowed": false,
|
||
"secret_plaintext_allowed": false,
|
||
"active_scan_allowed": false,
|
||
"production_route_change_allowed": false
|
||
},
|
||
"approval_boundaries": {
|
||
"runtime_execution_authorized": false,
|
||
"action_buttons_allowed": false,
|
||
"secret_value_collection_allowed": false,
|
||
"host_change_authorized": false,
|
||
"workflow_modification_authorized": false,
|
||
"production_routing_authorized": false,
|
||
"destructive_operation_allowed": false
|
||
}
|
||
}
|