Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

ci: 0.2.15 — pre-tag pin verifier + finding-positive fixture#28

Merged
ob-aion merged 4 commits into
mainfrom
ci/0.2.15-pin-verifier-and-fixture
May 12, 2026
Merged

ci: 0.2.15 — pre-tag pin verifier + finding-positive fixture#28
ob-aion merged 4 commits into
mainfrom
ci/0.2.15-pin-verifier-and-fixture

Conversation

@ob-aion
Copy link
Copy Markdown
Owner

@ob-aion ob-aion commented May 12, 2026

Summary

Two changes ship as 0.2.15. Both close bug classes that the 0.2.7 and 0.2.8 releases exposed. Both stayed open through the 0.2.13 → 0.2.14 revert cycle.

  1. Pre-tag pin verifier in scripts/verify-action-pins.sh. Closes the 0.2.7 lockstep-skip bug class at the release-pipeline gate.
  2. Finding-positive fixture in .github/workflows/self-scan.yml. Closes the 0.2.8 exit-code propagation bug class.

Neither validates cross-repo reusable-workflow behaviour from inside Pruner's own CI. A real consumer PR remains the only honest surface for that.

Pre-tag pin verifier

scripts/verify-action-pins.sh gains an opt-in check. Activation: set EXPECTED_RELEASE_TAG in the script environment.

The check reads .github/workflows/scan.yml, extracts the uses: ob-aion/pruner@<X.Y.Z> literal, and exits 1 if the literal does not match the tag being cut. Local runs without the env var keep the prior SHA-pin-only behaviour. Script header documents the env-var contract and the updated exit-code set: 0 = OK, 1 = bad pin, 2 = missing gh or scan.yml.

.github/workflows/release.yml reorders the steps so Resolve tag runs before the renamed Verify action SHA pins and scan.yml lockstep step. The verifier step receives the tag via EXPECTED_RELEASE_TAG. No behavioural change to the SHA-pin loop or any downstream release step.

The bug class this closes

Four consecutive releases (0.2.3 to 0.2.6) shipped scan.yml pinned to the previous composite. The bump step was a manual hand-edit that fell through review. Consumers calling scan.yml@0.2.6 ran the 0.2.2 composite internally and missed the Cisco engine bump. The 0.2.13 structural fix attempt was reverted at 0.2.14 — cross-repo github.* context refers to the caller. The manual lockstep is back. This verifier is the principled defence.

Finding-positive fixture

examples/finding-positive-skill/ ships a minimal skill that trips four sub-critical Coroboros pack rules.

Rule Severity Why
FC001 high name is "Bad Name", fails kebab-case
FC003 medium custom_field at top level (must live under metadata:)
FC004 low metadata.version present (Coroboros house rule forbids it)
FC005 low license: "Apache 2" is not a valid SPDX identifier

Zero critical findings by design. Companion EXPECTATIONS.md documents the cross-walk. examples/vulnerable-skill/ keeps its existing role: 21 findings, 7 critical, every finding allowlisted in .pruner-ignore.yml. That fixture validates the full Coroboros + Cisco detection surface.

.github/workflows/self-scan.yml adds a pruner-finding-positive job. It invokes the composite via uses: ./ against the new fixture at fail-on: critical. Green outcome asserts that pruner scan exit 1 threads through coroboros-pack-run and the gate step. Workflow stays green even though findings exist (all below threshold).

The bug class this closes

The pre-existing pruner-self-scan job scans . from repo root with .pruner-ignore.yml applied. Every Pruner-side fixture finding sat in the allowlist, so pruner scan exited 0. The 0.2.8 bug never surfaced on the maintainer side until the first consumer integration on coroboros/agent-skills.

Dual-path allowlist

The repo-root .pruner-ignore.yml gains four entries keyed by examples/finding-positive-skill/SKILL.md. Two scan contexts read that file with different target-path values, and the asymmetry is intentional.

Job target-path Finding path Allowlist match Effect
pruner-self-scan . examples/finding-positive-skill/SKILL.md yes suppressed — Security tab and PR review stay clean
pruner-finding-positive examples/finding-positive-skill SKILL.md no findings fire — exit-code propagation gets exercised

Same pattern as the 14 vulnerable-skill entries already in the file.

Lockstep bump

.github/workflows/scan.yml synced to ob-aion/pruner@0.2.15. Now verified pre-tag by the script in the first commit.

Branch protection follow-up

Branch protection on main requires pruner-self-scan already. Promoting pruner-finding-positive to a required status check is a one-line gh api follow-up after the first green run on main.

Files

  • scripts/verify-action-pins.sh — opt-in lockstep check.
  • .github/workflows/release.yml — step reorder.
  • examples/finding-positive-skill/SKILL.md + EXPECTATIONS.md — new fixture.
  • .github/workflows/self-scan.yml — new pruner-finding-positive job.
  • .github/workflows/scan.yml — lockstep bump to @0.2.15.
  • CHANGELOG.md — v0.2.15 entry.

Test plan

  • actionlint .github/workflows/*.yml clean.
  • cd wrapper && ruff check src tests && pytest tests --cov=pruner_wrapper --cov-fail-under=90 green.
  • pruner scan examples/finding-positive-skill --without-cisco reports exactly four findings (FC001, FC003, FC004, FC005), zero critical.
  • EXPECTED_RELEASE_TAG=0.2.15 bash scripts/verify-action-pins.sh exits 0.
  • EXPECTED_RELEASE_TAG=0.2.99 bash scripts/verify-action-pins.sh exits 1 (mismatch fires).
  • CI: pruner-self-scan green at fail-on: critical.
  • CI: pruner-finding-positive green at fail-on: critical. Validates exit-code propagation.
  • CI: Analyze (actions) + Analyze (python) + CodeQL green.

ob-aion added 2 commits May 12, 2026 17:14
Closes the 0.2.7 lockstep-skip bug class at the release-pipeline gate.

`scripts/verify-action-pins.sh` gains an opt-in check, activated when
`EXPECTED_RELEASE_TAG` is set in the script's environment. The check reads
`.github/workflows/scan.yml`, extracts the `uses: ob-aion/pruner@<X.Y.Z>`
literal, and exits 1 if `<X.Y.Z>` does not match the tag being cut. Local
runs without the env var keep the previous SHA-pin-only behaviour. Script
header documents the env-var contract and the updated exit-code set
(0 OK / 1 bad pin / 2 missing gh or scan.yml).

`.github/workflows/release.yml` reorders the steps so `Resolve tag` runs
before the renamed `Verify action SHA pins and scan.yml lockstep` step,
which receives the tag via `EXPECTED_RELEASE_TAG`. No behavioural change
to the SHA-pin loop or any downstream release step.

The 0.2.7 bug class: four consecutive releases (0.2.3-0.2.6) shipped
`scan.yml` pinned to the previous composite because the documented bump
step was a manual hand-edit that fell through review. Consumers calling
`scan.yml@0.2.6` got the 0.2.2 composite internally and missed the Cisco
engine bump. The 0.2.13 attempt to retire the lockstep via a structural
self-checkout pattern was reverted at 0.2.14 (cross-repo `github.*`
context refers to the caller). With the manual lockstep restored, this
verifier is the principled defence — pre-tag, scriptable, idempotent.
Closes the 0.2.8 exit-code bug class — `pruner scan` exit 1 (findings
present, all below threshold) must thread through `coroboros-pack-run`
and the gate step without being masked as a workflow failure.

`examples/finding-positive-skill/` is a minimal skill that trips four
sub-critical Coroboros pack rules: FC001 (high, name fails kebab-case),
FC003 (medium, top-level `custom_field`), FC004 (low, `metadata.version`
present), FC005 (low, non-SPDX license). Zero critical by design.
Companion `EXPECTATIONS.md` documents the cross-walk and distinguishes
the fixture from `examples/vulnerable-skill/` (21 findings, 7 critical,
every finding allowlisted in `.pruner-ignore.yml`).

`.github/workflows/self-scan.yml` adds a `pruner-finding-positive` job
invoking the composite via `uses: ./` against the new fixture at
`fail-on: critical`. Green outcome asserts the exit-code propagation
contract. The pre-existing `pruner-self-scan` job scans `.` from repo
root with `.pruner-ignore.yml` applied — every Pruner-side fixture
finding sits in the allowlist, so `pruner scan` exited 0 and the 0.2.8
bug never surfaced on the maintainer side until the first consumer
integration on `coroboros/agent-skills`. Finding-positive findings are
intentionally not allowlisted; they surface in Code Scanning at
downgraded severities (template-example weight 0.25 drops high to low,
medium to info, etc.) but never gate the workflow.

`.github/workflows/scan.yml` synced to `ob-aion/pruner@0.2.15` per the
lockstep contract, now verified pre-tag by the verifier extension in
the previous commit.

`CHANGELOG.md` — v0.2.15 entry covering both changes.

Branch protection on `main` requires `pruner-self-scan` already;
promoting `pruner-finding-positive` to a required status check is a
one-line `gh api` follow-up after the first green run on `main`.
@github-advanced-security
Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

1 similar comment
@github-advanced-security
Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Comment thread examples/finding-positive-skill/SKILL.md Fixed
Comment thread examples/finding-positive-skill/SKILL.md Fixed
Comment thread examples/finding-positive-skill/SKILL.md Fixed
Comment thread examples/finding-positive-skill/SKILL.md Fixed
ob-aion added 2 commits May 12, 2026 17:36
Split four sentences that ran over the 25-word hard cap. Tighten lexicon
("CI additions" not "defensive CI additions"), drop "lived as", drop the
verbose parenthetical that nested another em-dash inside a clause. Bullet
for the new fixture restructured: four rule items as short sentences
instead of a single 40-word parenthetical chain. Bullet for the new
self-scan job restructured: ten short sentences replace four long ones.

No semantic change. Same five bullets, same surface area.
…ture + docs

PR review on `#28` surfaced inline `github-advanced-security[bot]` comments on
`examples/finding-positive-skill/SKILL.md`. The pre-existing `pruner-self-scan`
job uploaded the four sub-critical findings to Code Scanning, the bot mirrored
each as a PR review comment, and the public PR ended up annotated with
intentional-fixture noise.

Fix exploits the wrapper's path-relative behaviour:

- `pruner-self-scan` runs with `target-path: .`. Finding paths land as
  `examples/finding-positive-skill/SKILL.md` (repo-root-relative). The four
  new entries in `.pruner-ignore.yml` are keyed on exactly that path and match,
  so the findings filter out before SARIF upload. Security tab and PR review
  surface stay clean.
- `pruner-finding-positive` runs with `target-path: examples/finding-positive-skill`.
  The wrapper computes finding paths relative to `target-path`, so each one is
  the bare string `SKILL.md`. Allowlist entries do not match, findings fire,
  `pruner scan` exits 1, and the composite's `coroboros-pack-run` step has to
  mask that exit for the workflow to pass — exactly the 0.2.8 propagation
  contract this fixture exists to validate.

Same path-rooted asymmetry as the 14 `examples/vulnerable-skill/` entries
already in `.pruner-ignore.yml`, so the file stays internally consistent.

Documentation updates folded in alongside the fix.

- `examples/finding-positive-skill/EXPECTATIONS.md` gains a "Dual-path
  allowlist behaviour" section with the truth table above. Distinct-from-
  vulnerable-skill note tightened.
- `examples/finding-positive-skill/SKILL.md` body sentence split across the
  brand-voice 25-word cap.
- `.github/workflows/self-scan.yml` comment block reworded — earlier
  "zero `SKILL.md` files" was inaccurate; the real reason `pruner scan` exits
  0 on the pre-existing job is that every Pruner-side fixture finding sits in
  `.pruner-ignore.yml`.
- `docs/sha-pinning.md` gains a "Pre-tag lockstep check" section documenting
  the `EXPECTED_RELEASE_TAG` env-var contract on `verify-action-pins.sh`.
- `docs/threat-model.md` self-scan bullet now names both jobs; release-
  integrity bullet now mentions the verifier's two invariants (SHA-pin
  validity + scan.yml lockstep).
- `CHANGELOG.md` v0.2.15 entry gains a fifth bullet describing the allowlist
  additions.
@ob-aion ob-aion merged commit cd75e93 into main May 12, 2026
8 checks passed
@ob-aion ob-aion deleted the ci/0.2.15-pin-verifier-and-fixture branch May 12, 2026 11:51
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants