Inspiration

Every team ships code fast, but few govern what actually gets deployed. Security findings, bloated binaries, failing tests, and staging errors slip through because gates are manual, inconsistent, or afterthoughts. AI agents add speed—but also risk if they can merge, tag, or deploy without oversight. We built AeroPipe to answer a simple question: what if release governance was code, and AI was read-only by design?

What it does

AeroPipe is a focused Go HTTP service with a release policy engine that turns real pipeline artifacts (test results, SAST reports, Secret Detection reports, binary size, staging error rate) into READY/BLOCKED release decisions. It integrates with GitLab Duo Agent Platform through a read-only MCP server (4 tools) and a custom Duo flow with a human approval gate. All 9 DevSecOps lifecycle stages are covered, from plan through govern.

Core capabilities:

  • Binary budget governance: The binary is measured inside the shipped container image (docker create + docker cp), not a side build. If it exceeds the 6 MiB budget, promotion is blocked.
  • Release policy engine: Evaluates all pipeline artifacts and emits a READY/BLOCKED decision with detailed blockers. High/critical SAST findings, any secret, failing tests, over-budget binaries, error-rate breaches, and missing rollback/changelog evidence all block the release.
  • Read-only MCP server (cmd/aeropipe-mcp): Serves get_binary_budget, get_release_readiness, get_release_evidence, and suggest_remediation to Agentic Chat and the Duo CLI over stdio. Registered in .gitlab/duo/mcp.json. Requires the group setting External MCP tools.
  • Custom Duo flow (binary_governor.yaml): An evidence_agent reads binary_budget_gate artifacts via built-in GitLab API tools, posts report.md on the linked issue/MR, and pauses at a human release_gate approval. The flow does not call the MCP server—it uses GitLab's native agent toolset.
  • Assisted autonomy: suggest_remediation gives agents human-readable fix hints for every blocker, but humans apply the fixes. Autonomy level: Supervised. Agents execute workflows; humans approve production. The manual deploy_production job is the only production gate.

AeroPipe is a focused Go HTTP service and a nine-stage GitLab release lifecycle:

plan -> create -> verify -> package -> secure -> release -> configure -> monitor -> govern

The pipeline:

  • Validates a release plan with a binary budget, test minimum, rollback plan, and changelog control.
  • Builds the container image and measures the binary inside the image that actually ships.
  • Runs unit tests and exports test-results.json.
  • Runs Semgrep SAST and GitLab Secret Detection.
  • Recomputes the release decision from the real artifacts with a Go policy engine.
  • Deploys to AWS App Runner staging with OIDC, not long-lived AWS keys.
  • Checks staging health and error rate.
  • Writes a governance audit.
  • Leaves deploy_production as a manual human job.

The live service exposes /health, /api/status, /api/metrics, and /api/report. /api/status measures the running executable and reports the current commit, binary size, budget, headroom, and budget state. That makes the live deployment self-describing: the numbers on the dashboard come from the artifact that is running.

GitLab Duo runs a custom flow with a pipeline-passed trigger. The flow reads the binary_budget_gate artifacts (report.md and metrics.json), compares the current size with the previous successful pipeline, and posts the report as a merge-request note. It then pauses at a human approval gate. The flow has no merge, tag, approve, or deploy tools. Its only declared write tool is note creation.

The demo is a real red-to-green regression:

  • The red commit added a Markdown renderer (goldmark) for the release report. The shipped binary grew to 7,340,216 bytes, over the 6,291,456-byte budget by 1,048,760 bytes.
  • binary_budget_gate failed. Downstream release stages were skipped.
  • The green commit replaced the renderer with a fixed stdlib HTML template. The binary returned to 5,787,832 bytes, leaving 503,624 bytes of headroom.
  • The green pipeline passed and the Duo flow posted the evidence note. After merge, the main pipeline deployed staging; production stayed manual.

One dependency consumed 1,552,384 bytes — about three times the remaining headroom — and the gate caught it before staging.

How we built it

