Security Steward — Devpost

Tagline: Given the file a security finding flags, route it to the active engineer with the strongest evidence-based claim to that code — from GitLab's knowledge graph, not a stale CODEOWNERS file or a guess.


Inspiration

GitLab's blast-radius demo assigns each vulnerable component to its owner. But in real triage the hard question comes first: who owns this finding at all? Scanners (SAST, dependency, secret) emit findings with no assignee. Deciding who should fix them is manual, slow, and stalls remediation — and CODEOWNERS is often coarse, stale, or missing, worst exactly where it matters: on legacy and long-tail code whose authors have moved on. We wanted that routing decision to be evidence-based and auditable, not a guess.

What it does

Security Steward takes an affected file (or a vulnerability id it resolves to a file) and reasons from two facts in the GitLab Knowledge Graph (Orbit):

  • AUTHORED — who has actually changed this file/area (real merge-request history)
  • MEMBER_OF — which of those people are still active on the project

…and returns one of three honest outcomes:

  1. the file's own authors are still active → assign the best-supported one;
  2. the authors aren't on the team but an active contributor maintains the area → assign them;
  3. nobody active → say so and escalate to CODEOWNERS / a lead, rather than invent an owner.

It then gates on a human confirmation and files one assigned GitLab issue with the evidence in the description. Orbit is read-only; the single write is one glab issue create.

How we built it

  • Evidence comes entirely from read-only Orbit graph traversals: User -[AUTHORED]-> MergeRequest -[HAS_DIFF]-> MergeRequestDiff -[HAS_FILE]-> MergeRequestDiffFile (matched on old_path), intersected with User -[MEMBER_OF]-> Project.
  • Reasoning is a small, deterministic continuity.py — no LLM in the decision path, so every recommendation traces to graph edges you can verify.
  • The only write is glab issue create (assignee + security::remediation label + evidence body + Orbit provenance footer).
  • Ships in three forms: a reference CLI (steward.sh) with a real confirmation gate, a committed GitLab Duo external agent, and an AI Catalog custom flow with a native HumanInputComponent approval step.

Challenges we ran into

  • No vulnerability→file edge in Orbit (DETECTED_IN points at a pipeline), so the file path comes from the location on VulnerabilityOccurrence.
  • Shared file paths across projects. In a multi-project namespace, dozens of projects share src/auth/.... A naïve author query collides across them, so we scope every query to the project with an IN_PROJECT hop.
  • Orbit indexing is a per-namespace beta flag GitLab allow-lists; we couldn't enable it on our own group, so we ran the live demo on an already-indexed namespace.
  • First-class vulnerability→issue linking is Ultimate-only, so we put the vulnerability URL in the issue body and never depend on the API — and never fabricate a finding link.

Accomplishments we're proud of

  • It ran live, end to end, on a real indexed graph — not a mock. A file whose last author is not on the team is correctly routed to the active maintainer, and the assigned issue is filed with the evidence.
  • Zero false positives. We ran the same logic across all 53 projects with authorship history in the hackathon group: it surfaced zero false gaps — it only fires on a genuine AUTHORED-without-MEMBER_OF, and the project-scoped queries never cross-match shared paths. The recommendation is precise and auditable.
  • Safe by construction: read-only graph, one human-gated write.

What we learned

Code ownership is dynamic — it lives in contribution history and current team membership, not a static file. For the long tail of legacy code that CODEOWNERS misses, the knowledge graph is a better source of truth, and intersecting two simple edges (AUTHOREDMEMBER_OF) is enough to make a defensible, explainable routing decision.

What's next

  • Ingest scanner findings directly (the vuln-id → file resolution is already implemented) so it triggers on every new finding.
  • Recency weighting using merged_at to rank among multiple active maintainers.
  • Reconcile with CODEOWNERS — use it where it's accurate, fill its gaps where it isn't.
  • Batch triage: route a whole security dashboard in one pass.

Built with

GitLab Knowledge Graph (Orbit) · glab · GitLab Duo Agent Platform / AI Catalog · bash · python · MIT.

Links

Built With

  • bash
  • claude
  • clickhouse-query-dsl
  • gitlab-duo-agent-platform
  • gitlab-duo-flows-/-ai-catalog
  • gitlab-knowledge-graph-(orbit)
  • gitlab-rest-api
  • glab-cli
  • python
Share this project:

Updates