Skip to content

Add DevSecOps pipeline: SAST, SCA, secret scanning, IaC checks, and Claude review - #305

Merged
gerardrecinto merged 11 commits into
masterfrom
feat/devsecops-pipeline-and-remediation
Sep 10, 2026
Merged

gerardrecinto merged 11 commits into
masterfrom
feat/devsecops-pipeline-and-remediation

Conversation

@gerardrecinto

Copy link
Copy Markdown
Collaborator

Summary

  • Adds CodeQL SAST (Go + JS/TS), Gitleaks secret scanning, govulncheck + Trivy dependency scanning, and Trivy Dockerfile/image config scanning, all blocking on critical/high and warning on medium.
  • Fixes two Dockerfiles (nocov test runner, bindings build image) that were running as root, which the new Trivy config scan correctly flagged.
  • Adds make security-scan and per-check targets (lint-sec, sca, secrets-scan, iac-scan, sast) mirroring CI for local pre-push checks.
  • Adds a Claude Code PR review workflow (posts findings as a comment, read-only) and a suggest-only remediation workflow triggered by /remediate or /claude fix (posts a diagnosis and patch as a comment, never commits).
  • Updates SECURITY.md to document the new controls.

Notes

  • Both Claude workflows need an ANTHROPIC_API_KEY repository secret to run; without it those two jobs fail but nothing else is affected.
  • golang.org/x/crypto has two known medium-severity CVEs (fixed in 0.56.0), surfaced by the new scan but not blocking. Worth a follow-up bump.
  • Found and left alone (out of scope here): .dockerignore excludes bindings/ from every Docker build context, so bindings/Dockerfile.build's own release build script can't actually find bindings/main when run. Pre-existing, unrelated to this PR.

Test plan

  • make security-scan passes locally (gofmt, go vet, govulncheck, Trivy fs/config, Gitleaks)
  • Built and ran the fixed Dockerfile.nocov image as non-root; full integration test suite passes
  • Built the fixed bindings/Dockerfile.build image and verified a representative cgo build succeeds as non-root
  • Built the runtime Dockerfile target and ran a Trivy image scan against it: clean
  • actionlint on all new/existing workflow files: no new issues beyond pre-existing shellcheck style warnings already present in the repo's other workflows
  • CI checks green on this PR (CodeQL, Security, existing CI/Go workflows)

Runs on push/PR to master plus a weekly schedule, using the
security-extended query pack. Go packages are built manually in two
passes (native plus GOOS=js/GOARCH=wasm) since demo and demo-agents
only compile under wasm, matching the exclusion already used in
ci.yml and go.yml.
Adds a Security workflow covering:
- Gitleaks secret scanning across full git history, with a baseline
  allowlist for generated dataset content and legacy scaffolding that
  otherwise trips the generic-api-key rule.
- govulncheck plus a Trivy filesystem scan for dependency CVEs,
  blocking on critical/high and reporting medium as a warning.
- Trivy config scanning of all four Dockerfiles for misconfigurations,
  same critical/high-blocks, medium-warns policy.
- A Trivy image scan of the built runtime container.

Filesystem scans run with --offline-scan since the Java binding's
pom.xml otherwise triggers live Maven Central lookups that get rate
limited on shared CI egress IPs.
Both images ran as root by default, which the new Trivy config scan
correctly flags as DS-0002. Neither actually needs it: the nocov
integration test runner only starts Redis on an unprivileged port and
runs go test, and the bindings build image only compiles Go/cgo code.

Both stages now create a dedicated non-root user and redirect
HOME/GOPATH/GOCACHE to a writable home directory, since the module and
build caches would otherwise resolve to root-owned paths. Verified by
building and running each image directly: nocov's full integration
suite passes, and a representative cgo build in the bindings image
succeeds with the redirected caches.
Adds security-scan, lint-sec, sast, sca, secrets-scan, and iac-scan
targets that mirror the checks in the new CI workflows, so issues
surface before a push instead of after CI runs. sca and iac-scan
snapshot tracked and non-ignored files into a temp directory before
handing them to Trivy rather than scanning the live working tree, so
gitignored local runtime state (dev server session data, .sop_data)
doesn't get scanned and reported as if it were committed.
claude-review.yml runs a security-focused review on every PR open and
update, posting findings as a single comment. It only has read-only
tool access (Read, Grep, Glob, and read-only git/gh commands) and no
contents:write permission, so it cannot modify the branch.

claude-remediation.yml only runs when a maintainer comments /remediate
or /claude fix on a PR. It diagnoses the failing checks and posts a
suggested patch as a comment for a human to apply; it does not commit
anything itself, by the same read-only tool restriction. Both require
an ANTHROPIC_API_KEY repository secret.
Explains what the CodeQL, Gitleaks, Trivy, and govulncheck checks
cover, how to run the equivalent checks locally with make, and how the
Claude Code review/remediation workflows are scoped.
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@0.28.0 without the v prefix isn't a real ref for aquasecurity/trivy-action
(their tags are v0.x.x), so every Trivy job failed at job setup before
running anything. Pinned to the v0.33.1 commit SHA instead.
go build ./demo/... under GOOS=js GOARCH=wasm writes an output binary
named after the package directory into the cwd with no -o, which
collides with the demo/ directory itself and fails the whole job.
deploy-demo.yml already avoids this by always passing -o; codeql.yml's
build step didn't.
The v0.33.1 pin defaults to installing Trivy v0.65.0, and that install
now fails (the release asset trivy-action's install script expects is
gone), which failed every job in this workflow before it ran a single
scan. Bumped the pin to v0.36.0, which defaults to a current Trivy
release.
Both jobs hard-failed when ANTHROPIC_API_KEY wasn't set, which would
have shown red on every PR and every /remediate request until the
secret is added. secrets isn't a valid context in a job/step if, so
this adds a step that checks for the key and sets an output, and gates
the actual Claude step on that instead.
Two real bugs found by watching this workflow actually run in CI:

- trivy-action silently drops the severity filter in SARIF mode (to
  build a report covering every severity) unless
  limit-severities-for-sarif is set. Without it, the critical/high
  block steps were evaluating exit-code against every severity,
  including the known non-blocking MEDIUM golang.org/x/crypto CVEs,
  and failing every run.
- gitleaks/gitleaks-action@v2 now requires a paid GITLEAKS_LICENSE
  secret for organization repositories. Replaced it with the gitleaks
  CLI directly (still free and open source), same config and flags
  already verified locally.
@gerardrecinto
gerardrecinto merged commit a0f5f8c into master Sep 10, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants