You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Validate Claude Code Plugin workflow (run #24325546859) failed because 3 test cases in git-guards/scripts/test_permission_guard.py return the wrong decision when the test suite is executed from the main branch (as CI always does).
Commit: 506b6eb (fix: recompile gh-aw workflows with v0.68.1)
Trigger: push to main
Failed Step: "Run tests" in validate-plugin.yml
Root Cause Analysis
git-guards/scripts/git-permission-guard.py has a BLOCKED_ON_MAIN set containing {"add", "commit", "push"}. When _is_on_main_branch() returns True, any git subcommand in this set is immediately denied.
In CI, the repository is always checked out on main, so _is_on_main_branch() returns True. Three test cases in test_permission_guard.py use commit or push as the git subcommand in order to test other logic (hooksPath precision and force-push differentiation), but the BLOCKED_ON_MAIN guard fires before the intended check is reached, returning deny instead of the expected ask or silent_allow.
Failed Tests
FAIL [git push --force feature branch]: decision=deny
Expected: ask, Got: deny
Command: git push --force origin feature/my-branch
(BLOCKED_ON_MAIN fires for 'push' before ASK_GIT check)
FAIL [hooksPath in value only]: decision=deny
Expected: silent_allow, Got: deny
Command: git -c some.key=echo-core.hooksPath commit -m test
(BLOCKED_ON_MAIN fires for 'commit' before hooksPath key/value check)
FAIL [hooksPath in commit message]: decision=deny
Expected: silent_allow, Got: deny
Command: git -c user.name=test commit -m "allow -c core.hooksPath bypass example"
(BLOCKED_ON_MAIN fires for 'commit' before shlex false-positive guard)
Why bash -eo pipefail Causes the Step to Fail
GitHub Actions runs steps with bash --noprofile --norc -eo pipefail. The Run tests step uses:
The while loop runs in a subshell; with -e, the subshell exits when python3 test_permission_guard.py returns 1. With pipefail, that subshell failure propagates as a pipeline failure, causing the step to fail.
Recommended Actions
Fix test cases 2 & 3 (hooksPath tests): Replace the commit subcommand with a non-BLOCKED subcommand such as restore that is also processed through the -c option extraction path, or patch them to mock _is_on_main_branch to return False.
Fix test case 1 (force-push): The test validates that git push --force to a non-main branch should ask, not deny. Since push is in BLOCKED_ON_MAIN, this test can never pass when run on main. Either:
Move this assertion into a dedicated test that mocks _is_on_main_branch, or
Add a note that force-push to feature branches is blocked on main (i.e., change expected to deny).
Minimal fix example for hooksPath tests (lines 95 & 102 in test_permission_guard.py):
# Change 'commit' to 'restore' so BLOCKED_ON_MAIN doesn't firecheck("hooksPath in value only",
"git -c some.key=echo-core.hooksPath restore some/file.txt", "ask")
check("hooksPath in commit message",
'git -c user.name=test restore some/file.txt', "ask")
```(Note: expected changes to `ask` because `restore` matches `ASK_GIT`.)
## Prevention Strategies1.Teststhatmixbranch-state-dependentguardswithotherlogicshouldmockenvironmentchecks (`_is_on_main_branch`) orusesubcommandsnotaffectedbytheguardundertest.
2.Whenaddinganewcommandto `BLOCKED_ON_MAIN`, auditexistingteststhatusethatcommandasasubcommandinunrelatedtestscenarios.
3.ConsideraddingaCI-specificenvironmentvariable (`CI=true`) toskiporadjustthemain-branchcheckinunittests.
## AI Team Self-Improvement
```
WhenaddingcommandstoBLOCKED_ON_MAIN (oranyenvironment-sensitivedenylist),
auditALLexistingtestcasesthatusethosecommandsubcommandsandensuretheyeither (a) mocktheenvironmentcheck, (b) useadifferentsubcommand, or (c)
updatetheexpectedvaluetoreflectthedeny. CIalwaysrunsonmainbranch.
Donotuse 'commit', 'push', or 'add' assubcommandsinteststhataremeanttoverifyunrelatedlogic (e.g. hooksPathparsing) withoutmocking_is_on_main_branch() toreturnFalse.
The commit that triggered this run (506b6eb) only changed .lock.yml workflow files and actions-lock.json — it did not introduce the test failures. The failures are pre-existing and will recur on every push to main until fixed.
Summary
The
Validate Claude Code Pluginworkflow (run #24325546859) failed because 3 test cases ingit-guards/scripts/test_permission_guard.pyreturn the wrong decision when the test suite is executed from themainbranch (as CI always does).Failure Details
validate-plugin.ymlRoot Cause Analysis
git-guards/scripts/git-permission-guard.pyhas aBLOCKED_ON_MAINset containing{"add", "commit", "push"}. When_is_on_main_branch()returnsTrue, any git subcommand in this set is immediately denied.In CI, the repository is always checked out on
main, so_is_on_main_branch()returnsTrue. Three test cases intest_permission_guard.pyusecommitorpushas the git subcommand in order to test other logic (hooksPath precision and force-push differentiation), but theBLOCKED_ON_MAINguard fires before the intended check is reached, returningdenyinstead of the expectedaskorsilent_allow.Failed Tests
Why bash -eo pipefail Causes the Step to Fail
GitHub Actions runs steps with
bash --noprofile --norc -eo pipefail. TheRun testsstep uses:The
whileloop runs in a subshell; with-e, the subshell exits whenpython3 test_permission_guard.pyreturns 1. Withpipefail, that subshell failure propagates as a pipeline failure, causing the step to fail.Recommended Actions
commitsubcommand with a non-BLOCKED subcommand such asrestorethat is also processed through the-coption extraction path, or patch them to mock_is_on_main_branchto returnFalse.git push --forceto a non-main branch shouldask, notdeny. Sincepushis inBLOCKED_ON_MAIN, this test can never pass when run on main. Either:_is_on_main_branch, ordeny).Minimal fix example for hooksPath tests (lines 95 & 102 in
test_permission_guard.py):Historical Context
.lock.ymlworkflow files andactions-lock.json— it did not introduce the test failures. The failures are pre-existing and will recur on every push to main until fixed.