| | @@ -0,0 +1,46 @@ |
| + | # Pipeline detail |
| + | |
| + | ## Triggers |
| + | |
| + | The workflow runs on push and pull request to `main`, plus `workflow_dispatch` so I |
| + | can kick it manually when I'm testing a change to the pipeline itself. |
| + | |
| + | ## Permissions |
| + | |
| + | The workflow requests `contents: read` and `security-events: write`. The second is |
| + | what lets the SARIF upload write to the Security tab. Nothing in the pipeline needs |
| + | write access to the repo contents, so it doesn't ask for it. |
| + | |
| + | ## Job graph |
| + | |
| + | `lint` is the fail-fast. If ruff fails there's no point spending runner minutes on |
| + | the heavier scans, so everything depends on it. |
| + | |
| + | `sast`, `secrets`, and `dependencies` have no dependency on each other and run in |
| + | parallel. Each one is independently informative: a Semgrep finding, a leaked secret, |
| + | and a vulnerable dependency are three different problems with three different fixes. |
| + | |
| + | `test` waits on all three security jobs. Tests passing on code that has a known |
| + | secret leak in it isn't a green pipeline, so the gates come first. |
| + | |
| + | `notify-soc` uses `if: always()` and depends on `test`, so it reports the outcome |
| + | whether the pipeline passed or failed. |
| + | |
| + | ## Why these tools |
| + | |
| + | - **ruff** replaces flake8 + isort + a chunk of bandit's lint-level checks in one |
| + | fast binary. The `S` rule selection pulls in the security subset. |
| + | - **Semgrep** does the real static analysis. Custom rules live in the repo so they |
| + | are reviewed like any other code. |
| + | - **gitleaks** scans full history on pull requests (`fetch-depth: 0`) so a secret |
| + | that was committed and then "removed" in a later commit is still caught. |
| + | - **pip-audit** checks the pinned dependencies against the advisory database. `--strict` |
| + | makes an unfixable advisory fail the job rather than warn. |
| + | |
| + | ## Tuning the noise |
| + | |
| + | Semgrep on `p/default` is broad. The `.gitleaks.toml` allowlist covers the |
| + | documented placeholders (`replace-with-...`, `changeme-...`) and the test fixtures so |
| + | the secret scan doesn't flag the examples in this repo. Real allowlisting should be |
| + | narrow - path- and rule-scoped - which is why the allowlist here is explicit instead |
| + | of a blanket ignore. |