Skip to content

DevSecOps: Establish security-focused CI pipeline (SAST/SCA/IaC + gating for main) #31

Description

@necdetsanli

Context

We want a production-grade DevSecOps pipeline for Do Not Ghost Me that:

  • Detects security issues early (PR-time).
  • Produces actionable results inside GitHub (checks + Security tab / Code Scanning).
  • Enforces merge gates on main, while keeping staging fast and iteration-friendly.

Recent work includes:

  • Adding a Snyk workflow draft (SAST + SCA + IaC + Container) and SARIF upload capability.
  • Updating GitHub Actions dependencies via Dependabot bumps.
  • Adding repo-level tooling/config around coverage/security (e.g. Codecov config), and adjusting Dependabot behavior to target staging-only PRs.

Goals

  • Add/standardize security scanning in CI:
    • SAST (Code scanning)
    • SCA (dependency vuln scanning)
    • IaC scanning (Terraform/Docker/K8s configs if present)
    • Container scanning (Dockerfile/image), if applicable
  • Upload results to GitHub Code Scanning (SARIF) where possible.
  • Make security checks required on main (merge gate), but not required on staging.
  • Keep permissions minimal and workflows deterministic (pinned action SHAs, least privilege).

Requirements / Constraints

  • Main branch: security checks must pass before merge (ruleset required status checks).
  • Staging branch: security scans may run, but should not block merges by default.
  • Secrets:
    • Workflow uses SNYK_TOKEN (or equivalent). We must decide how it behaves on PRs from forks and Dependabot PRs.
    • If we want scanning to run on Dependabot PRs, we may need to configure Dependabot secrets or accept that secrets are not available there.
  • Avoid noisy/low-signal failure modes. Prefer “reporting” for staging and “enforcing” for main.

Proposed approach

  1. Decide toolset (industry standard baseline)

    • CodeQL (GitHub-native SAST)
    • Dependabot alerts + security updates (SCA baseline)
    • Optional: Snyk (SAST/SCA/IaC/container) for deeper scanning
  2. Workflow design

    • One workflow file, with logic:
      • main: fail the check on findings above threshold (or fail on tool exit code).
      • staging: always upload results but do not fail (or use different severity threshold).
    • Ensure Node install and dependencies are set up before scanning where needed.
    • Pin all GitHub Actions to major versions (or commit SHAs for extra hardening).
  3. Branch rulesets

    • Add required status checks for main (e.g. ci, codeql, snyk-security).
    • Keep staging less strict (required: ci only, optionally vercel).
  4. Security tab integration

    • SARIF upload for code scanning (GitHub Code Scanning UI).
    • Ensure alerts show up consistently and are easy to triage.

Tasks

  • Choose security tooling set: CodeQL only vs CodeQL + Snyk (and which features)
  • Add CodeQL workflow (or enable default setup) for JS/TS
  • Add / finalize Snyk workflow (if we keep Snyk)
    • Snyk Code (SAST) -> SARIF upload
    • Snyk Open Source (SCA)
    • Snyk IaC (if applicable)
    • Snyk Container scan (only if Dockerfile/image exists and is meaningful)
  • Define severity thresholds:
    • main: fail on high/critical (or configurable)
    • staging: report-only (do not block)
  • Confirm secrets strategy:
    • behavior for fork PRs (no secrets)
    • behavior for Dependabot PRs (Dependabot secrets vs skip)
  • Update branch rulesets to enforce required checks on main only
  • Document in README/SECURITY.md:
    • what runs where
    • how to interpret results
    • how to rotate tokens / manage secrets

Acceptance criteria

  • PRs targeting main cannot be merged unless:
    • CI passes
    • Security scan checks pass (as defined)
  • PRs targeting staging run scans but do not block merge by default.
  • Security results are visible in GitHub (checks + Code Scanning where applicable).
  • Workflows use least-privilege permissions and are stable (no flaky steps).

Notes / Open questions

  • What is our minimum viable enforcement level for main?
  • Do we want Snyk to be required, or keep GitHub-native (CodeQL + Dependabot) as the baseline?
  • How should we handle token availability on Dependabot PRs and fork PRs?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions