Skip to main content

CI integration

This guide shows how to submit a ticketyboo scan from a GitHub Actions workflow, poll for completion, and fail the workflow when a blocking Gatekeep gate fires. The same pattern works in any CI system that can run shell scripts.

Prerequisites

How CI integration works

The scan API is asynchronous. The workflow:

  1. Posts the repository URL to POST /api/scan to start the scan.
  2. Receives a scan_id in the response.
  3. Polls GET /api/scan/{id} until status is complete.
  4. Reads the gatekeep.verdict field from the response.
  5. Exits non-zero if the verdict is failed.

GitHub Actions workflow

Add this workflow file to your repository at .github/workflows/ticketyboo.yml:

name: ticketyboo scan

on:
  push:
    branches: [main]
  pull_request:

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - name: Submit scan
        id: submit
        run: |
          RESPONSE=$(curl -s -X POST https://api.ticketyboo.dev/api/scan \
            -H "Content-Type: application/json" \
            -H "x-api-key: ${{ secrets.TICKETYBOO_API_KEY }}" \
            -d "{\"repo_url\": \"https://github.com/${{ github.repository }}\", \"deep\": false}")
          echo "scan_id=$(echo $RESPONSE | jq -r '.scan_id')" >> $GITHUB_OUTPUT

      - name: Wait for scan completion
        id: poll
        run: |
          SCAN_ID="${{ steps.submit.outputs.scan_id }}"
          for i in $(seq 1 30); do
            RESULT=$(curl -s https://api.ticketyboo.dev/api/scan/$SCAN_ID)
            STATUS=$(echo $RESULT | jq -r '.status')
            if [ "$STATUS" = "complete" ]; then
              echo "result=$RESULT" >> $GITHUB_OUTPUT
              break
            fi
            sleep 10
          done
          if [ "$STATUS" != "complete" ]; then
            echo "Scan did not complete in time"
            exit 1
          fi

      - name: Check Gatekeep verdict
        run: |
          VERDICT=$(echo '${{ steps.poll.outputs.result }}' | jq -r '.gatekeep.verdict // "not_evaluated"')
          echo "Gatekeep verdict: $VERDICT"
          if [ "$VERDICT" = "failed" ]; then
            echo "One or more blocking gates fired. Check the scan report."
            exit 1
          fi

Using a deep scan

To request a deep scan, change "deep": false to "deep": true in the submit step. Deep scans consume more credits and are subject to the 3-per-IP-per-7-day rolling rate limit. Consider limiting deep scans to pushes to main only:

on:
  push:
    branches: [main]   # deep scan on merge only

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - name: Submit deep scan
        id: submit
        run: |
          RESPONSE=$(curl -s -X POST https://api.ticketyboo.dev/api/scan \
            -H "Content-Type: application/json" \
            -H "x-api-key: ${{ secrets.TICKETYBOO_API_KEY }}" \
            -d "{\"repo_url\": \"https://github.com/${{ github.repository }}\", \"deep\": true}")
          echo "scan_id=$(echo $RESPONSE | jq -r '.scan_id')" >> $GITHUB_OUTPUT

Handling rate limits

If the scan submission returns HTTP 429, the IP has hit a rate limit. In GitHub Actions, the runner IP is shared across many workflows and may reach the limit quickly for deep scans. To avoid this:

Handling no contract (not_evaluated)

If the repository has no devcontract.json, the Gatekeep verdict is not_evaluated. The workflow above will not fail in this case. If you want to enforce that a contract must be present, change the check step:

      - name: Check Gatekeep verdict
        run: |
          VERDICT=$(echo '${{ steps.poll.outputs.result }}' | jq -r '.gatekeep.verdict // "not_evaluated"')
          echo "Gatekeep verdict: $VERDICT"
          if [ "$VERDICT" = "failed" ]; then
            echo "Blocking gates fired."
            exit 1
          fi
          if [ "$VERDICT" = "not_evaluated" ]; then
            echo "No devcontract.json found. Add one to enable Gatekeep."
            exit 1
          fi

Scan credits in CI

Each scan consumes one credit from the authenticated account. An API key authenticates the request and credits are deducted from the key owner's account. Monitor your credit balance from GET /api/account/me if running scans at high frequency.

Next steps