Skip to content

ci: audit example with-keys against current action.yml input contracts#136

Merged
eFAILution merged 2 commits intofeat/argus-portabilityfrom
ci/audit-example-action-inputs
May 7, 2026
Merged

ci: audit example with-keys against current action.yml input contracts#136
eFAILution merged 2 commits intofeat/argus-portabilityfrom
ci/audit-example-action-inputs

Conversation

@eFAILution
Copy link
Copy Markdown
Collaborator

Description

Closes the audit gap that let the recent example-staleness drift through unnoticed (PRs #134 / #135 fixed the symptom; this PR closes the source).

Composite-action consumers passing with: keys not declared in action.yml::inputs see a runtime warning, not a failure. CI never runs the example workflows — only YAML-validates them — so a contract trim could silently leave examples/ referencing inputs the action no longer accepts.

Changes Made

  • Added new scanner/workflow
  • Modified existing scanner/workflow
  • Updated documentation
  • Fixed bug
  • Other (please specify) — new CI gate + audit script + tests

Details

scripts/ci/check_example_inputs.py (new) — walks every examples/**/*.yml, finds each uses: huntridge-labs/argus/.github/actions/<name>@<ref> step, diffs its with: keys against the matching action's declared inputs. Reports unknown keys with job/step/file location.

Surface Description
Default Audits both examples/workflows/ and examples/github-enterprise/
--paths <dir>... Override the example roots
--actions-dir <p> Override the source-of-truth actions dir
--json Machine-readable output for downstream consumers
--gh-annotations ::error file=...:: lines that render inline in PR Files-changed view

Exit codes: 0 clean, 1 unknown-key found, 2 internal error.

tests/unit/test_check_example_inputs.py (new) — 18 tests covering:

  • Input-name collection from action.yml files
  • Clean / unknown-input / multi-key / missing-action / yaml-parse-error workflows
  • Non-argus uses: steps ignored
  • Exit codes (0 / 1 / 2)
  • JSON output shape
  • --gh-annotations stderr emission
  • Real-repo smoke (current examples/ passes today)

.github/workflows/test-examples-functional.yml (modified) — new audit-action-inputs job runs once across the whole example tree (cross-action correlation, not per-example). Wired into the examples-summary aggregator so any failure blocks the workflow. Uses env-var-injected needs.<>.result values to stay workflow-injection-safe per GitHub's security guidance.

Why a single job, not the per-example matrix

The audit needs the full action.yml input contract for every referenced action plus every with: block across the tree. Splitting per file would re-load the contracts N times and fragment the failure summary. One job, one parse pass, one report.

Cross-platform safety

  • Pure additive change. No existing job semantics modified.
  • No platform branching; pure-Python audit.
  • Workflow-injection-safe: needs.<>.result values flow through env: rather than being interpolated inside run: script bodies.

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • Tested with different scanner combinations

Test Results

$ python -m scripts.ci.check_example_inputs
✓ all example with: keys match current action.yml contracts

$ pytest tests/unit/test_check_example_inputs.py --no-cov -q
18 passed

$ pytest --no-cov -q   # full pytest (npm test equivalent)
2911 passed, 2 skipped, 7 deselected

Security Considerations

  • No security impact
  • Security enhancement
  • Potential security implications

(The new workflow job follows GitHub's workflow-injection-safety guidance: ${{ needs.<>.result }} flows through env: vars, not inside run: script bodies.)

AI Context Updates (.ai/)

  • .ai/architecture.yaml updated
  • .ai/workflows.yaml updated
  • .ai/decisions.yaml updated
  • .ai/errors.yaml updated
  • N/A - No .ai/ updates needed

(Pure CI infra add. The script's docstring documents the resolution flow for future contributors.)

Checklist

  • Code follows project style guidelines
  • Documentation updated (if applicable)
  • Changelog updated (if applicable)
  • All tests pass
  • Reviewed by at least one maintainer
  • Reviewed CONTRIBUTING.md guidelines

Related Issues

N/A — closes the audit-gap follow-up tracked in PR #135's roadmap entry. Companion to PR #134 (which fixed the symptom).

Closes the gap that let the recent example-staleness drift through
unnoticed. Composite-action consumers passing ``with:`` keys that
aren't declared in ``action.yml::inputs`` see a runtime warning,
not a failure. CI never *runs* the example workflows — only
YAML-validates them — so a contract trim could silently leave
``examples/`` referencing inputs the action no longer accepts.
PR #134 fixed the symptom; this PR closes the source.

What ships
==========

* ``scripts/ci/check_example_inputs.py`` — walks every
  ``examples/**/*.yml``, finds each
  ``uses: huntridge-labs/argus/.github/actions/<name>@<ref>``
  step, and diffs its ``with:`` keys against the matching
  action's declared inputs. Reports unknown keys with
  job/step/file location. Exits 1 on any miss, 0 on clean,
  2 on internal error (missing actions dir).

  Surfaces:
    --json              machine-readable output
    --gh-annotations    ``::error file=...:: PR-inline rendering
    --paths <dir>...    override the default examples roots
    --actions-dir <p>   override the default actions dir

* ``tests/unit/test_check_example_inputs.py`` — 18 tests
  covering: input-name collection, clean / unknown-input /
  multi-key / missing-action / yaml-parse-error workflows,
  non-argus uses-step ignored, exit codes (0/1/2), JSON output
  shape, gh-annotations stderr emission, and a smoke test that
  the actual repo's ``examples/`` passes today.

* ``.github/workflows/test-examples-functional.yml`` — new
  ``audit-action-inputs`` job runs once across the whole
  example tree (cross-action correlation, not per-example).
  Wired into the ``examples-summary`` aggregator so any failure
  blocks the workflow. Uses env-var-injected ``needs.<>.result``
  values to stay workflow-injection-safe per the GitHub
  security guidance.

Why a single job, not the per-example matrix
=============================================

The audit needs the full ``action.yml`` input contract for every
referenced action plus every ``with:`` block across the tree.
Splitting per file would re-load the contracts N times and
fragment the failure summary. One job, one parse pass, one
report — fast enough that the matrix split adds nothing.

Local verification
==================

* ``python -m scripts.ci.check_example_inputs`` → exit 0 on
  ``feat/argus-portability`` post PRs #134 / #135.
* Full SDK suite + the new tests: 2911 passed, 2 skipped, 7
  deselected.
* ``test-examples-functional.yml`` parses as valid YAML.

Future
======

If a future contract trim lands without an examples follow-up,
the audit fails the next PR-validation run with an inline
annotation pointing at the offending example. Either fix the
example, or update the action's contract — see the script's
docstring for the resolution flow.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

E2E Test Coverage Report

Action E2E Test Status Notes
ai-summary ⚪ Exception Manual-only action - triggered via dedicated ai-summary.yml workflow with user-supplied PR number
comment-pr ⚪ Exception Utility action - tested indirectly by all scanner and linter actions
get-job-id ⚪ Exception Utility action - tested indirectly by other jobs
linter-dockerfile ✅ Tested
linter-javascript ✅ Tested
linter-json ✅ Tested
linter-python ✅ Tested
linter-terraform ✅ Tested
linter-yaml ✅ Tested
linting-summary ✅ Tested
parse-container-config ✅ Tested
parse-zap-config ✅ Tested
scanner-bandit ✅ Tested
scanner-checkov ✅ Tested
scanner-clamav ✅ Tested
scanner-codeql ✅ Tested
scanner-container ✅ Tested
scanner-container-summary ⚪ Exception Tested as part of scanner-container
scanner-dependency-review ✅ Tested
scanner-gitleaks ✅ Tested
scanner-opengrep ✅ Tested
scanner-osv ✅ Tested
scanner-supply-chain ✅ Tested
scanner-syft ✅ Tested
scanner-trivy-iac ✅ Tested
scanner-zap ✅ Tested
scanner-zap-summary ⚪ Exception Tested as part of scanner-zap
scn-detector ✅ Tested
security-summary ⚪ Exception Tested in test-summary job

Summary

  • Total Actions: 29
  • Covered: 29
  • Missing E2E Tests: 0
  • Coverage: 100%

✅ All Actions Have E2E Coverage

@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

❌ Patch coverage is 86.20690% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
scripts/ci/check_example_inputs.py 86.20% 16 Missing ⚠️

📢 Thoughts on this report? Let us know!

… tests

The new audit script and its tests reference ``huntridge-labs/argus/.
github/actions/<name>@<ref>`` as a literal placeholder pattern in
docstrings, comments, and a test-helper f-string. The
``check_version_refs.py`` gate parses that as a real version ref
and flags it as uncovered.

Three minimal fixes — keep the placeholder text intact where the
docstring needed it, just teach the gate to skip those lines:

* scripts/ci/check_example_inputs.py:61 — added the ``release-it-
  ignore`` IGNORE_MARKER suffix to the comment line that documents
  the regex shape.

* tests/unit/test_check_example_inputs.py:4 — embedded the marker
  inline in the docstring's prose. The marker is a plain string
  the gate searches for, so prose context works fine.

* tests/unit/test_check_example_inputs.py::_write_example —
  pulled ``huntridge-labs/argus/.github/actions/`` into a local
  variable so the literal pattern doesn't appear on the same
  source line as the action name + ref. The rendered YAML still
  has a single ``uses:`` line, which is what the audit-under-test
  consumes.

Verified: ``check_version_refs`` exits 0 against tracked files,
the audit script + 18 unit tests still pass.
@eFAILution eFAILution merged commit 106bfbd into feat/argus-portability May 7, 2026
47 checks passed
@eFAILution eFAILution deleted the ci/audit-example-action-inputs branch May 7, 2026 23:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant