Yes. In GitHub Actions, a job skipped by a conditional reports Success, and a job that depends on a failed job is skipped, which may not block merging. Design the security gate so a skip is treated as a failure, or so the job always runs.
The failure mode
Imagine a pipeline: build, then test, then security scan, each depending on the last. Tests fail. The scan job is skipped because its prerequisite failed. If the required check is the scan job, and a skip shows as green, the pull request may look fine. In practice the test failure still shows red elsewhere, but you should never rely on another job to catch what your gate meant to.
GitHub's documentation describes the pieces: a job skipped by a conditional reports Success; and for required checks that depend on other jobs, use the always function in addition to needs so they still report when a prerequisite fails.
Safer patterns
| Pattern | How it works | Trade off |
|---|---|---|
| Scan job with no dependencies | Runs in parallel with build and tests | Uses more runner minutes |
| Final aggregate job | Needs all jobs, runs always, fails if any result is not success | One more job to maintain |
| Explicit result check | Inspect the needs results and fail on skipped | Requires a small script |
Steps to harden it
- List every required check in branch protection.
- For each one, ask: can this job be skipped by an if condition or a failed need?
- For gates, remove the if condition or invert it so the default is to run.
- Add an aggregate job that always runs and fails when the scan result is anything but success.
- Test it: break the build on purpose and confirm the merge is blocked.
What an aggregate job looks like
The idea in words: the last job lists the others as needs, runs even if they fail, then reads each result. If the security job result equals skipped or failure, it exits non zero. Make that final job the required check, and branch protection watches one stable name.
A commit status itself has four states: error, failure, pending or success. There is no "skipped" state, which is why a skip has to be turned into one of those four by your own design.
Why this matters for audits
Auditors ask whether a control can be bypassed. A gate that passes on a skip is a bypass nobody intended. A short test record, showing you tried to skip it and could not, is good evidence.
Quick check
Does the always function make a job run after a failure?
It makes the job evaluate its steps even when a needed job failed, which lets a required check report instead of staying skipped.
Should the aggregate job be the only required check?
Often yes. A single stable check name avoids breakage when jobs are renamed or matrixed.
Safeguard's pull request gate reports a clear pass or fail status, with policy decisions you configure. You can try a free scan at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.