Skip to content

CI Recipes

Pengfei Hu edited this page May 31, 2026 · 2 revisions

CI Recipes

Patterns for running Agents Shipgate in CI. The default mode is advisory — the action never blocks a PR unless you ask it to.


GitHub Actions

Minimum: advisory PR comment

# .github/workflows/agents-shipgate.yml
name: Agents Shipgate
on: pull_request
permissions:
  contents: read
  pull-requests: write   # only needed for pr_comment
jobs:
  shipgate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0          # so verify can diff against the PR base
      - uses: ThreeMoonsLab/agents-shipgate@v0.10.0
        with:
          ci_mode: advisory
          diff_base: target        # enrich with the PR base/head diff
          pr_comment: 'true'

What you get on every PR:

  • A "Agents Shipgate" comment summarizing critical/high/medium counts and top three findings
  • A workflow artifact with report.{md,json,sarif} and the Release Evidence Packet packet.{md,json,html}
  • A markdown step summary in the Actions UI

The job exits 0 regardless of findings.

Strict on critical, advisory on the rest

- uses: ThreeMoonsLab/agents-shipgate@v0.10.0
  with:
    ci_mode: strict
    fail_on: critical
    pr_comment: 'true'

The job exits 20 (which the action surfaces as a job failure) only when at least one unsuppressed critical finding exists. Suppressed findings never fail CI.

Strict on critical and high, with baseline diff

For repos that already have known findings they're choosing not to fix yet, save a baseline once and fail only on new findings:

agents-shipgate baseline save -c shipgate.yaml \
  --out .agents-shipgate/baseline.json
git add .agents-shipgate/baseline.json && git commit -m "Baseline shipgate findings"
- uses: ThreeMoonsLab/agents-shipgate@v0.10.0
  with:
    ci_mode: strict
    fail_on: critical,high
    baseline: .agents-shipgate/baseline.json

See Baseline Workflow for the full pattern.

Multi-config workspace scan

If your monorepo has several shipgate.yaml files (one per agent), the action accepts a workspace root:

- uses: ThreeMoonsLab/agents-shipgate@v0.10.0
  with:
    config: '**/shipgate.yaml'
    ci_mode: advisory

Or invoke the CLI directly for richer control:

      - run: pipx install agents-shipgate==0.10.0
      - run: |
          agents-shipgate scan \
            --workspace . \
            --out agents-shipgate-reports \
            --ci-mode strict --fail-on critical

If one manifest has a parse error, the rest still scan; the highest exit code wins.

Pinning the version

For reproducible CI, pin both the action and the underlying CLI version:

- uses: ThreeMoonsLab/agents-shipgate@v0.10.0
  with:
    shipgate_version: '0.10.0'   # forces the action to install this exact PyPI version

When shipgate_version is empty, the action installs the CLI from the action source — convenient on @main, less reproducible.


GitLab CI

# .gitlab-ci.yml
shipgate:
  image: python:3.12-slim
  stage: review
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - pip install --quiet agents-shipgate==0.10.0
    - agents-shipgate scan -c shipgate.yaml --ci-mode advisory
  artifacts:
    when: always
    expire_in: 30 days
    paths:
      - agents-shipgate-reports/

For strict gates, switch to --ci-mode strict --fail-on critical,high and let the nonzero exit fail the job.


CircleCI

# .circleci/config.yml
version: 2.1
jobs:
  shipgate:
    docker:
      - image: cimg/python:3.12
    steps:
      - checkout
      - run: pip install --quiet agents-shipgate==0.10.0
      - run: agents-shipgate scan -c shipgate.yaml --ci-mode advisory
      - store_artifacts:
          path: agents-shipgate-reports
workflows:
  pr:
    jobs:
      - shipgate

Jenkins (declarative)

pipeline {
  agent { docker { image 'python:3.12-slim' } }
  stages {
    stage('Shipgate') {
      steps {
        sh 'pip install --quiet agents-shipgate==0.10.0'
        sh 'agents-shipgate scan -c shipgate.yaml --ci-mode advisory'
      }
      post {
        always {
          archiveArtifacts artifacts: 'agents-shipgate-reports/**', fingerprint: true
        }
      }
    }
  }
}

Rolling out strict mode

Going from "informational" to "blocking" without surprising the team:

  1. Land the workflow in advisory mode. Watch PR comments for a sprint or two. Tune risk_overrides and checks.ignore based on real false positives. Open issues for the rest.
  2. Save a baseline. agents-shipgate baseline save — captures everything currently active. Commit it.
  3. Switch to ci_mode: strict with the baseline applied. Now CI only fails on net-new findings. Existing findings stay in the report but don't block.
  4. Pick severity thresholds incrementally. Start with fail_on: critical. Move to [critical, high] after one or two rounds of cleanup.
  5. Sunset the baseline when the active list is small enough to fix. Delete .agents-shipgate/baseline.json and let strict mode see all findings directly.

This is the same pattern that's worked for code linters — the goal is to never surprise a contributor with an unrelated failure on their PR.


Reading the action outputs

The action exposes these outputs you can wire into downstream steps:

Output Example Notes
decision blocked release_decision.decision — the release gate (blocked/review_required/insufficient_evidence/passed). Prefer this.
merge_verdict blocked Verifier projection of the decision for the ongoing-PR flow
can_merge_without_human false True only when no human-review signal is present
critical_count 2 Unsuppressed only
high_count 13
medium_count 1
baseline_new_count 0 When a baseline is applied
ci_would_fail true Whether the configured fail policy would fail CI
report_json agents-shipgate-reports/report.json Path
report_markdown agents-shipgate-reports/report.md Path
report_sarif agents-shipgate-reports/report.sarif Path
verifier_json agents-shipgate-reports/verifier.json Path (verify flow)
status release_blockers_detected Legacy / baseline-blind — kept for v0.7 callers; prefer decision.
exit_code 20 Exact CLI exit code, even on advisory runs

Example: post a Slack alert only when criticals appeared:

      - id: scan
        uses: ThreeMoonsLab/agents-shipgate@v0.10.0
      - if: steps.scan.outputs.critical_count != '0'
        run: |
          curl -X POST -H 'Content-type: application/json' \
            -d "{\"text\":\"Shipgate criticals on ${{ github.event.pull_request.html_url }}\"}" \
            ${{ secrets.SLACK_WEBHOOK }}

Clone this wiki locally