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
- A ticketyboo account with an API key (begins with
tbo-) - The API key stored as a GitHub Actions secret named
TICKETYBOO_API_KEY - A
devcontract.jsonat the repository root (see Your first contract) - The repository is public (ticketyboo scans public repositories only)
How CI integration works
The scan API is asynchronous. The workflow:
- Posts the repository URL to
POST /api/scanto start the scan. - Receives a
scan_idin the response. - Polls
GET /api/scan/{id}until status iscomplete. - Reads the
gatekeep.verdictfield from the response. - 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:
- Run deep scans only on pushes to
main, not on every pull request. - Check quota before submitting using
GET /api/scan/deep-quotaand skip the scan step gracefully if quota is exhausted. - Use a paid plan to take advantage of account-based credit tracking.
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.