DEV Community

Cover image for How to roll out a supply-chain gate: SBOM, then VEX, then refuse download
Wen Ping
Wen Ping

Posted on Originally published at anguskit.com

How to roll out a supply-chain gate: SBOM, then VEX, then refuse download

Thousands of findings and nobody reads the report; day-one global blocking and a company-wide allowlist three days later—usually not “missing a scanner,” but the wrong pacing.

This article is the schedule: SBOM → VEX → observe → “refuse download when checks fail.” Integration and policy fields: how to block vulns and licenses at admission. Ownership split: platform supply chain. Sample host repo.anguskit.com.

Product boundary:

  • AngusRepo = in-repo policies, vuln desk, download enforcement; deep SCA / cross-repo findings belong to AngusSecurity.
  • Without Security integration you rarely get a real vuln gate—do not pretend “upload means scanned.”
  • Push/upload auto-check is off by default; “refuse download when checks fail” is off by default.
  • Policies bind only to HOSTED / PROXY—not GROUP or Raw. Manual: security scanning.

Rule of thumb: See first (SBOM), discriminate next (VEX), observe before you enforce. In the console the switch is “refuse download when checks fail” (aka autoBlock below).

SBOM → VEX → observe → refuse download

1. Two failure scripts, two fixes

Failure Symptom Fix
Detection only Reports pile up; prod still pulls old packages Inventory + archive, then enforce
Over-enforcement Company-wide pull 403 on day one Observe, clear FPs with VEX, open narrow

Order of the trilogy: SBOM (see) → VEX (discriminate) → refuse download (stop). Shuffle it and you replay the table.

Division of labor vs the admission article: that one covers Security integration and policy fields; this one covers when to open each step and what to clear before blocking.

2. SBOM: give every artifact an inventory

An SBOM answers: what is actually inside this artifact?

After checks run, Security → scan history can export SBOM (CycloneDX / SPDX) for finished tasks. Right usage is not “generate and archive”—it is:

Scenario Practice
New CVE drops Reverse-lookup against existing SBOM / scan indexes—minutes, not days
Compliance delivery Archive SBOM with the release; export on audit
Release gate Confirm SBOM retained before promote (see release practices)

How scans are triggered (product-accurate)

Trigger Notes
Policy: check on push/upload Off by default; opens a task for new HOSTED/PROXY artifacts
Policy: scheduled scan Covers inventory; optional force-rescan for audit trail
Immediate scan Console Security / repo Scan
Explicit pipeline wait After publish, wait for the task before deploy

No ready engine / no integration → no trustworthy vuln results. “Two lights” detail: admission article.

3. VEX: separate “has a CVE” from “should block”

Scanners cry wolf: a CVE anywhere in the tree turns red, reachable or not. Real threats drown in thousands of alerts; teams learn to ignore red.

In Repo Security → Vulnerabilities you can import VEX (standard OpenVEX JSON). Updates disposition by CVE + component (suppress FPs, mark unreachable, etc.). VEX does not replace a scan.

Verdict (concept) Follow-up
Not Affected / unreachable Denoise alerts; keep rationale
Affected Remediation queue; counts toward the gate if over threshold
Under Investigation Deadline + owner

Process rules:

  1. Named owner and SLA (e.g. Under Investigation ≤ 5 business days).
  2. Waivers live on the repo vuln desk—not scattered project .ignore / allowlists.
  3. After the gate is on: console suppress / accept risk does not lift quarantine—fix and republish, or raise threshold and rescan (see the manual gate section).

4. “Refuse download when checks fail”: flip last

When on: failing artifacts are quarantined; download / preview / image pull denied (clients often see 403); bytes stay in the repo. Failed or incomplete checks also block. Multiple policies on one repo → strictest wins.

Canary pacing (never fleet-enable on day one)

  1. Preflight — engine/integration healthy; critical HOSTED baseline scanned; intel sync works.
  2. ~Two weeks observe — gate off, reports only; daily “what would have blocked”; clear via VEX / fixes.
  3. Narrow → wide — non-prod first; start at high severity; then prod.
  4. Escape hatch — emergency waiver (approval + TTL) rehearsed; a gate with no hatch gets bypassed wholesale.

After enabling, existing artifacts wait for the next check before quarantine—use Immediate scan on the policy for instant effect. Disable the gate with no other gating policy → quarantine immediately lifts.

Counterintuitive: a gate’s value is not block count, but fewer blocks after deterrence—upstream CI learns to self-check; block events should trend down.

5. Wire CI (AngusGit first)

Wait for the gate before deploy. Prefer AngusGit / AngusCICD (credentials = Repo Deploy Token). YAML intro: AngusCICD. Skeleton also in Jenkins build-test-publish.

# .anguscicd/publish-then-gate.yaml (sketch)
version: "1"
name: publish-then-gate

triggers:
  - on: tag
    branches: ["v*"]

pipeline:
  publish:
    runner:
      mode: DOCKER
      image: node:20
      labels: ["linux", "docker"]
    credentials: ["NPM_TOKEN"]
    steps:
      - name: publish HOSTED
        run: |
          npm config set //repo.anguskit.com/npm/npm-hosted/:_authToken "$NPM_TOKEN"
          npm publish --access restricted
        timeout: 600

  # Wait for scan/gate: follow console policy and documented APIs
  # Failure logs should be readable (CVE / policy), not a bare 403
Enter fullscreen mode Exit fullscreen mode

CI pre-scan does not replace Repo enforcement on published coordinates.

6. Failure table

Symptom Likely cause Fix
Upload OK but “never scanned” No integration / auto-check off / engine not ready Check Security link + policy
Fleet paralysis on enable No observe, no VEX, prod first Disable → observe → non-prod pilot
False 403 Threshold too strict / FP not in VEX Import VEX or retune + rescan
Old packages still pull after enable Inventory not rescanned Policy Immediate scan
“No vulns” treated as safe Job never ran / LOCAL_ONLY Scan history + integration status

7. Landing checklist

  • [ ] Security integration health check green (deep scan on)
  • [ ] Critical HOSTED/PROXY have policies; GROUP/Raw not mis-bound
  • [ ] Push auto-check or schedule covers new + existing
  • [ ] Can export CycloneDX/SPDX; one CVE reverse-lookup drill done
  • [ ] VEX import has owner/SLA; waivers not in project files
  • [ ] “Refuse download” observe first, then non-prod
  • [ ] Waiver path (approval + TTL) rehearsed ≥ once
  • [ ] Pipelines deploy only after the gate passes

8. FAQ

How is this different from the admission article?

Admission covers integration + policy fields + verification; this article covers SBOM/VEX/enable pacing. Integrate first, then schedule here.

Does a successful upload mean it was scanned?

No. Auto-check is off by default; without integration, vuln tasks rarely appear.

Can suppress unlock download?

With “refuse download” on: no—suppress/accept risk does not lift quarantine. See the manual.

Can a GROUP repo enable the gate?

Policies cannot bind to GROUP. Put the gate on member HOSTED (or relevant PROXY).

9. Takeaways

  • Order: SBOM → VEX → observe → refuse download when checks fail.
  • Repo enforces; Security runs the engine; green upload ≠ scanned.
  • Non-prod first, narrow first; rehearse the escape hatch.

Reference articles

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.