AeroPipe was built specifically for the GitLab Transcend Hackathon (Path A: Start Fresh)—new work, not a fork. Tech stack: Go 1.24 (stdlib-only, zero external dependencies), ~6.5 MB stripped binary, distroless scratch container, multi-stage Docker build (golang:1.24-alpine → scratch), GitLab OIDC → AWS STS (no long-lived keys), AWS App Runner deployment. Build pipeline (10 stages):

  1. plan — validate_release_plan validates the manifest and emits warnings for loose controls
  2. create — compile_application builds the Go binary
  3. verify — unit_tests runs go vet + go test -json
  4. package — package_container builds the image; binary_budget_gate measures the binary inside the image and blocks if over budget
  5. test — SAST + Secret Detection scanner templates
  6. secure — enforce_release_policy evaluates scanner reports and all evidence
  7. release — write_release_record + deploy_staging to App Runner
  8. configure — prepare_staging_configuration emits staging config
  9. monitor — check_service_health reads /health and /api/metrics
    1. govern — governance_audit emits final decision; deploy_production is manual

GitLab Duo integration:

  • MCP server registered in .gitlab/duo/mcp.json, serving Agentic Chat and Duo CLI
  • Custom flow created from .gitlab/duo/flows/binary_governor.yaml with Pipeline Passed trigger
  • Read-only AI constraint enforced: MCP tools are GET-only; flow cannot merge, tag, approve, or deploy Challenges we ran into
  • MCP server vs. custom flow separation. Initially we implied the Duo flow used the MCP server, but the flow uses built-in GitLab agent tools while the MCP server serves Agentic Chat and Duo CLI separately. We rewired the README and CONFIG.md to clarify this distinction and added the External MCP tools group setting prerequisite.
  • Binary budget measured inside the image. Measuring a side build is meaningless—we needed the binary that actually ships. We added docker create + docker cp to package_container so binary_budget_gate evaluates the real container artifact.
  • No Google Cloud bonus. We removed ~120 lines of untested GCP Cloud Run jobs from .gitlab-ci.yml because no billing account was available. The submission deploys to AWS App Runner only and does not claim the 0.2 bonus point.
  • CI/CD variables committed in public repo. AWS account IDs and role ARNs are in .gitlab-ci.yml. They're not secrets, but we verified the IAM trust policy pins the OIDC token's sub claim to this project on main, not just the aud: https://gitlab.com audience.
  • Red-to-green pipeline history. Judges score visible pipeline history. We had to open an over-budget MR (red run), fix it, and re-run (green) to prove the budget gate actually blocks—and then play deploy_production so a production environment exists in the history.

Accomplishments that we're proud of

  • All 9 DevSecOps stages covered with per-stage evidence artifacts (plan.json, test-results.json, metrics.json, security-evidence.json, release-record.json, staging-config.json, observability.json, governance-audit.json)
  • Read-only AI by design — the MCP server and Duo flow can recommend but never modify project state
  • Binary budget as a hard gate — measured inside the shipped image, blocking promotion on regression
  • Supervised autonomy — agents run multi-step workflows and clear automated gates, but production deployment requires human action
  • Stdout-only Go — zero external dependencies, ~6.5 MB stripped binary, cold-start friendly
  • Red-to-green demo path — pipeline history shows both a blocked over-budget run and a passing run, proving the gate works

What we learned

  • GitLab Duo's MCP server and custom flows are complementary but separate: MCP serves Agentic Chat/CLI; flows orchestrate with built-in GitLab tools. Don't conflate them.
  • Measuring binary size outside the shipped image is governance theater—you must measure what actually deploys.
  • Supervised autonomy (approve the outcome, not every step) is the right balance for release governance: agents handle the workflow, humans own the production decision.
  • Go's stdlib is sufficient for a production-grade HTTP service with embedded assets, atomic metrics, graceful shutdown, and JSON policy evaluation—no web framework needed.
  • Pipeline history visibility matters as much as the code itself: a passing-only run doesn't demonstrate that gates work.

What's next for AeroPipe

  • Pull-request-level budget gates so every MR sees binary impact before merge
  • SAST/Secret Detection exception tracking in the policy engine (documented false positives)
  • Slack/email notifications for blocked releases and production promotions
  • Multi-service support so the policy engine can govern multiple binaries in one repository
  • Ecosystem expansion—the same pattern applies to any language: measure the shipped artifact, gate on evidence, keep AI read-only

Built With

  • alpine-linux
  • amazon-ecr
  • amazon-web-services
  • aws-app-runner
  • aws-sts
  • ci/cd
  • devsecops
  • docker
  • gitlab
  • gitlab-duo
  • gitlab-oidc
  • go
  • go-standard-library-only
  • json-rpc-2.0
  • model-context-protocol-(mcp)
Share this project:

Updates

Submission history