Who it is for

Small software teams, roughly 2 to 20 engineers, that run a web service, let coding agents write part of it, and have no security engineer and no release engineer. Their three problems: agents write merge requests faster than people can review them; green scanners do not mean safe; and customers and regulators now ask for evidence (SBOM, VEX, signed provenance) that nobody has time to write.

What it does

You assign a GitLab issue to Dongjo. That is the only human action.

  1. Plan. In about a minute, a Plan Card appears on the issue: acceptance criteria, a STRIDE threat table, a risk label and a sequence diagram.
  2. Create. The builder agent writes the code and one test per acceptance criterion, and opens a merge request.
  3. Attack before merge. CI deploys the merge request to its own Cloud Run revision (no traffic). The red team agent writes new attacks from the STRIDE table and runs them over real HTTP against that live revision. One successful attack blocks the merge. Dongjo fixes the code and the same attacks run again.
  4. Merge. When every gate passes, a CI job merges at the exact commit the gates checked. The agent itself cannot merge, and gate-guard fails any agent change to the pipeline, the policy, the flow or existing attacks.
  5. Release. The signed image rolls out as a canary at 10, 50 and 100 percent, judged against stable at each step, with automatic rollback. The release carries a CycloneDX SBOM, an OpenVEX document whose not_affected statements are backed by the blocked attack transcripts, and an evidence pack signed with Sigstore. One cosign command verifies it.
  6. Watch. After every release and every 15 minutes, five user journeys and every attack ever committed run against production. If a promise breaks, Dongjo confirms twice, bisects the Cloud Run revisions, rolls back to the last good one and opens an incident assigned to Dongjo, which starts the loop again. (During judging it only reports; see below.)
  7. Map. On the issue, the Dongjo Map links all nine DevSecOps stages (Plan, Create, Verify, Package, Secure, Release, Configure, Monitor, Govern) to the jobs that prove them.

