CI: GitHub Actions & scanning in pipelines

Wire Cybros into CI to scan on every PR and block deploys when policy is violated. This page shows three recipes:

  1. Deployment gate — fail a job on blocking findings.
  2. Scan on PR with gh cybros.
  3. Generic "CLI in CI" — the cybros CLI in any runner.

Store your org API key as the CYBROS_API_KEY repository secret first (see Authentication). Mint a least-privilege key with cybros keys create ... --role member.


1. Deployment gate

Cybros exposes a deployment-gate endpoint that evaluates a commit against your policy and returns an approved boolean. Use it as a required check.

A ready-to-adapt snippet lives in the repo at cybros-api/docs/github-actions.yml. The core job:

name: cybros-security-gate
on:
  push:
    branches: [main]
  pull_request:

jobs:
  deployment-gate:
    runs-on: ubuntu-latest
    steps:
      - name: Cybros deployment gate
        env:
          CYBROS_API_KEY: ${{ secrets.CYBROS_API_KEY }}
          CYBROS_API_URL: ${{ vars.CYBROS_API_URL || 'https://backend.cybros.hacktigerlabs.com' }}
        run: |
          set -euo pipefail
          REPO="${GITHUB_REPOSITORY}"
          SHA="${GITHUB_SHA}"

          # The scan may still be running just after a push — poll the gate.
          for i in $(seq 1 30); do
            RESP="$(curl -sS \
              -H "Authorization: Bearer ${CYBROS_API_KEY}" \
              "${CYBROS_API_URL}/api/v1/deployment-gate?repo=${REPO}&sha=${SHA}")"

            APPROVED="$(echo "$RESP" | jq -r '.approved')"
            STATUS="$(echo "$RESP" | jq -r '.status')"

            if [ "$APPROVED" = "true" ]; then
              echo "Cybros security gate passed."; exit 0
            fi
            if [ "$STATUS" = "no_completed_scan" ]; then
              echo "Scan not complete yet; retrying ($i/30)..."; sleep 10; continue
            fi

            echo "Cybros security gate FAILED — blocking findings present."
            echo "$RESP" | jq '{security_score, blocking_findings, report_url}'
            exit 1
          done

          echo "Timed out waiting for a completed Cybros scan."; exit 1

Make deployment-gate a required status check on the branch so PRs can't merge (and deploys can't proceed) until it passes.

CYBROS_API_URL here is the host (no /api/v1 suffix) because the script appends the path. The CLI/SDK env var, by contrast, expects the full .../api/v1 base — see Authentication.


2. Scan on PR with gh cybros

If you prefer to drive the scan from CI (rather than relying on webhook-triggered scans), use the gh cybros extension. gh and jq are preinstalled on GitHub-hosted runners.

name: cybros-scan
on: pull_request

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install gh-cybros
        run: gh extension install ayushtenguria/gh-cybros
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Scan and fail on critical/high
        env:
          CYBROS_API_KEY: ${{ secrets.CYBROS_API_KEY }}
        run: |
          set -euo pipefail
          RESULT="$(gh cybros scan --json)"
          echo "$RESULT" | jq '.findings_summary'
          BLOCKING="$(echo "$RESULT" | jq '(.findings_summary.critical // 0) + (.findings_summary.high // 0)')"
          if [ "$BLOCKING" -gt 0 ]; then
            echo "::error::$BLOCKING critical/high findings — failing the build."
            exit 1
          fi

3. Generic "CLI in CI"

The cybros CLI works in any runner. It resolves the key from CYBROS_API_KEY, exits 2 when unauthenticated, and supports --json for scripting.

name: cybros-cli
on: pull_request

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0          # so the CLI can read the git ref/remote

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - run: pip install cybros

      - name: Scan and gate on policy
        env:
          CYBROS_API_KEY: ${{ secrets.CYBROS_API_KEY }}
        run: |
          set -euo pipefail
          # Trigger + wait; the CLI streams progress and exits non-zero on error.
          SCAN_ID="$(cybros --json scan | jq -r '.id')"
          # Fail the build if any critical findings remain:
          COUNT="$(cybros --json findings --scan "$SCAN_ID" --severity critical | jq 'length')"
          echo "Critical findings: $COUNT"
          test "$COUNT" -eq 0

The same pattern works in GitLab CI, CircleCI, Jenkins, or any container — set CYBROS_API_KEY in the environment and call the CLI.

Tips

  • Full history. Use fetch-depth: 0 on checkout so the CLI/extension can read the git ref and remote.
  • Least privilege. Use a member-role key for CI.
  • Machine-readable everywhere. --json on every read command → pipe into jq.
  • Exit codes. 0 success, 1 error, 2 unauthenticated — see the CLI reference.

See also