Zion Boggan zionboggan.com ↗

readme with semgrep + pip-audit screenshots

c277804   Zion Boggan committed on Apr 22, 2026 (2 months ago)
README.md +84 -0
@@ -0,0 +1,84 @@
+# Secure CI/CD Pipeline
+
+A GitHub Actions pipeline that gates every push and pull request on four security
+checks before code is allowed to merge, then reports the run back to a SOC for
+visibility. The sample app is a small Flask task API; the point of the repo is the
+pipeline around it.
+
+The checks run as separate jobs so a failure tells you exactly which gate tripped
+instead of one long log you have to scroll through.
+
+```mermaid
+flowchart TD
+ push[push / pull_request] --> lint[ruff lint]
+ lint --> sast[Semgrep SAST]
+ lint --> secrets[gitleaks secret scan]
+ lint --> deps[pip-audit dependencies]
+ sast --> test[pytest + coverage]
+ secrets --> test
+ deps --> test
+ test --> notify[notify SOC webhook]
+```
+
+## The gates
+
+| Job | Tool | What it stops |
+|-----|------|---------------|
+| `lint` | ruff | style + a security rule set (`S`) on top of the usual lint |
+| `sast` | Semgrep | the OWASP/Flask rule packs plus four custom rules in `.semgrep/rules.yml` |
+| `secrets` | gitleaks | committed credentials, full history scanned on PRs |
+| `dependencies` | pip-audit | known-vulnerable pinned dependencies |
+| `test` | pytest | regressions, with coverage reported |
+| `notify-soc` | `scripts/notify_soc.py` | nothing - it posts the run outcome to the SOC |
+
+`lint` runs first as a cheap fail-fast. The three security scans fan out in
+parallel, `test` waits on all of them, and the SOC notification runs last with
+`if: always()` so the SOC hears about failures too, not just green runs.
+
+## Custom Semgrep rules
+
+The packs catch the common cases; `.semgrep/rules.yml` adds the ones I kept seeing
+slip through:
+
+- Flask started with `debug=True` (Werkzeug debugger RCE)
+- `subprocess` with `shell=True` on a non-literal argument
+- `jwt.decode` with signature verification disabled
+- binding to `0.0.0.0` without an explicit reason
+
+The four rules running against a deliberately vulnerable file - every finding is
+Blocking, so the SAST job fails the pipeline before the code can merge:
+
+![Semgrep custom rules](docs/screenshots/01-semgrep-sast.png)
+
+## SARIF and the Security tab
+
+Semgrep emits SARIF that gets uploaded with `github/codeql-action/upload-sarif`, so
+findings show up under the repo's Security tab and as inline PR annotations rather
+than only in the job log.
+
+The dependency gate is `pip-audit`, which fails the build on a pinned package with a
+known advisory:
+
+![pip-audit dependency scan](docs/screenshots/02-pip-audit-deps.png)
+
+## Run it locally
+
+```bash
+make install
+make all
+```
+
+`make all` runs the same gates the pipeline does. You need `semgrep` and `gitleaks`
+on your PATH for the `sast` and `secrets` targets; everything else is pip-installed
+by `make install`.
+
+## SOC integration
+
+The last job posts the run outcome - repo, commit, actor, status, and a link back to
+the run - to a Shuffle webhook. In my lab that webhook feeds the
+[SOC automation lab](../soc-automation-lab), so a failed security gate opens a case
+in TheHive the same way a Wazuh alert does. Set the `SHUFFLE_WEBHOOK_URL` repository
+secret to wire it up; without it the job no-ops instead of failing.
+
+More detail in [docs/pipeline.md](docs/pipeline.md) and
+[docs/soc-integration.md](docs/soc-integration.md).
docs/screenshots/01-semgrep-sast.png +0 -0
Binary file not shown
docs/screenshots/02-pip-audit-deps.png +0 -0
Binary file not shown