The Hands-off brief, step by step (run 4: issue #5, MR !23, v0.4.0):

The brief says Dongjo
You create an issue The issue is assigned to Dongjo at 16:20:25 UTC
Agents review it 55 s later: Plan Card with five acceptance criteria, a STRIDE table and dongjo-risk::high
Create 1+ MRs The builder opens MR !23 with one test per acceptance criterion
Run security scans SAST, secret detection, pip-audit, and 15 attacks against the MR's own live Cloud Run revision: 1 succeeded
Fix what they find Dongjo fixes the code; the same attacks: 0 of 15
Merge when everything passes The auto-merge CI job merges at the commit the gates checked, 16:31:29
Deploy to staging, validate Every MR runs on its own staging revision before merge; the canary is judged against stable
Promote to production Canary 10% → 50% → 100%, PROMOTE; a failing canary rolls back with no release
Post a summary on the issue The Dongjo Map: nine stages, each linked to its job
You touched nothing 0 human touches, issue → release in 23 minutes (runs 5 and 6: 21 and 26)
"We expect submissions that go well beyond them" OpenVEX from blocked attacks, a Sigstore-signed evidence pack, a production watch every 15 minutes with release bisect and rollback, and a sealed benchmark of the red team

Self-healing is real, and frozen for judging. From 26 October until the submission, the watch ran against production every 15 minutes with full authority to roll back and to hand Dongjo an incident; the drill below is it doing exactly that. The rules ask that the repository stay unchanged from the deadline until the winners are announced, and a self-healing Dongjo would change it by itself: a broken promise makes the watch roll back and open an incident, and the incident starts a Dongjo run that merges and releases. So before the deadline we set watch.act: false in dongjo.yml: the watch still checks production with every journey and attack every 15 minutes, confirms and bisects, but it moves no traffic and opens no incident. What it does when it acts is shown by the drill below, with links to its jobs. The README section "During judging: the watch only reports" has the details.

Results, every one linked in the README:

  • Three runs went from assignment to release with zero human touches, in 23, 21 and 26 minutes.
  • On Dongjo's own builder code, the red team found four real flaws in pipelines where unit tests, the AC gate, Semgrep SAST, secret detection and pip-audit were all green. None shipped.
  • Sealed benchmark, three runs. A person wrote small features with common API mistakes and sealed the answer key by SHA-256 before each run. Every gate passed all 16 mistakes. The red team caught 13 of 16. We also measured false positives on the same features without the mistake: after one prompt change they dropped from 4 of 6 to 0 of 6, and on new code in run 3 two of four were blocked, one of them by a real 500 the key had missed. Every miss and every wrong attack is quoted in the results.
  • A drill in production. We shipped a leak on purpose: a search cache switched on only in production. Every gate passed it. Four minutes after the release, the watch had confirmed it, rolled production back and opened an incident; Dongjo's fix held against 30 attacks and shipped. One human touch was needed (a test line too long for lint), and that cause is fixed too.

How we used GitLab to automate the post-code lifecycle

All nine stages, each with a proof link in the README's stage table:

  • Plan: the planner agent posts a Plan Card on the issue: acceptance criteria, a STRIDE threat table, a scoped risk label and a Mermaid sequence diagram.
  • Create: the builder agent opens the merge request, with a test named after every acceptance criterion.
  • Verify: lint, unit tests and ac-gate, which fails the MR if any acceptance criterion lacks a passing test.
  • Package: container build, CycloneDX SBOM, keyless cosign signature and SBOM attestation.
  • Secure: GitLab SAST, secret detection and pip-audit, plus the redteam agent's new attacks run over HTTP against the MR's own Cloud Run revision. One successful attack blocks the merge.
  • Release: the version is computed from Conventional Commits; the GitLab Release carries the changelog, the OpenVEX document and the signed evidence pack.
  • Configure: the Google Cloud platform as Terraform, planned read-only on every MR; Cloud Run revisions deployed by digest through Workload Identity Federation, with no stored keys.
  • Monitor: a canary judge at 10, 50 and 100 percent with automatic rollback; after release, a scheduled watch every 15 minutes that bisects revisions, rolls back and opens an incident assigned to Dongjo.
  • Govern: policy-check turns dongjo.yml into the merge decision; gate-guard fails any agent change to the pipeline, the policy, the flow or existing attacks; the evidence pack is mapped to NIST SSDF.

GitLab features used: Duo Agent Platform custom flows (two, in the AI Catalog, started by an Assign trigger and run by their service accounts), merge request and scheduled pipelines, environments and resource groups for staging and production, GitLab SAST and Secret Detection, OIDC ID tokens for Google Cloud and Sigstore, protected and masked variables, scoped labels, issue and MR comments, the Releases API, GitLab Pages for the Dongjo Console, and Mermaid rendering for the Dongjo Map.

Google Cloud. notes-api runs on Cloud Run in europe-north1, with images in Artifact Registry. The deployment code is in the repository: infra/terraform/ (the platform), infra/setup.sh, ci/ (staging, canary, rollout and watch scripts) and .gitlab-ci.yml.

How we built it

  • Two halves: "CI computes, the LLM decides." A GitLab Duo Agent Platform custom flow (flows/dongjo.yaml, in the AI Catalog) does what needs judgment: planner, builder, red team and shipper agents. A deterministic GitLab CI pipeline does everything that can be computed: tests, the AC gate, SAST, secret detection, pip-audit, attacks, image build, SBOM, signing, VEX, canary judging, release and watch. Merge, VEX status and promote or rollback are computed from exit codes and the policy file dongjo.yml, never from model prose.
  • Batons. Agents and CI hand off state as small JSON "batons" in issue and merge request comments, which also feed the Dongjo Map.
  • Real attacks. Attack tests are pytest files that assert a defence holds, run over HTTP against the merge request's own Cloud Run revision tag and again against the production canary.
  • Google Cloud without keys. GitLab OIDC to Workload Identity Federation for deploys, separate service accounts for staging and production, the platform described in Terraform and planned read-only on every merge request. GitLab OIDC to Sigstore for keyless signatures.
  • A second flow for the benchmark. "Dongjo red team" runs only the planner and red team with identical prompts, so the benchmark measures the red team alone.
  • Dongjo Console on GitLab Pages shows every release with its attacks, gates, canary and evidence.
  • The service Dongjo works on is notes-api, a small FastAPI and SQLite app built during the hackathon.

Challenges we ran into

  • The flow could not merge. A run went green in 14 minutes and then GitLab refused the merge with 403 insufficient_scope: the flow token cannot merge, and neither can the CI job token. We moved merging into a CI job that runs only after policy-check passes and merges at the exact commit the gates checked.
  • Flows only start on a person's action, so the production watch cannot start Dongjo by itself. The watch opens the incident with a narrowly scoped team-member token that merge request pipelines never see.
  • False positives. In the first benchmark run the red team blocked four of six fine changes by assuming exact status codes the contract never names. One paragraph in the prompt, "what counts as a finding", brought that to zero in run 2, and cost two catches, which we report.
  • The harness had to fail closed. One attack could not run because httpx rejects a "Bearer " header; Dongjo stopped with an exact diagnosis instead of passing. We now run every new attack over real HTTP before committing it.
  • Three main pipelines computed the same version. Queued pipelines each picked v0.9.0, and two failed with 409 Release already exists. Versions now come from the commit history, and a test replays that morning.
  • Smaller ones: Cloud Run's front end reserves paths ending in "z", so /healthz always answered 404; scoped labels in one scope wipe each other out; and agent prompts and tool outputs have HTML comments stripped, so batons became fenced blocks.

Accomplishments that we're proud of

  • Zero-touch runs from issue to signed release in about 20 minutes, with a red team that attacks each change's own live revision before the merge.
  • A benchmark with a sealed answer key, run three times, where we publish the misses and the false positives as plainly as the catches.
  • OpenVEX that is earned: not_affected only when blocked attack transcripts or a test-backed statement say so.
  • A real rollback and a real drill in production, with timestamps and job links.
  • Every row of the nine-stage table in the README links to the job that proves it.

What we learned

  • A green scanner run says little about what a running service answers a stranger. Attacks against the live revision found flaws that every static gate passed.
  • Agents are best kept away from the decisions that matter. Letting the model write code and attacks while CI decides merge, VEX and rollout made the system both autonomous and auditable.
  • Measuring false positives matters as much as measuring catches. Our first red team was too eager, and one clear definition of a finding fixed most of it.
  • Honest numbers are more convincing than perfect ones.

What's next for Dongjo

  • Run merge request staging with production settings, so configuration-only leaks like the drill's are caught before merge.
  • More attack classes in the red team, such as rate limits and timing, behind the same "what counts as a finding" rule.
  • Packaging Dongjo as AI Catalog items and a CI component that any GitLab project can enable.
  • Running the sealed benchmark on more services than notes-api.

Built With

  • artifact-registry
  • cosign
  • cyclonedx
  • fastapi
  • gitlab
  • gitlab-ci
  • gitlab-duo-agent-platform
  • gitlab-pages
  • google-cloud-run
  • httpx
  • mermaid
  • openvex
  • pytest
  • python
  • semgrep
  • sigstore
  • sqlite
  • terraform
  • workload-identity-federation
Share this project:

Updates

Submission history