Inspiration

Since 11 September 2026 manufacturers of software sold in the EU must report actively exploited vulnerabilities to ENISA within 24 h (early warning), 72 h (notification) and 14 days after a fix (final report) — and from December 2027 must keep an SBOM and technical documentation for every release. Small teams treat this as paperwork after the code is done: scattered SBOMs, spreadsheets, and a scramble when an exploited CVE appears. That is exactly the "life after code".

What it does

cra-gate makes GitLab run the post-code lifecycle for CRA compliance:

  • CI (deterministic): tests, container image, CycloneDX SBOM and an exploited-vulnerability check (CISA KEV / ENISA EUVD / EPSS) with the open-source cra-scan; a scheduled cra:watch re-scans the released lockfile.
  • Flow 1 — Release Gate: on a release MR, triages findings (including whether the vulnerable code is reachable), files issues, commits the Annex VII compliance dossier with the SBOM hash, and posts a PASS / PASS WITH JUSTIFICATION / BLOCK verdict.
  • Flow 2 — Vulnerability Watch: when the watch fails, escalates the issue, computes the Art. 14 deadlines, opens a fix MR with the exact fixed version and git revision (computed by CI, never invented), a draft security advisory and a draft ENISA early warning.
  • Supervised by design: the flows never merge. The maintainer — the legal "manufacturer" — starts the fix pipeline and approves the MR, so the human sign-off the law requires is the workflow's gate.

How we built it

GitLab Duo Agent Platform custom flows (YAML; agent components with GitLab API tools), triggered by pipeline events, plus GitLab CI/CD, pipeline schedules with inputs, issues, MRs, labels and approvals. The agents' rules live in AGENTS.md. The demo product is a small Swift (Hummingbird 2) service deployed to Cloud Run; the scanner is cra-scan (Apache-2.0, a pinned PyPI dependency). Everything in the repository is MIT.

Challenges we ran into

  • Agents cannot look up a git revision for a dependency bump → CI computes a fix plan and the agent only copies it.
  • GitLab does not fire flow triggers for pipelines created by a flow's own service account → the maintainer's "Run pipeline" became the first human step of the gate (and prevents flows triggering each other in loops).
  • Schedule inputs reached jobs masked, so the simulation switch is passed as a script argument instead.
  • Demonstrating an exploited finding honestly → a clearly labelled simulation switch carried through every artifact.
  • Our first Cloud Run deploy answered 503: a handler in the wrong place of the HTTP pipeline crashed the server, and our router-only tests could not see it. We fixed it and added a live-server regression test.

Accomplishments we're proud of

Two flows that cooperate through GitLab itself (issues, MRs, labels, notes) with a complete audit trail; a fix MR that bumps both Package.swift and Package.resolved with the verified tag revision; covering all nine lifecycle stages (plan, create, verify, package, secure, release, configure, monitor, govern).

What we learned

Keep facts deterministic and let the agents do judgement and drafting; write the rules for the agents as a plain file (AGENTS.md); and test the unglamorous seams (triggers, tokens, bot-created pipelines), because that is where automation breaks.

What's next

GitLab security-report output from cra-scan (so findings appear in the MR security widget), more ecosystems, a "CRA Advisor" chat agent that answers "are we ready to release X?", and ENISA Single Reporting Platform field mapping.

Built With

  • cra-scan
  • gitlab-ci/cd
  • gitlab-duo-agent-platform-(custom-flows)
  • gitlab-issues/mrs/schedules
  • google-artifact-registry
  • google-cloud-run
  • hummingbird
  • kaniko
  • python
  • swift
  • swift-nio-extras
Share this project:

Updates

Submission history