Skip to content

CI Failure DoctorCI Failure: test_permission_guard.py fails on main branch due to BLOCKED_ON_MAIN false positives #218

@github-actions

Description

@github-actions

Summary

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).

Failure Details

  • Run: 24325546859
  • 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:

find . -name "test_*.py" -o -name "*_test.py" | while read -r test; do
    python3 "$test"
done

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 fire
check("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 Strategies

1. Tests that mix branch-state-dependent guards with other logic should mock environment checks (`_is_on_main_branch`) or use subcommands not affected by the guard under test.
2. When adding a new command to `BLOCKED_ON_MAIN`, audit existing tests that use that command as a subcommand in unrelated test scenarios.
3. Consider adding a CI-specific environment variable (`CI=true`) to skip or adjust the main-branch check in unit tests.

## AI Team Self-Improvement

```
When adding commands to BLOCKED_ON_MAIN (or any environment-sensitive deny list),
audit ALL existing test cases that use those command subcommands and ensure they
either (a) mock the environment check, (b) use a different subcommand, or (c)
update the expected value to reflect the deny. CI always runs on main branch.
Do not use 'commit', 'push', or 'add' as subcommands in tests that are meant
to verify unrelated logic (e.g. hooksPath parsing) without mocking
_is_on_main_branch() to return False.

Historical Context

  • Related open issue: git-permission-guard: false positive blocks --no-edit as --no-verify #180 ("git-permission-guard: false positive blocks --no-edit as --no-verify") — a similar false-positive pattern in this same guard script.
  • 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.

Generated by CI Failure Doctor · ● 1.7M ·

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions