Skip to content

Guard required CI commands against failure-masking wrappers #951

Closed

Description

@cemililik

Found while re-reviewing #946; this gap predates the monitoring change.

The failure-masking check in tests/test_guard_wiring.py::test_no_gauntlet_short_circuits_on_failure checks the three documented local gauntlets. It does not inspect GitHub Actions run blocks. The existing CI wiring assertions accept a required test command followed by || true.

Reproduction: in an isolated archive of ee1770a, append || true to the validation job's Node test command and run tests/test_guard_wiring.py --no-cov -q. All 16 wiring tests still pass. The actual checkout and CI configuration were not mutated. The sanctioned Bandit/pip-audit scanner + severity-helper exception must remain supported.

Acceptance criteria:

  • Reject failure-masking wrappers on required pytest, Node, Ruff and guard invocations in GitHub Actions run blocks.
  • Cover multiline shell blocks and command chaining without treating comments or quoted prose as executable commands.
  • Preserve the documented scanner + severity-helper exception only when the helper actually gates the scanner output.
  • Include negative fixtures/mutations proving that a required test command wrapped with || true fails the check.
  • Wire any added guard into CI and the canonical local gauntlets, preserving their inventory checks.

Related: #549 covers scanner report completeness; #920 covers consolidating the local gauntlets. This issue covers failure masking in workflow commands.

Activity

  1. cemililik commented on Oct 16, 2026

    @cemililik
    CollaboratorAuthor

    Found while fixing this. Items 1–3 are addressed in #954.

    1. The gauntlet check accepted a wrapped || true around any command. tests/test_guard_wiring.py::test_no_gauntlet_short_circuits_on_failure only checks that a gauntlet || true sits inside a { …; } group. Its failure message told contributors to "wrap it as '{ cmd || true; }'", so { pytest tests/ || true; } passed. The new guard rejects that unless the wrapped command is bandit or pip-audit followed by its severity helper reading the same report. The wiring test's message now says so.

    2. Workflows could mask failures without || true. These forms all kept CI green:

      • || : and || exit 0;
      • | tee without pipefail, and set +e;
      • a step-level continue-on-error;
      • cmd && echo ok followed by another line: bash's errexit ignores a failure inside an &&/|| list.

      The guard also covers EXIT/ERR traps that can exit 0, functions or aliases that take over a required command, repository scripts run with ./x.sh or source, and composite actions.

    3. The standards contradicted each other on continue-on-error. docs/standards/testing.md told contributors to replace any other || true with a step-level continue-on-error. docs/standards/code-review.md listed continue-on-error as an anti-pattern. Both now say: never on a step that runs a required command.

    4. Two partial copies of the gauntlet have drifted. They are in docs/standards/code-review.md and the review-pr skill. Not changed in Fix the wizard's Compliance step and field labels, guard CI against failure masking, correct monitoring copy #954; details are on Replace the ~31-command self-review chain triplicated in CLAUDE.md, AGENTS.md and CONTRIBUTING.md with tools/gauntlet.sh — deferred until a decision row approves it #920.

    Known limits are documented in the guard's docstring and in testing.md. The guard reads shell text only, so it cannot see:

    • a program replaced on disk or put first on PATH;
    • a script generated while the step runs;
    • an installer piped from curl or wget.
  2. added 4 commits that reference this issue on Oct 17, 2026
    b16f23d
    b281cdf
    baacb7a
    f6ddb3e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions