DEV Community

Wen Ping
Wen Ping

Posted on

Replace Semgrep, Trivy, and Gitleaks scripts with one scan gate

The merge request is green, then release is blocked by a secret or dependency CVE—usually because Semgrep, Trivy, and Gitleaks each own a job: three logs, three exit codes, no shared Finding, no shared suppressions.

Takeaway: Put SAST (static application security testing), secret scanning, and SCA (software composition analysis for deps/artifacts/images) into one scan job, normalize to one Finding model, then apply policy for PASSED / FAILED / SKIPPED. Community edition is GPL-3.0—use, modify, and distribute freely (see the repo LICENSE). This path can replace a pile of standalone scanner scripts. It does not replace full-site DAST, host IDS/RASP, or enterprise asset vulns platforms.

Below is replace script sprawl + Semgrep migration.

1. Where teams get stuck

Symptom Usual cause
PR blocks SAST only; images scanned on main Three jobs onboarded at different times
Same issue in Semgrep logs and Trivy CSV No shared fingerprint / disposition
Exit code 1 means “everything bad” Scripts treat all non-zero alike
Rule upgrades touch three YAML files Rule versions not bound to one job model
Empty Findings but PASSED Stub engines or empty vuln DB

Shortest path: install engines → doctor non-stub → small repo sast+secret → Findings and gate visible in console → run in parallel for about a week, then delete standalone jobs.

2. Capability map

Capability Plain language Default engine Typical target
sast Static dangerous patterns (injection, XSS, unsafe deserialization, …) OpenGrep Source / Git
secret Hard-coded AK/SK, tokens, private keys, connection strings Gitleaks Source / Git (history optional)
sca Known CVEs and license issues in deps, artifacts, images Trivy Directory deps, artifacts, images

Quality (smells, complexity) can run separately and by default does not count toward the security gate. Do not treat SonarQube Scanner as the default security core—console/docs win for quality engines.

Primary target types: upload, Git repo, artifact URL, container image; CLI can also scan a local directory. The console is not meant to scan arbitrary server paths.

3. From three scripts to one gate

3.1 Before (sketch)

# Problem: three logs, three exit semantics, no unified governance
semgrep:
  script: [semgrep ci --config auto]
trivy-fs:
  script: [trivy fs --exit-code 1 .]
gitleaks:
  script: [gitleaks detect --source . --exit-code 1]
Enter fullscreen mode Exit fullscreen mode

3.2 After: one job

Command shape follows current angus-security --help; this is a copyable sketch:

export ANGUS_SECURITY_URL="https://security.example.com"   # console onboarding wins
export ANGUS_SECURITY_TOKEN="***"                          # CI secret only—never commit

angus-security scan run \
  --target-type DIRECTORY \
  --path . \
  --capabilities sast,secret,sca \
  --fail-on high
Enter fullscreen mode Exit fullscreen mode

Exit codes (when aligned with product docs; confirm on your CLI):

Code Meaning CI handling
0 Gate passed Continue
1 Scan OK, Findings over policy Block merge/release; fix or suppress
2 Execution error (engine/network) Page ops—not a business vuln
3 Config / auth error Fix token/args—not a business vuln

Gate also has SKIPPED (e.g. capability not covered)—skipped ≠ passed.

3.3 Minimal GitLab step (other platforms linked)

# .gitlab-ci.yml (sketch)
security-scan:
  stage: security
  script:
    - angus-security tools doctor || true
    - angus-security scan run --target-type GIT_REPO
        --repo "$CI_REPOSITORY_URL"
        --ref "$CI_COMMIT_SHA"
        --capabilities sast,secret
        --fail-on high
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
Enter fullscreen mode Exit fullscreen mode

Layering: PR with sast+secret and a higher threshold; nightly/release add sca (artifact or image). GitHub Actions / Jenkins and full layering: CI integration Reference.

4. Migrating off Semgrep

OpenGrep targets Semgrep-like rule matching. Migrate as “rule pack → job capability → gate,” not a line-by-line rewrite of every rule.

Semgrep habit In the unified job
semgrep ci --config auto / custom ruleset Enable sast; bind rule-pack version on project/job
PR scans changed files only Shallower scan level (e.g. QUICK); full tree nightly
--severity-threshold / custom exit Platform --fail-on / policy thresholds → PASSED/FAILED
SARIF upload to GitHub Export SARIF after the job from reports/Findings
Separate Gitleaks job Add secret on the same job

4.1 Parallel cutover (about a week)

  1. Keep old Semgrep stage while the new job runs.
  2. Same small repo once each: high/blocking volume should be in the same order of magnitude (not byte-identical counts).
  3. Enable secret; confirm secrets no longer need a standalone Gitleaks job.
  4. Sample 3–5 highs: fingerprints exist; suppressions possible (TTL in the disposition article).
  5. Split CI alerts for exit 1 vs 2/3.
  6. Delete standalone semgrep / trivy-* / gitleaks stages; canary before adding sca to release gates.

Language coverage follows the current rule pack—do not claim “all languages.” If you depend on a Semgrep-ecosystem-only third-party pack, verify OpenGrep coverage first.

5. Console check that you “folded into one”

Text-only path:

  1. Open the scan job: completed; capability list matches what you enabled.
  2. Findings filter by engine/capability—stop grepping three external logs.
  3. Gate on the summary is PASSED/FAILED/SKIPPED and matches CI exit semantics (1 = over gate, not 2/3).
  4. For leadership/audit, export a report snapshot—do not screenshot the Findings home (see report-export Reference).

6. Failure table and boundaries

Symptom Cause Fix
Empty Findings + PASSED Stub engines or empty DB doctor non-stub; SCA false green → vuln DB article
Still three jobs New job added, old not removed Delete after parallel week
Exit 2 treated as vuln Engine missing / bad token Separate gate fail vs exec fail
Secret flood Fixtures / docs examples Suppressions Reference
Repo ingest treated as full governance Repo light gate ≠ Security depth Repo integration Reference

Out of scope: full-site DAST, RASP/host IDS, Qualys-class asset inventory, “scan equals MLPS pass,” AI auto-opening fix PRs.

FAQ

Does this fully replace Semgrep OSS?

On the “CI rule match + unified gate” path, yes for script sprawl. Verify third-party packs before migrating.

Is community edition enough to prove the path?

GPL-3.0 community can run install-engines + first scan. Seats/quotas/commercial follow console/docs—no pricing here.

How is this different from “Sonar as security”?

Quality analysis ≠ security pattern match. Security path is OpenGrep / Gitleaks / Trivy; quality gates stay separate by default.

Keep old SARIF pipelines?

Govern on platform Findings; export SARIF when IDE/tickets need it.

Summary

  • Three scripts → one job, one Finding model, one gate.
  • doctor → sast+secret → parallel week → then delete old jobs; add sca for release.
  • Split “over gate” from “did not run.”
  • Not a DAST/host replacement; Repo light gate ≠ Security depth.

Reference articles

Top comments (0)