Skip to content

test: cover the organization PR baseline gate detector - #10

Merged
Viktor Didkovskyi (viktor958) merged 3 commits into
mainfrom
viktor/hea-7249-baseline-gate-detector-tests
Aug 12, 2026
Merged

test: cover the organization PR baseline gate detector#10
Viktor Didkovskyi (viktor958) merged 3 commits into
mainfrom
viktor/hea-7249-baseline-gate-detector-tests

Conversation

@viktor958

@viktor958 Viktor Didkovskyi (viktor958) commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds test coverage for the gate detector merged in #8. Follow-up to that PR; no change to the baseline workflow itself.

The detector had no committed tests. It was verified once by hand against the organization's 216 workflow files, which proves nothing about the next edit.

Approach

The audit ships as an inline shell: python step so the reusable workflow carries no dependency on files in this repository. A test that re-implemented that logic would drift from it silently. So these tests extract the script out of the workflow YAML and execute it — the code under test is provably the code that ships, and changing the workflow changes what the tests exercise.

Coverage — 29 tests, split by consequence

Fake gates that must be blocked (9): inline and block-scalar echo, a set -e prefix, any other phrase, exit 0, true, chained inert commands, all-inert multiline, and a checkout step followed by an echo — the shape actually present in meditation-service and healify-org.

Real gates that must pass (9): these matter more, because a false positive in the blocking tier red-lines a compliant repository. Compound commands after an echo (echo "verifying" && make verify), command words that merely begin with an inert word (truncate_logs), semicolon and pipe separation, an exit 1 guard, aggregation through needs.<job>.result, a gate sharing a file with an unrelated job that mentions the phrase, and non-gate jobs never being judged.

Advisory tier, pinned in both directions (5): must annotate without failing by default, must fail under strict: true, each advisory class detected, and SHA-pinned and local actions not reported as mutable.

Robustness (4): unparsable YAML is blocking, an empty workflow directory is clean, the step summary is written, stderr stays empty.

Self-consistency (2): the extracted step parses as Python, and this repository passes its own blocking tier.

Why a separate workflow

The tests cannot run inside the reusable baseline: that executes against the caller's checkout, so it cannot see this repository's test files. baseline-selftest.yml runs them on pull requests touching the baseline, the tests, or itself.

Verification

  • 29/29 pass locally against the merged detector.
  • actionlint 1.7.12 clean on all three workflows.
  • Diff versus main is exactly the two new files.

Linear: https://linear.app/lifecycle-innovations/issue/HEA-7249

Summary by CodeRabbit

  • New Features

    • Added automated baseline-audit checks for pull requests and updates to the main branch.
    • Added validation for merge gates, workflow structure, action pinning, advisory behavior, and audit output.
  • Tests

    • Added comprehensive coverage for valid, invalid, malformed, empty, and self-audited workflows.
    • Configured checks to use Python 3.12, read-only repository permissions, and automatic cancellation of outdated runs.

The detector had no committed tests. It was verified once by hand against the
organization's workflows, which proves nothing about the next edit.

Add 29 tests that extract the audit script out of the workflow YAML and execute
it, rather than re-implementing the logic. The code under test is therefore the
code that ships, and a change to the workflow changes what the tests exercise.

Coverage is split by consequence. Fake gates that must be blocked: inline and
block-scalar echo, a set -e prefix, any other phrase, exit 0, true, chained
inert commands, and a checkout step followed by an echo — the shape actually
present in meditation-service and healify-org. Real gates that must pass, which
matter more because a false positive here red-lines a compliant repository:
compound commands after an echo, command words that merely start with an inert
word, semicolon and pipe separation, an exit 1 guard, aggregation through
needs.<job>.result, and a gate sharing a file with an unrelated job that
mentions the phrase. Advisory behaviour is pinned in both directions: it must
annotate without failing by default and must fail under strict, each advisory
class must be detected, and SHA-pinned and local actions must not be reported
as mutable. Robustness covers unparsable YAML, an empty workflow directory, the
step summary, and a clean stderr.

Run them in CI through a separate workflow. They cannot live in the reusable
baseline, which executes against the caller's checkout and so cannot see this
repository's test files.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@viktor958, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 55 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 056edebb-c549-4ec6-9312-69af9546a7e9

📥 Commits

Reviewing files that changed from the base of the PR and between 0f16d05 and ff0c0a1.

📒 Files selected for processing (1)
  • .github/tests/test_baseline_audit.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 38548570-47bc-4334-8b9b-4589081612cc

📥 Commits

Reviewing files that changed from the base of the PR and between ceb5a2d and 0f16d05.

📒 Files selected for processing (2)
  • .github/tests/test_baseline_audit.py
  • .github/workflows/baseline-selftest.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/baseline-selftest.yml

📝 Walkthrough

Walkthrough

Added tests for the inline baseline audit script and a GitHub Actions workflow that runs them on relevant pull requests and pushes to main.

Changes

Baseline audit validation

Layer / File(s) Summary
Audit extraction and execution harness
.github/tests/test_baseline_audit.py
The test harness extracts the named audit step, creates synthetic workflows, executes audits, and classifies blocking and advisory results.
Audit behavior and robustness coverage
.github/tests/test_baseline_audit.py
Tests cover blocked and permitted gates, advisory findings, malformed workflows, output handling, Python parsing, and repository self-consistency.
Automated workflow execution
.github/workflows/baseline-selftest.yml
The workflow runs on filtered pull requests and main pushes. It uses read-only permissions, Python 3.12, PyYAML, checkout without persisted credentials, timeout limits, and concurrency cancellation.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant BaselineSelftestWorkflow
  participant BaselineAuditTests
  participant AuditScript
  GitHubActions->>BaselineSelftestWorkflow: trigger on pull request or main push
  BaselineSelftestWorkflow->>BaselineAuditTests: execute test_baseline_audit.py
  BaselineAuditTests->>AuditScript: extract and execute audit step
  AuditScript-->>BaselineAuditTests: return audit results
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the added tests for the organization PR baseline gate detector.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch viktor/hea-7249-baseline-gate-detector-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/tests/test_baseline_audit.py:
- Around line 69-75: Update the subprocess.run call in the baseline audit test
to include a short timeout for the extracted audit script, ensuring hung
detector regressions fail promptly while preserving the existing capture and
text settings.
- Around line 64-72: Update the subprocess environment construction in the
baseline audit test around audit_source() so it contains only the required
STRICT and GITHUB_STEP_SUMMARY values, removing the os.environ spread; keep the
existing strict-mode conversion and summary path unchanged.

In @.github/workflows/baseline-selftest.yml:
- Around line 16-20: Update the push.paths filter for the Baseline Self-Test
workflow to include .github/workflows/baseline-selftest.yml, matching the
existing pull_request path filter so changes to this workflow on main trigger
the workflow.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c7c41c05-cca2-4212-9399-7a0e5d60a032

📥 Commits

Reviewing files that changed from the base of the PR and between 0d88258 and ceb5a2d.

📒 Files selected for processing (2)
  • .github/tests/test_baseline_audit.py
  • .github/workflows/baseline-selftest.yml

Comment thread .github/tests/test_baseline_audit.py
Comment thread .github/tests/test_baseline_audit.py
Comment thread .github/workflows/baseline-selftest.yml
Three fixes from review.

The harness copied the full test-runner environment into a script that is read
out of a workflow file, and a pull request can change that file. Pass only the
two variables the script reads, plus PATH, so a modified audit step has nothing
inherited to disclose. All 29 tests pass under the restricted environment,
which confirms nothing else was needed.

Bound the subprocess with a 60 second timeout so a detector regression that
hangs fails the test pointing at the audit, rather than stalling until the job
timeout.

Align the push path filter with the pull_request one: a push to main touching
only baseline-selftest.yml would previously have skipped the self-test.
Keeping PATH was a half-measure. The script imports only stdlib and yaml and
never shells out, so it needs no inherited value at all. It now receives exactly
the two variables it reads. All 29 tests pass, which confirms it.

Drop the now-unused os import.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full review at ff0c0a17. This is the right way to test a gate, and I would merge it.

The design decision that makes it worth having: run_audit does not reimplement the detector, it yaml.safe_loads organization-pr-baseline.yml, pulls the run body of the named audit step, and executes that via subprocess against a synthetic .github/workflows tree in a tempdir. So the code under test is provably the code that ships. Tests that paraphrase a workflow's shell script are the usual pattern here and they drift from the artifact within a release or two; this cannot.

The extraction also fails in the right direction — raise AssertionError(f"step {AUDIT_STEP!r} not found in {WORKFLOW}") when the step name no longer matches. Renaming the step breaks the suite loudly instead of leaving it silently exercising nothing, which is exactly the failure mode I just flagged on #9 in this same repo. Worth calling out because the two PRs make opposite choices about what a miss should do, and this one is the choice to keep.

Splitting the assertions by consequence is the other thing I liked: separating cases that must block from cases that must pass matters more than raw count here, because a false positive red-lines a compliant repo and that is the expensive direction of failure for an org-wide baseline. Reading ::error and ::warning off stdout to distinguish blocking from advisory keeps the tiers pinned in both directions rather than just asserting an exit code.

The self-test workflow is wired sensibly: path-filtered so it only runs when the baseline or its tests change, setup-python pinned by SHA rather than a floating tag, pyyaml installed explicitly, and the suite run directly. The tests cannot live inside the reusable baseline itself, since that executes against the caller's checkout and cannot see this repo's files — so a separate workflow is the correct structure, not a workaround.

All checks pass or skip, three review threads are resolved with zero unresolved, and GitHub reports it mergeable and clean at this head. .github main requires no approvals, so nothing gates it.

One follow-up rather than an objection: baseline-selftest.yml is not itself a required check, so a detector regression would go red without blocking a merge. Given the whole point is that the gate keeps working, adding it to the required set once it has a few green runs would close the loop.

Merge it.

@viktor958
Viktor Didkovskyi (viktor958) merged commit 596a2b5 into main Aug 12, 2026
6 checks passed
@viktor958
Viktor Didkovskyi (viktor958) deleted the viktor/hea-7249-baseline-gate-detector-tests branch August 12, 2026 14:36
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