Skip to content

fix: make the required validate-profile check fail, not skip - #50

Merged
abrichr merged 2 commits into
mainfrom
fix/ledger-wave2-2026-10-14
Oct 14, 2026
Merged

abrichr merged 2 commits into
mainfrom
fix/ledger-wave2-2026-10-14

Conversation

@abrichr

@abrichr abrichr commented Oct 14, 2026

Copy link
Copy Markdown
Member

Main's committed ruleset (main-branch-ruleset.json, from #48) makes validate-profile a required check. Until now, that job was skipped on runs the lifecycle App starts, because it had a job-level if and needs: reject-lifecycle-app. GitHub reports a skipped job as a success, even when it is a required check. So once the ruleset is applied, a pull request the App opens would show validate-profile as passed although validation never ran.

This change keeps the job from being skipped. It now fails on those runs instead.

Fixes

Problem Change Regression test Ref
On a run the lifecycle App starts, the required validate-profile job is skipped, and a skipped job satisfies a required check. validate-profile no longer has a job-level if or needs. Its first step, before checkout, refuses the App the same way reject-lifecycle-app does, and fails. The other jobs are unchanged. tests/test_branch_protection.py::WorkflowTests::test_required_check_fails_instead_of_skipping reads the required checks from the committed ruleset. It fails if the job behind a required check has a job-level if, needs or continue-on-error. It also fails if the job's first step is an action, lacks the App refusal, or has its own if or continue-on-error. B247, #48, #49

Not fixed here

  • Main is still unprotected. On 2026-10-14, GET branches/main/protection returned 404 "Branch not protected", and both rulesets and rules/branches/main returned []. Applying the ruleset needs an admin, so this pull request can't do it. The scheduled run on 2026-10-14 (38567461248) failed at check-branch-protection and filed Branch protection on main needs attention #49. Leave Branch protection on main needs attention #49 open until the ruleset is in place.
  • A pull request can change the workflow behind its own required check. pull_request runs use the workflow file from the pull request. With the approval floor at 0, anyone with write access can merge a pull request that weakens validate-profile, and the check runs the weakened version. The same applies to the lifecycle App if it can write workflow files. This pull request does not check the App's permissions. The required check stops mistakes, not a determined writer. Raising the approval floor (the open decision from fix: add a daily check that main is branch-protected #48) is what would close this.
  • actionlint reports an info-level SC2016 in the "Refuse Production release-ledger rollback" step. It is also reported on main and is not related to this change.

How it was tested

  • The regression test fails on origin/main (936617b) and passes on this branch. Copying only the updated test file onto main gives 1 failure in 418 tests. On this branch, all 418 pass (1 skipped), with the pinned versions from requirements/profile-consistency.txt.
  • I ran a mutation test on the workflow. Each of 8 bypasses was injected and the test run against it: job-level if, needs and continue-on-error, if on the refusal step (as the first key and as a later key), continue-on-error on the refusal step, the refusal moved after checkout, and the refusal removed. The test catches all 8. The first version of the test missed the 3 cases with a step-level if or continue-on-error, so the second commit adds checks for them.
  • ruff check and ruff format --check pass on the test file.
  • The other CI steps pass locally: validate_evidence_registry.py, check_profile.py, and check_benchmark_claims.py --allow-recorded-drift.

After merging

  1. From the repository root, apply the ruleset: gh api -X POST repos/OpenAdaptAI/.github/rulesets --input main-branch-ruleset.json. This creates an active ruleset named "OpenAdapt policy: protected main". It requires a pull request and the validate-profile check from GitHub Actions, blocks force pushes and deletion, and has no bypass actors.
  2. Run the Profile consistency workflow by hand. Confirm check-branch-protection passes, then close Branch protection on main needs attention #49. The workflow files and updates that issue but does not close it.
  3. From then on, a pull request opened by the lifecycle App shows validate-profile as failed. To validate it, close and reopen the pull request so that a run starts under your account. Re-running the job does not help, because github.actor stays the App.
  4. Decide whether the approval floor stays at 0 or goes up to 1 (open from fix: add a daily check that main is branch-protected #48). A floor of 1 needs a second reviewer account.

🤖 Generated with Claude Code

abrichr and others added 2 commits October 14, 2026 10:18
The code part of this bug merged in #48: main-branch-ruleset.json requires
a pull request and the validate-profile check, and a daily job fails while
main is unprotected. Main is still unprotected today; the 2026-10-14
scheduled run failed and filed issue #49.

The ruleset had a gap that would open once it is applied. validate-profile
had a job-level condition and needed reject-lifecycle-app, so on a pull
request the lifecycle App opens, the job was skipped. GitHub counts a
skipped job as a passing required check, so that pull request would show
validate-profile as passed although validation never ran.

validate-profile now has no job-level condition or needs. Its first step
refuses the lifecycle App and fails, before checkout. The check is red,
not skipped, on App-triggered runs. A person closes and reopens the pull
request to run validation as themselves. The new test reads the required
checks from the committed ruleset and fails if the job behind any of them
can be skipped.

Ledger: B247

Signed-off-by: abrichr <richard.abrich@mldsai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The regression test for B247 checked that validate-profile has no
job-level condition or needs, and that its first step refuses the
lifecycle App. It still passed in three cases that weaken the refusal.
A step-level if can skip the refusal. continue-on-error on the refusal
step turns its failure into a success, so the job goes on and the
check passes. The test now fails on both, and on continue-on-error at
the job level as well.

A mutation run on the workflow shows the earlier test missed these
three cases. The new test catches them and the five cases the earlier
test already caught.

Ledger: B247

Signed-off-by: abrichr <richard.abrich@mldsai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@abrichr
abrichr merged commit 24c4a37 into main Oct 14, 2026
5 checks passed
@abrichr
abrichr deleted the fix/ledger-wave2-2026-10-14 branch October 14, 2026 16:52
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.

Branch protection on main needs attention

1 participant