Skip to content

ci(sast): blocking Semgrep gate on the untrusted-document parsing surface (maturity X4) - #1012

Merged
BigSimmo merged 3 commits into
mainfrom
claude/x4-sast-gate
Jul 20, 2026
Merged

ci(sast): blocking Semgrep gate on the untrusted-document parsing surface (maturity X4)#1012
BigSimmo merged 3 commits into
mainfrom
claude/x4-sast-gate

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 20, 2026

Copy link
Copy Markdown
Owner

What

Completes maturity workorder X4: Semgrep ERROR findings now block on the untrusted-document parsing surface instead of merely advising.

  • New semgrep-ingestion-gate job in sast.ymlno continue-on-error — scoped to worker/**, src/lib/ingestion*.ts, src/lib/extractors, src/app/api/ingestion, src/app/api/upload, using the same pinned semgrep/semgrep:1.168.0 image and rule packs as the advisory job, plus p/python so the worker's OCR stack (the code that actually opens untrusted PDFs) is covered.
  • The repo-wide advisory job is untouched — registry-rule mutability keeps it advisory by design.
  • check-github-action-pins.mjs now enforces both halves of the policy fail-closed: the repo-wide scan step must remain advisory, and the ingestion gate must exist, must not carry continue-on-error, and must keep its target scope and p/python.
  • docs/maturity-backlog-workorders.md: X4 marked DONE with triage evidence.

Triage (the workorder's precondition)

Ran the CI-pinned image over the scoped paths locally via Docker before flipping the gate: 0 ERROR findings (24 TS rules / 17 files; 55 Python rules / 3 files) — the gate starts green with no code changes or suppressions.

Risk

  • Registry packs can change independently of this repo — accepted deliberately for this narrow surface (ERROR-only, ~21 files → rule-churn exposure is small); a spurious future finding fails only this job and is triaged like any red check.
  • Note: the SAST workflow is not a branch-protection required check; job-level blocking makes findings fail the workflow (and auto-merge waits on it via check state). Making it a required check is an operator/settings decision, not part of this PR.

Verification

  • Exact gate command (glob form) green in the pinned container, exit 0
  • check:github-actions (incl. the new assertions, verified fail-closed), check:ci-scope, yaml-contract vitest
  • npm run verify:cheap green (337 files / 3031 tests)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Security

    • Added a blocking Semgrep scan focused on the untrusted document parsing and ingestion path (including worker, extraction, and ingestion/upload routes).
    • Semgrep ERROR findings in this scope now fail CI (no longer advisory).
    • The blocking gate uses a digest-pinned Semgrep runner for stronger CI integrity.
  • Documentation

    • Recorded the new security gate and the zero-ERROR results from the scoped scan.
    • Updated internal maturity tracking to mark the SAST ingestion gate as complete.
  • CI / Maintenance

    • Added stricter CI checks to ensure the required blocking gate and configuration are present and fail closed if missing.

…face (maturity X4)

The repo-wide Semgrep job stays advisory (registry rules are mutable), but the
paths that open attacker-supplied uploads now get a second, path-scoped job
with no continue-on-error: worker/** (including the Python OCR stack via
p/python), src/lib/ingestion*.ts, src/lib/extractors, and the ingestion/upload
API routes. ERROR-severity findings there fail the workflow instead of merely
advising.

Triage-first per the workorder: the CI-pinned semgrep/semgrep:1.168.0 image
run over the scoped paths reports 0 ERROR findings (24 TS rules / 17 files,
55 Python rules / 3 files), so the gate starts green.

check-github-action-pins.mjs now enforces both halves of the policy
fail-closed: the repo-wide scan step must remain advisory, and the ingestion
gate must exist, must not carry continue-on-error, and must keep its target
scope and p/python config.

Verification: exact gate command green in the pinned container (exit 0),
check:github-actions, check:ci-scope, yaml-contract vitest, verify:cheap
(3031 tests).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f54725a-9221-41a7-b515-cc79261be472

📥 Commits

Reviewing files that changed from the base of the PR and between ccb044b and 1d7d814.

📒 Files selected for processing (4)
  • .github/workflows/sast.yml
  • docs/branch-review-ledger.md
  • docs/maturity-backlog-workorders.md
  • scripts/check-github-action-pins.mjs
🚧 Files skipped from review as they are similar to previous changes (4)
  • .github/workflows/sast.yml
  • scripts/check-github-action-pins.mjs
  • docs/maturity-backlog-workorders.md
  • docs/branch-review-ledger.md

📝 Walkthrough

Walkthrough

A new blocking Semgrep job scans the untrusted ingestion and parsing surface for ERROR findings. CI validation now requires the job, scoped targets, Python ruleset, and digest-pinned image, while review and maturity records document the completed gate.

Changes

Ingestion SAST gate

Layer / File(s) Summary
Add blocking ingestion Semgrep job
.github/workflows/sast.yml
Adds a digest-pinned Semgrep container job that scans worker, ingestion, extraction, upload, and parser paths with blocking ERROR severity settings.
Validate and document the gate
scripts/check-github-action-pins.mjs, docs/branch-review-ledger.md, docs/maturity-backlog-workorders.md
Validates the gate’s presence, blocking behavior, targets, Python ruleset, and image pin; records the zero-error result and marks X4 complete.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the new blocking Semgrep gate on the untrusted-document parsing surface and matches the PR's main change.
Description check ✅ Passed The description covers summary, triage, risk, and verification, and it is mostly complete despite omitting the template's clinical governance checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/x4-sast-gate

Comment @coderabbitai help to get the list of available commands.

@supabase

supabase Bot commented Jul 20, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/sast.yml:
- Around line 67-68: Pin the semgrep-ingestion-gate container in
.github/workflows/sast.yml at lines 67-68 to a verified `@sha256`: digest instead
of the mutable 1.168.0 tag. Update check-github-action-pins.mjs at lines 79-103
to reject tag-only references for semgrep-ingestion-gate. Update the related
tracking entries in docs/branch-review-ledger.md:664 and
docs/maturity-backlog-workorders.md:97-102 to reflect the completed digest
pinning and enforcement changes.

In `@docs/branch-review-ledger.md`:
- Line 664: The X4 completion records use a future date and prematurely mark the
work as shipped. In docs/branch-review-ledger.md lines 664-664, defer the entry
or replace its date with the actual completion date; in
docs/maturity-backlog-workorders.md lines 88-102, remove the “Shipped
2026-07-21” claim; and at lines 198-198, restore the non-completed status until
the gate has shipped.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fe8059bd-8914-45de-81f0-a59080b728cb

📥 Commits

Reviewing files that changed from the base of the PR and between f33890a and ccb044b.

📒 Files selected for processing (4)
  • .github/workflows/sast.yml
  • docs/branch-review-ledger.md
  • docs/maturity-backlog-workorders.md
  • scripts/check-github-action-pins.mjs

Comment thread .github/workflows/sast.yml Outdated
Comment thread docs/branch-review-ledger.md Outdated
@BigSimmo
BigSimmo enabled auto-merge (squash) July 20, 2026 22:23
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

The agent ran but didn't make any changes. The issues may already be fixed or require manual intervention.

…in pins check

Review follow-up (PR #1012): the blocking job's engine must be immutable, so
the gate now uses the sha256 digest of the exact semgrep/semgrep:1.168.0 image
the X4 triage ran, and check-github-action-pins.mjs rejects a tag-only
reference for that job. Tracking docs updated to record the digest pinning.
The advisory job keeps its tag deliberately - it is non-blocking by policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@BigSimmo
BigSimmo disabled auto-merge July 20, 2026 22:33
@BigSimmo
BigSimmo enabled auto-merge (squash) July 20, 2026 22:33
@BigSimmo

Copy link
Copy Markdown
Owner Author

Review findings dispositioned:

  1. Digest-pin the blocking container — FIXED (1d7d814). The semgrep-ingestion-gate container is now pinned to semgrep/semgrep@sha256:59fbed61… — the digest of the exact 1.168.0 image the X4 triage ran — and check-github-action-pins.mjs rejects any tag-only reference for that job (fail-closed). The gate command was re-verified green by digest (exit 0). Tracking docs updated. The repo-wide advisory job deliberately keeps its tag: it is non-blocking by policy, and its existing checker assertions are unchanged.

  2. "Future date / premature DONE" — SKIPPED (finding is factually incorrect). Today is 2026-07-21; the ledger and workorder dates are the actual dates. The DONE marking is not premature: it merges atomically with the gate itself in this PR, so main can never contain the claim without the gate. Wording clarified to "Shipped (this PR)".

@BigSimmo
BigSimmo merged commit daf66e5 into main Jul 20, 2026
18 checks passed
@BigSimmo
BigSimmo deleted the claude/x4-sast-gate branch July 20, 2026 22:38
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.

1 participant