From 43396f5603fd22cbf7c515f5f74ddcfd84fe1672 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 30 Jun 2026 07:39:05 +0800 Subject: [PATCH] feat(api): expose gitea runner attestation request --- .gitea/workflows/cd.yaml | 6 + apps/api/src/api/v1/agents.py | 36 ++++ .../services/delivery_closure_workbench.py | 110 +++++++++++ ...rkflow_runner_owner_attestation_request.py | 172 ++++++++++++++++++ .../test_delivery_closure_workbench_api.py | 25 +++ ...ow_runner_owner_attestation_request_api.py | 53 ++++++ docs/LOGBOOK.md | 13 ++ .../test_cd_controlled_runtime_profile.py | 4 + 8 files changed, 419 insertions(+) create mode 100644 apps/api/src/services/gitea_workflow_runner_owner_attestation_request.py create mode 100644 apps/api/tests/test_gitea_workflow_runner_owner_attestation_request_api.py diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 9587d961..44480107 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -307,6 +307,8 @@ jobs: ;; apps/api/src/services/gitea_private_inventory_p0_scorecard.py) ;; + apps/api/src/services/gitea_workflow_runner_owner_attestation_request.py) + ;; apps/api/src/services/reboot_auto_recovery_slo_scorecard.py) ;; apps/api/src/services/reboot_auto_recovery_drill_preflight.py) @@ -405,6 +407,8 @@ jobs: ;; apps/api/tests/test_gitea_private_inventory_p0_scorecard_api.py) ;; + apps/api/tests/test_gitea_workflow_runner_owner_attestation_request_api.py) + ;; apps/api/tests/test_reboot_auto_recovery_slo_scorecard_api.py) ;; apps/api/tests/test_iwooos_security_operating_system.py) @@ -583,6 +587,7 @@ jobs: src/services/gitea_owner_coverage_attestation_validation.py \ src/services/gitea_private_inventory_closeout_validation.py \ src/services/gitea_private_inventory_p0_scorecard.py \ + src/services/gitea_workflow_runner_owner_attestation_request.py \ src/services/reboot_auto_recovery_slo_scorecard.py \ src/services/reboot_auto_recovery_drill_preflight.py \ src/services/iwooos_security_operating_system.py \ @@ -635,6 +640,7 @@ jobs: tests/test_backup_dr_readiness_matrix_api.py \ tests/test_credential_escrow_evidence_intake_readiness_api.py \ tests/test_gitea_private_inventory_p0_scorecard_api.py \ + tests/test_gitea_workflow_runner_owner_attestation_request_api.py \ tests/test_reboot_auto_recovery_slo_scorecard_api.py \ tests/test_iwooos_security_operating_system.py \ tests/e2e_network_test.py::TestHMACVerification::test_valid_hmac_signature \ diff --git a/apps/api/src/api/v1/agents.py b/apps/api/src/api/v1/agents.py index 5a9a1146..255a3357 100644 --- a/apps/api/src/api/v1/agents.py +++ b/apps/api/src/api/v1/agents.py @@ -381,6 +381,9 @@ from src.services.gitea_private_inventory_closeout_validation import ( from src.services.gitea_private_inventory_p0_scorecard import ( load_latest_gitea_private_inventory_p0_scorecard, ) +from src.services.gitea_workflow_runner_owner_attestation_request import ( + load_latest_gitea_workflow_runner_owner_attestation_request, +) from src.services.gitea_workflow_runner_health import ( load_latest_gitea_workflow_runner_health, ) @@ -4129,6 +4132,39 @@ async def get_gitea_workflow_runner_health() -> dict[str, Any]: ) from exc +@router.get( + "/gitea-workflow-runner-owner-attestation-request", + response_model=dict[str, Any], + summary="取得 Gitea workflow runner owner attestation request", + description=( + "從 Gitea workflow / runner health contract 產生 runner label owner " + "attestation request packet;此端點只回傳脫敏 metadata 欄位、驗收規則與禁止事項。" + "它不送出 request、不呼叫 Gitea API、不修改 workflow、不重啟或註冊 runner、" + "不改 runner label、不讀 Secret 或 runner token、不觸發 workflow。" + ), +) +async def get_gitea_workflow_runner_owner_attestation_request() -> dict[str, Any]: + """Return the read-only Gitea runner owner attestation request packet.""" + try: + return await asyncio.to_thread( + load_latest_gitea_workflow_runner_owner_attestation_request + ) + except FileNotFoundError as exc: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=str(exc), + ) from exc + except (json.JSONDecodeError, ValueError) as exc: + logger.error( + "gitea_workflow_runner_owner_attestation_request_invalid", + error=str(exc), + ) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Gitea workflow runner owner attestation request 無效", + ) from exc + + @router.get( "/observability-contract-matrix", response_model=dict[str, Any], diff --git a/apps/api/src/services/delivery_closure_workbench.py b/apps/api/src/services/delivery_closure_workbench.py index 9090995e..1f46ffd5 100644 --- a/apps/api/src/services/delivery_closure_workbench.py +++ b/apps/api/src/services/delivery_closure_workbench.py @@ -33,6 +33,9 @@ from src.services.credential_escrow_evidence_intake_readiness import ( from src.services.gitea_private_inventory_p0_scorecard import ( load_latest_gitea_private_inventory_p0_scorecard, ) +from src.services.gitea_workflow_runner_owner_attestation_request import ( + load_latest_gitea_workflow_runner_owner_attestation_request, +) from src.services.gitea_workflow_runner_health import ( load_latest_gitea_workflow_runner_health, ) @@ -65,6 +68,9 @@ def load_delivery_closure_workbench() -> dict[str, Any]: load_latest_awoooi_gitea_onboarding_warning_step_runtime_enablement_gate() ) gitea = load_latest_gitea_workflow_runner_health() + gitea_runner_attestation_request = ( + load_latest_gitea_workflow_runner_owner_attestation_request() + ) runtime = load_latest_runtime_surface_inventory() backup = load_latest_backup_dr_readiness_matrix() credential_escrow_intake = load_latest_credential_escrow_evidence_intake_readiness() @@ -78,6 +84,7 @@ def load_delivery_closure_workbench() -> dict[str, Any]: cicd_template_copy_receipt=cicd_template_copy_receipt, cicd_runtime_enablement_gate=cicd_runtime_enablement_gate, gitea=gitea, + gitea_runner_attestation_request=gitea_runner_attestation_request, runtime=runtime, backup=backup, credential_escrow_intake=credential_escrow_intake, @@ -95,6 +102,7 @@ def build_delivery_closure_workbench( cicd_template_copy_receipt: dict[str, Any], cicd_runtime_enablement_gate: dict[str, Any], gitea: dict[str, Any], + gitea_runner_attestation_request: dict[str, Any], runtime: dict[str, Any], backup: dict[str, Any], credential_escrow_intake: dict[str, Any], @@ -145,6 +153,18 @@ def build_delivery_closure_workbench( production_deploy_rollups = _dict(production_deploy.get("rollups")) gitea_status = _dict(gitea.get("program_status")) gitea_rollups = _dict(gitea.get("rollups")) + gitea_runner_request_readback = _dict( + gitea_runner_attestation_request.get("readback") + ) + gitea_runner_request_packet = _dict( + gitea_runner_attestation_request.get("request_packet") + ) + gitea_runner_request_rollups = _dict( + gitea_runner_attestation_request.get("rollups") + ) + gitea_runner_request_boundaries = _dict( + gitea_runner_attestation_request.get("operation_boundaries") + ) runtime_status = _dict(runtime.get("program_status")) runtime_rollups = _dict(runtime.get("rollups")) backup_status = _dict(backup.get("program_status")) @@ -1007,6 +1027,47 @@ def build_delivery_closure_workbench( "metric": { "kind": "workflow_count", "count": _int(gitea_rollups.get("total_workflows")), + "runner_attestation_request_status": str( + gitea_runner_attestation_request.get("status") or "" + ), + "runner_attestation_request_ready": ( + gitea_runner_request_rollups.get("request_template_ready") is True + ), + "runner_attestation_request_active_blocker_count": _int( + gitea_runner_request_rollups.get("active_blocker_count") + ), + "runner_attestation_contract_id": str( + gitea_runner_request_readback.get("contract_id") or "" + ), + "runner_attestation_workflow_count": _int( + gitea_runner_request_rollups.get( + "workflow_requiring_attestation_count" + ) + ), + "runner_attestation_required_owner_field_count": _int( + gitea_runner_request_rollups.get("required_owner_field_count") + ), + "runner_attestation_owner_response_received_count": _int( + gitea_runner_request_rollups.get("owner_response_received_count") + ), + "runner_attestation_owner_response_accepted_count": _int( + gitea_runner_request_rollups.get("owner_response_accepted_count") + ), + "runner_attestation_request_send_performed": ( + gitea_runner_request_boundaries.get("request_send_performed") + is True + ), + "runner_attestation_runner_label_change_allowed": ( + gitea_runner_request_boundaries.get("runner_label_change_allowed") + is True + ), + "runner_attestation_runner_registration_allowed": ( + gitea_runner_request_boundaries.get("runner_registration_allowed") + is True + ), + "runner_attestation_secret_read_allowed": ( + gitea_runner_request_boundaries.get("secret_read_allowed") is True + ), }, "href": "/deployments", "next_action": _first_contract_action(gitea.get("runner_contracts")), @@ -1363,6 +1424,55 @@ def build_delivery_closure_workbench( ) is True ), + "gitea_runner_attestation_request_status": str( + gitea_runner_attestation_request.get("status") or "" + ), + "gitea_runner_attestation_request_ready": ( + gitea_runner_request_rollups.get("request_template_ready") is True + ), + "gitea_runner_attestation_request_active_blocker_count": _int( + gitea_runner_request_rollups.get("active_blocker_count") + ), + "gitea_runner_attestation_contract_id": str( + gitea_runner_request_readback.get("contract_id") or "" + ), + "gitea_runner_attestation_runner_label": str( + gitea_runner_request_readback.get("runner_label") or "" + ), + "gitea_runner_attestation_workflow_count": _int( + gitea_runner_request_rollups.get( + "workflow_requiring_attestation_count" + ) + ), + "gitea_runner_attestation_required_owner_field_count": _int( + gitea_runner_request_rollups.get("required_owner_field_count") + ), + "gitea_runner_attestation_forbidden_action_count": _int( + gitea_runner_request_rollups.get("forbidden_action_count") + ), + "gitea_runner_attestation_owner_response_received_count": _int( + gitea_runner_request_rollups.get("owner_response_received_count") + ), + "gitea_runner_attestation_owner_response_accepted_count": _int( + gitea_runner_request_rollups.get("owner_response_accepted_count") + ), + "gitea_runner_attestation_request_sent": ( + gitea_runner_request_packet.get("request_sent") is True + ), + "gitea_runner_attestation_request_send_performed": ( + gitea_runner_request_boundaries.get("request_send_performed") is True + ), + "gitea_runner_attestation_runner_label_change_allowed": ( + gitea_runner_request_boundaries.get("runner_label_change_allowed") + is True + ), + "gitea_runner_attestation_runner_registration_allowed": ( + gitea_runner_request_boundaries.get("runner_registration_allowed") + is True + ), + "gitea_runner_attestation_secret_read_allowed": ( + gitea_runner_request_boundaries.get("secret_read_allowed") is True + ), "p0_cicd_baseline_status": str(cicd_baseline.get("status") or ""), "p0_cicd_baseline_workplan_id": str( cicd_baseline_readback.get("workplan_id") or "" diff --git a/apps/api/src/services/gitea_workflow_runner_owner_attestation_request.py b/apps/api/src/services/gitea_workflow_runner_owner_attestation_request.py new file mode 100644 index 00000000..82cf1a5e --- /dev/null +++ b/apps/api/src/services/gitea_workflow_runner_owner_attestation_request.py @@ -0,0 +1,172 @@ +"""Gitea workflow runner owner attestation request readback. + +Builds a metadata-only request packet from the committed Gitea workflow / +runner health contract. This module never sends the request, calls Gitea, +changes runner labels, registers runners, triggers workflows, or reads secrets. +""" + +from __future__ import annotations + +from typing import Any + +from src.services.gitea_workflow_runner_health import ( + load_latest_gitea_workflow_runner_health, +) + +_SCHEMA_VERSION = "gitea_workflow_runner_owner_attestation_request_v1" +_CONTRACT_ID = "ubuntu_latest_gitea_runner_label" +_REQUIRED_FIELDS = [ + "runner_label", + "actual_runner_mapping_ref", + "runner_host_alias", + "executor_scope", + "capacity_owner", + "maintenance_window", + "evidence_ref", + "no_secret_value_attestation", + "no_runner_registration_change_attestation", + "rollback_owner", + "post_check_owner", +] +_FORBIDDEN_ACTIONS = [ + "workflow_modification", + "workflow_dispatch", + "runner_label_change", + "runner_registration", + "runner_restart", + "runner_container_stop", + "secret_or_runner_token_read", + "gitea_api_write", + "github_api", +] + + +def load_latest_gitea_workflow_runner_owner_attestation_request() -> dict[str, Any]: + """Return the owner attestation request packet for runner label evidence.""" + + health = load_latest_gitea_workflow_runner_health() + rollups = _dict(health.get("rollups")) + action_contracts = [ + contract + for contract in health.get("runner_contracts", []) + if isinstance(contract, dict) + and contract.get("contract_id") + in set(_strings(rollups.get("runner_contracts_requiring_action"))) + ] + target_contract = next( + ( + contract + for contract in action_contracts + if contract.get("contract_id") == _CONTRACT_ID + ), + {}, + ) + workflow_ids = _strings(rollups.get("workflow_ids_requiring_runner_attestation")) + request_ready = bool(target_contract) and bool(workflow_ids) + active_blockers = [] + if not request_ready: + active_blockers.append("runner_attestation_request_source_missing") + active_blockers.append("owner_attestation_response_not_received") + + return { + "schema_version": _SCHEMA_VERSION, + "priority": "P1-002", + "scope": "gitea_workflow_runner_owner_attestation_request", + "status": ( + "owner_attestation_request_ready_waiting_response" + if request_ready + else "blocked_owner_attestation_request_source_missing" + ), + "readback": { + "workplan_id": "P1-002-GITEA-RUNNER-OWNER-ATTESTATION", + "source_health_schema_version": health.get("schema_version"), + "source_health_endpoint": "/api/v1/agents/gitea-workflow-runner-health", + "contract_id": _CONTRACT_ID, + "runner_label": _first_string(target_contract.get("runner_labels")), + "request_packet_id": "gitea_runner_owner_attestation_request::ubuntu_latest", + "safe_next_step": ( + "collect_redacted_owner_attestation_response_then_validate_no_runner_mutation" + ), + }, + "request_packet": { + "request_template_ready": request_ready, + "request_sent": False, + "owner_response_received": False, + "owner_response_accepted": False, + "contract_id": _CONTRACT_ID, + "display_name": str(target_contract.get("display_name") or ""), + "risk_level": str(target_contract.get("risk_level") or "high"), + "runner_labels": _strings(target_contract.get("runner_labels")), + "workflow_ids_requiring_attestation": workflow_ids, + "required_owner_fields": _REQUIRED_FIELDS, + "forbidden_actions": _FORBIDDEN_ACTIONS, + "allowed_response_shape": { + "redacted_metadata_only": True, + "evidence_ref_required": True, + "secret_value_allowed": False, + "runner_token_allowed": False, + "authorization_header_allowed": False, + "raw_runner_config_allowed": False, + }, + "acceptance_checks": [ + "runner_label_mapping_ref_present", + "runner_host_alias_present", + "capacity_owner_present", + "maintenance_window_present", + "no_secret_value_attested", + "no_runner_registration_change_attested", + "post_check_owner_present", + ], + "rejection_rules": [ + "contains_secret_value", + "contains_runner_token", + "requests_runner_label_change", + "requests_runner_registration", + "requests_workflow_dispatch", + "missing_evidence_ref", + ], + }, + "rollups": { + "request_template_ready": request_ready, + "request_packet_count": int(request_ready), + "workflow_requiring_attestation_count": len(workflow_ids), + "runner_contracts_requiring_action_count": len(action_contracts), + "required_owner_field_count": len(_REQUIRED_FIELDS), + "forbidden_action_count": len(_FORBIDDEN_ACTIONS), + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "active_blocker_count": len(active_blockers), + "runtime_gate_opened": False, + }, + "active_blockers": active_blockers, + "operation_boundaries": { + "read_only_api_allowed": True, + "request_send_performed": False, + "workflow_modification_allowed": False, + "workflow_trigger_allowed": False, + "runner_label_change_allowed": False, + "runner_registration_allowed": False, + "runner_restart_allowed": False, + "runner_container_stop_allowed": False, + "secret_read_allowed": False, + "secret_plaintext_allowed": False, + "runner_token_read_allowed": False, + "gitea_api_write_allowed": False, + "github_api_used": False, + }, + } + + +def _dict(value: Any) -> dict[str, Any]: + return value if isinstance(value, dict) else {} + + +def _strings(value: Any) -> list[str]: + if not isinstance(value, list): + return [] + return [str(item) for item in value if item is not None] + + +def _first_string(value: Any) -> str: + values = _strings(value) + return values[0] if values else "" diff --git a/apps/api/tests/test_delivery_closure_workbench_api.py b/apps/api/tests/test_delivery_closure_workbench_api.py index 24726410..d2e54f71 100644 --- a/apps/api/tests/test_delivery_closure_workbench_api.py +++ b/apps/api/tests/test_delivery_closure_workbench_api.py @@ -276,6 +276,31 @@ def _assert_delivery_workbench_shape(data: dict): assert data["summary"]["github_global_freeze_enabled"] is True assert data["summary"]["github_lane_status"] == "stopped_retired_do_not_use" assert data["summary"]["github_lane_excluded_from_p0_blocker_count"] is True + assert data["summary"]["gitea_runner_attestation_request_status"] == ( + "owner_attestation_request_ready_waiting_response" + ) + assert data["summary"]["gitea_runner_attestation_request_ready"] is True + assert data["summary"]["gitea_runner_attestation_request_active_blocker_count"] == 1 + assert data["summary"]["gitea_runner_attestation_contract_id"] == ( + "ubuntu_latest_gitea_runner_label" + ) + assert data["summary"]["gitea_runner_attestation_runner_label"] == "ubuntu-latest" + assert data["summary"]["gitea_runner_attestation_workflow_count"] == 8 + assert data["summary"]["gitea_runner_attestation_required_owner_field_count"] >= 10 + assert data["summary"]["gitea_runner_attestation_forbidden_action_count"] >= 8 + assert data["summary"]["gitea_runner_attestation_owner_response_received_count"] == 0 + assert data["summary"]["gitea_runner_attestation_owner_response_accepted_count"] == 0 + assert data["summary"]["gitea_runner_attestation_request_sent"] is False + assert data["summary"]["gitea_runner_attestation_request_send_performed"] is False + assert ( + data["summary"]["gitea_runner_attestation_runner_label_change_allowed"] + is False + ) + assert ( + data["summary"]["gitea_runner_attestation_runner_registration_allowed"] + is False + ) + assert data["summary"]["gitea_runner_attestation_secret_read_allowed"] is False assert data["summary"]["github_blocked_preflight_target_count"] == 0 assert data["summary"]["github_operator_unblock_required"] is False assert data["summary"]["reboot_auto_recovery_status"] == ( diff --git a/apps/api/tests/test_gitea_workflow_runner_owner_attestation_request_api.py b/apps/api/tests/test_gitea_workflow_runner_owner_attestation_request_api.py new file mode 100644 index 00000000..15178fcf --- /dev/null +++ b/apps/api/tests/test_gitea_workflow_runner_owner_attestation_request_api.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +from src.api.v1.agents import router + + +def test_gitea_workflow_runner_owner_attestation_request_endpoint(): + app = FastAPI() + app.include_router(router, prefix="/api/v1") + client = TestClient(app) + + response = client.get( + "/api/v1/agents/gitea-workflow-runner-owner-attestation-request" + ) + + assert response.status_code == 200 + data = response.json() + assert ( + data["schema_version"] + == "gitea_workflow_runner_owner_attestation_request_v1" + ) + assert data["priority"] == "P1-002" + assert data["status"] == "owner_attestation_request_ready_waiting_response" + assert data["readback"]["contract_id"] == "ubuntu_latest_gitea_runner_label" + assert data["readback"]["runner_label"] == "ubuntu-latest" + assert data["request_packet"]["request_template_ready"] is True + assert data["request_packet"]["request_sent"] is False + assert data["request_packet"]["owner_response_received"] is False + assert data["request_packet"]["owner_response_accepted"] is False + assert ( + len(data["request_packet"]["workflow_ids_requiring_attestation"]) + == data["rollups"]["workflow_requiring_attestation_count"] + == 8 + ) + assert data["rollups"]["required_owner_field_count"] >= 10 + assert data["rollups"]["owner_response_received_count"] == 0 + assert data["rollups"]["owner_response_accepted_count"] == 0 + assert "owner_attestation_response_not_received" in data["active_blockers"] + + boundaries = data["operation_boundaries"] + assert boundaries["read_only_api_allowed"] is True + assert boundaries["request_send_performed"] is False + assert boundaries["workflow_modification_allowed"] is False + assert boundaries["workflow_trigger_allowed"] is False + assert boundaries["runner_label_change_allowed"] is False + assert boundaries["runner_registration_allowed"] is False + assert boundaries["runner_restart_allowed"] is False + assert boundaries["secret_read_allowed"] is False + assert boundaries["runner_token_read_allowed"] is False + assert boundaries["gitea_api_write_allowed"] is False + assert boundaries["github_api_used"] is False diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index cc13faa2..01a320d8 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -51,6 +51,19 @@ **邊界**:未重啟主機,未 restart service,未 workflow_dispatch,未操作 host / Docker / K8s / DB / firewall,未使用 GitHub / `gh` / GitHub API,未讀 secret / token / raw sessions / SQLite / `.env`。 +## 2026-06-30 — 07:38 P1-002 Gitea runner owner attestation request readback + +**照主線 next_focus 推進的實作**: +- P0-006 reboot SLO 仍只剩 `host_boot_observation_older_than_target_window`,未重啟主機;因此依 Delivery Workbench 下一個可執行主線推進 Gitea runner owner attestation request。 +- 新增 `GET /api/v1/agents/gitea-workflow-runner-owner-attestation-request`,把 `ubuntu_latest_gitea_runner_label`、8 個需 owner attestation 的 workflow、11 個 required owner fields、9 個 forbidden actions 與 response acceptance / rejection rules 轉成機器可讀 request packet。 +- Delivery Workbench 的 `gitea` lane 與 summary 現在顯示 request ready、workflow count、required field count、response received / accepted count 與 runner mutation/secret/Gitea write 邊界。 + +**驗證**: +- Focused pytest:Gitea runner attestation request / workflow runner health / Delivery Workbench / CD profile `29 passed`。 +- `py_compile`、Gitea runner pressure guard、`git diff --check` 通過。 + +**邊界**:未送出 request,未呼叫 Gitea API,未修改 workflow,未 workflow_dispatch,未註冊 / 重啟 runner,未改 runner label,未操作 host / Docker / K8s / DB / firewall,未讀 secret / token / raw sessions / SQLite / `.env`,未使用 GitHub / `gh` / GitHub API。 + ## 2026-06-30 — 00:41 P0-004 template copy receipt runtime-image readback 修正 **照優先順序完成的實作**: diff --git a/ops/runner/test_cd_controlled_runtime_profile.py b/ops/runner/test_cd_controlled_runtime_profile.py index f8764fe3..491b1a58 100644 --- a/ops/runner/test_cd_controlled_runtime_profile.py +++ b/ops/runner/test_cd_controlled_runtime_profile.py @@ -228,7 +228,9 @@ def test_gitea_private_inventory_scorecard_stays_on_controlled_runtime_profile() "apps/api/src/services/gitea_owner_coverage_attestation_validation.py)", "apps/api/src/services/gitea_private_inventory_closeout_validation.py)", "apps/api/src/services/gitea_private_inventory_p0_scorecard.py)", + "apps/api/src/services/gitea_workflow_runner_owner_attestation_request.py)", "apps/api/tests/test_gitea_private_inventory_p0_scorecard_api.py)", + "apps/api/tests/test_gitea_workflow_runner_owner_attestation_request_api.py)", "docs/operations/awoooi-gitea-authenticated-inventory-payload-validation.snapshot.json)", "docs/security/GITEA-REPO-INVENTORY-SNAPSHOT.md)", "docs/security/gitea-repo-inventory.snapshot.json)", @@ -240,7 +242,9 @@ def test_gitea_private_inventory_scorecard_stays_on_controlled_runtime_profile() "src/services/gitea_owner_coverage_attestation_validation.py", "src/services/gitea_private_inventory_closeout_validation.py", "src/services/gitea_private_inventory_p0_scorecard.py", + "src/services/gitea_workflow_runner_owner_attestation_request.py", "tests/test_gitea_private_inventory_p0_scorecard_api.py", + "tests/test_gitea_workflow_runner_owner_attestation_request_api.py", "scripts/security/tests/test_gitea_authenticated_inventory_payload_validator.py)", "../../scripts/security/gitea-private-inventory-p0-scorecard.py", "../../scripts/security/gitea-authenticated-inventory-payload-validator.py",