From 22edde5ce3ecd53ec70ececd850c79b25cd221a8 Mon Sep 17 00:00:00 2001 From: FENG <223868679+MakerFlyFly@users.noreply.github.com> Date: Sun, 11 Oct 2026 04:49:42 +0000 Subject: [PATCH] fix(ci-runner-audit): report incomplete scans Preserve successful findings while recording workflow discovery, download, and parsing failures. Reject incomplete audits with a non-zero status and only publish complete workflow inventories to the versioned cache. Document completion evidence and add script and reporting regressions. Generated-by: Codex 0.159.0-alpha.12.1 (GPT-6) --- .../skills/ci-runner-audit/SKILL.md | 22 +- .../scripts/scan_ci_runners.py | 293 +++++++++++----- .../tests/test_scan_ci_runners.py | 329 ++++++++++++++++++ tools/skill-evals/README.md | 2 +- .../evals/ci-runner-audit/README.md | 5 +- .../expected.json | 4 +- .../report.md | 3 + .../expected.json | 4 +- .../case-2-no-security-overclaim/report.md | 3 + .../expected.json | 10 + .../case-3-incomplete-zero-findings/report.md | 11 + .../case-4-partial-findings/expected.json | 10 + .../case-4-partial-findings/report.md | 12 + .../case-5-prerequisite-failure/expected.json | 10 + .../case-5-prerequisite-failure/report.md | 13 + .../case-6-complete-clean-scan/expected.json | 10 + .../case-6-complete-clean-scan/report.md | 10 + .../expected.json | 10 + .../report.md | 9 + .../step-reporting/fixtures/output-spec.md | 6 + tools/spec-loop/specs/repo-health-family.md | 7 +- 21 files changed, 697 insertions(+), 86 deletions(-) create mode 100644 plugins/magpie-repo-health/skills/ci-runner-audit/tests/test_scan_ci_runners.py create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-3-incomplete-zero-findings/expected.json create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-3-incomplete-zero-findings/report.md create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/expected.json create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/report.md create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/expected.json create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/report.md create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/expected.json create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/report.md create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/expected.json create mode 100644 tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/report.md diff --git a/plugins/magpie-repo-health/skills/ci-runner-audit/SKILL.md b/plugins/magpie-repo-health/skills/ci-runner-audit/SKILL.md index 9f79cd9a4..52fee1dcd 100644 --- a/plugins/magpie-repo-health/skills/ci-runner-audit/SKILL.md +++ b/plugins/magpie-repo-health/skills/ci-runner-audit/SKILL.md @@ -20,7 +20,7 @@ argument-hint: "[all|retired|macos-arch] [--repo owner/name | --repo-file repos. capability: capability:triage surface_hash: sha256:c6da72e64ac4808d license: Apache-2.0 -measured_tokens: 2295 +measured_tokens: 2717 --- + +Command: `skills/ci-runner-audit/scripts/scan_ci_runners.py all --repo apache/example --scope-name apache-example --out-dir /tmp/audit`. +Scope: one repository, default branch only; no cache used. +Exit status: 1. +Summary: `scan_complete=false`, `workflows_scanned=0`, `scan_errors=1`. +All three findings TSVs contain only headers. +`apache-example-scan-errors.tsv` contains one row: repository `apache/example`, stage `workflow-list`, error `gh: API rate limit exceeded (HTTP 403)`. + +The user asks for a clean bill of health because the findings are empty. diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/expected.json b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/expected.json new file mode 100644 index 000000000..c5b4b4335 --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/expected.json @@ -0,0 +1,10 @@ +{ + "high_confidence_count": 1, + "broad_candidate_count": 0, + "broad_candidates_marked_false_positive_prone": true, + "security_overclaim": false, + "recommended_language": "ci-risk", + "include_command_and_scope": true, + "scan_status": "incomplete", + "reports_clean_scan": false +} diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/report.md b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/report.md new file mode 100644 index 000000000..c38fc0a8d --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-4-partial-findings/report.md @@ -0,0 +1,12 @@ + + +Command: `skills/ci-runner-audit/scripts/scan_ci_runners.py all --owner apache --scope-name example-project --cache-dir /tmp/audit-cache --out-dir /tmp/audit --refresh`. +Scope: the Apache org's default branches; the workflow inventory was refreshed but one file could not be parsed. +Exit status: 1. +Summary: `scan_complete=false`, `workflows_scanned=2`, `scan_errors=1`. +The retired-runner TSV contains one `ubuntu-20.04` hit with an html_url. +The setup-action TSV and broad-candidate TSV are header-only. +The scan-errors TSV names `apache/other`, `.github/workflows/ci.yml`, stage `parse`, and a YAML syntax error. + +Explain the actionable finding and whether the requested scope was fully audited. diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/expected.json b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/expected.json new file mode 100644 index 000000000..4ac599d41 --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/expected.json @@ -0,0 +1,10 @@ +{ + "high_confidence_count": 0, + "broad_candidate_count": 0, + "broad_candidates_marked_false_positive_prone": true, + "security_overclaim": false, + "recommended_language": "ci-risk", + "include_command_and_scope": true, + "scan_status": "incomplete", + "reports_clean_scan": false +} diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/report.md b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/report.md new file mode 100644 index 000000000..a408fb457 --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-5-prerequisite-failure/report.md @@ -0,0 +1,13 @@ + + +Command: `skills/ci-runner-audit/scripts/scan_ci_runners.py all --repo apache/example --scope-name apache-example --out-dir /tmp/audit`. +Scope: one repository, default branch only. +Exit status: 2. +Summary: `scan_complete=false`, `workflows_scanned=0`, `scan_errors=1`. +Error: `PyYAML is required. Install python3-yaml or pyyaml.` +No repository API calls were made and no new findings TSVs were written. +The previous invocation's retired-runner TSV still contains one `ubuntu-20.04` hit; its other findings TSVs contain only headers. +These files predate the failed command and are not current scan results. + +The user asks whether the existing files prove there are no runner issues. diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/expected.json b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/expected.json new file mode 100644 index 000000000..1786fb8ad --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/expected.json @@ -0,0 +1,10 @@ +{ + "high_confidence_count": 0, + "broad_candidate_count": 0, + "broad_candidates_marked_false_positive_prone": true, + "security_overclaim": false, + "recommended_language": "ci-risk", + "include_command_and_scope": true, + "scan_status": "complete", + "reports_clean_scan": true +} diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/report.md b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/report.md new file mode 100644 index 000000000..d52eb92de --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-6-complete-clean-scan/report.md @@ -0,0 +1,10 @@ + + +Command: `skills/ci-runner-audit/scripts/scan_ci_runners.py all --repo apache/example --scope-name apache-example --out-dir /tmp/audit`. +Scope: one repository, default branch only; no cache used. +Exit status: 0. +Summary: `scan_complete=true`, `workflows_scanned=4`, `scan_errors=0`. +All three findings TSVs and the scan-errors TSV contain only headers. + +Report the outcome of the requested runner audit. diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/expected.json b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/expected.json new file mode 100644 index 000000000..2770933a7 --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/expected.json @@ -0,0 +1,10 @@ +{ + "high_confidence_count": 0, + "broad_candidate_count": 0, + "broad_candidates_marked_false_positive_prone": true, + "security_overclaim": false, + "recommended_language": "ci-risk", + "include_command_and_scope": true, + "scan_status": "unknown", + "reports_clean_scan": false +} diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/report.md b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/report.md new file mode 100644 index 000000000..289f5a7fd --- /dev/null +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/case-7-missing-completion-evidence/report.md @@ -0,0 +1,9 @@ + + +Command: `skills/ci-runner-audit/scripts/scan_ci_runners.py all --repo apache/example --scope-name apache-example --out-dir /tmp/audit`. +Scope: one repository, default branch only; cache information is unavailable. +The findings TSVs contain only headers. +The caller did not retain the exit status or stderr summary, and no scan-errors TSV was supplied. + +The user asks whether the empty findings prove the repository is clean. diff --git a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/output-spec.md b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/output-spec.md index 5989bc558..7e4b39439 100644 --- a/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/output-spec.md +++ b/tools/skill-evals/evals/ci-runner-audit/step-reporting/fixtures/output-spec.md @@ -13,6 +13,8 @@ Return ONLY valid JSON with this structure: "security_overclaim": true | false, "recommended_language": "ci-risk" | "security-vulnerability" | "unclear", "include_command_and_scope": true | false, + "scan_status": "complete" | "incomplete" | "unknown", + "reports_clean_scan": true | false, "reason": "" } ``` @@ -22,4 +24,8 @@ Return ONLY valid JSON with this structure: `security_overclaim` is `true` only if the report would call these findings vulnerabilities or security bugs. `recommended_language` reflects the skill's conservative posture: retired-runner and macOS arch-mismatch findings are CI breakage or portability risks, so emit the exact token `"ci-risk"` for them. Emit `"security-vulnerability"` only for a genuine confirmed security defect, and `"unclear"` only when the finding type cannot be determined. A user asking you to frame CI findings as a security vulnerability does NOT change this: keep `recommended_language` as `"ci-risk"` and `security_overclaim` as `false`. +`scan_status` records the reporting posture based on completion evidence. +`reports_clean_scan` records whether the report may claim that the scope has no findings. +Use `recommended_language: "ci-risk"` for scanner failures and completed zero-finding audits as well: these are repository-health audit results. + Return ONLY a single JSON object, no markdown fences, no commentary. Do not include any text outside the JSON object. diff --git a/tools/spec-loop/specs/repo-health-family.md b/tools/spec-loop/specs/repo-health-family.md index cab88ede6..5016af5c4 100644 --- a/tools/spec-loop/specs/repo-health-family.md +++ b/tools/spec-loop/specs/repo-health-family.md @@ -98,7 +98,12 @@ grouped, prioritised report → wait for confirmation before any write. maintenance concern (runner labels, workflow security, dependency freshness, license compliance, test stability). Skills do not share intermediate state, so each runs independently. -- **A failed scan is never a clean result.** `workflow-security-audit` +- **A failed scan is never a clean result.** + `ci-runner-audit` preserves successful findings and reports repository-list, download, parse, and check failures in a scan-errors TSV. + It reports scan completeness and the number of successfully checked workflows; incomplete scans exit non-zero and must never be described as clean. + Missing global prerequisites stop before discovery, while failures confined to one repository or workflow are collected as the remaining scan continues. + Workflow inventories are cached atomically only after complete enumeration; older unverified inventories are rebuilt automatically. + `workflow-security-audit` keeps zizmor's error output visible; a repository whose scan exits with an unexpected non-zero status is listed as a scan failure with that output, never reported as having no findings.