CI/CD automation
You can wire BestDefense into a CI/CD pipeline to scan on every release and fail the build when serious issues appear. This page shows the end-to-end pattern with the REST API; for authentication and tokens, start with API access & tokens.
Before you start
Section titled “Before you start”- A verified site to scan — see Managing sites.
- An API token stored as a secret in your CI/CD provider — see API access & tokens.
All examples use the base URL https://app.bestdefense.io and assume your token
is in BD_API_TOKEN.
The pattern
Section titled “The pattern”A security gate is four steps: trigger → poll → fetch → decide.
- Trigger a scan against your site.
- Poll the report until it completes.
- Fetch the findings (a risk summary by severity).
- Decide — pass or fail the build based on the counts.
Worked example
Section titled “Worked example”This script runs a quick Vortex scan, waits for it, and exits non-zero if there are any critical or high findings:
#!/usr/bin/env bashset -euo pipefail
BD="https://app.bestdefense.io"AUTH="Authorization: Bearer ${BD_API_TOKEN:?set BD_API_TOKEN}"SITE_HOST="example.com" # a verified site in your org
# 1. Find the site's UUID by hostnamesite_id=$(curl -fsS -H "$AUTH" "$BD/api/sites" \ | jq -r --arg h "$SITE_HOST" '.data.sites[] | select(.hostname == $h) | .id')
# 2. Trigger an Analog (quick) Vortex scan; capture the new report's UUIDreport_id=$(curl -fsS -X POST -H "$AUTH" -H "Content-Type: application/json" \ "$BD/api/report/create/for-target/$site_id" \ -d '{ "options": { "security": { "enabled": true, "options": { "vortexType": "analog", "testingType": "web", "scanIntensity": "quick" } } } }' | jq -r '.id')echo "Started report $report_id"
# 3. Poll progress until the scan completesuntil [ "$(curl -fsS -H "$AUTH" "$BD/api/report/$report_id/progress" \ | jq -r '.data.isCompleted')" = "true" ]; do echo " scanning…"; sleep 30done
# 4. Resolve the security report's numeric id from the overviewsecr_id=$(curl -fsS -H "$AUTH" "$BD/api/report/$report_id/overview" \ | jq -r '.data.security.id')
# 5. Pull the risk summary by severityread -r crit high < <(curl -fsS -H "$AUTH" \ "$BD/api/report/vortex/$secr_id/alerts" \ | jq -r '.data.riskSummary | "\(.critical) \(.high)"')echo "Critical: $crit High: $high"
# 6. Fail the build on any critical or high findingif [ "$crit" -gt 0 ] || [ "$high" -gt 0 ]; then echo "::error::Security gate failed — $crit critical, $high high findings" exit 1fiecho "Security gate passed"In GitHub Actions
Section titled “In GitHub Actions”Store the token as a repository secret (BD_API_TOKEN) and run the script as a
step:
jobs: security-gate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: BestDefense scan gate env: BD_API_TOKEN: ${{ secrets.BD_API_TOKEN }} run: ./scripts/bestdefense-gate.shThe same approach works in GitLab CI/CD (a masked variable + a script job) or any
runner that can execute curl and jq.
Other automation flows
Section titled “Other automation flows”Scheduled scans
Section titled “Scheduled scans”Instead of triggering on every pipeline run, you can create a recurring schedule once:
POST /api/report/create/for-target/{siteId}/scheduledThe body takes top-level name, frequency, frequencyInterval, a
reportConfig object (the same security/scaling shape as create), and optional
isEnabled and startDate. Scheduling requires the appropriate plan.
Triggering AI remediation
Section titled “Triggering AI remediation”Once you have a finding’s alert ID (from the alerts endpoint), you can open a fix pull request and poll its status:
POST /api/ai/remediation { "securityAlertId": "<alert-uuid>" }GET /api/ai/remediation/{securityAlertId}/statusGET /api/ai/remediation/{securityAlertId}/pull-requestsCreating a remediation returns 202 Accepted and runs asynchronously. See
AI remediation for the bigger picture.
Network scans
Section titled “Network scans”POST /api/network-scans { "tool": "nmap", "targets": ["10.0.0.0/24"] }GET /api/network-scans (list, paginated)GET /api/network-scans/{scanId} (status + detail)GET /api/network-scans/{scanId}/hosts (Nmap scans)GET /api/network-scans/{scanId}/vulnerabilities (OpenVAS scans)POST /api/network-scans/{scanId}/canceltool is nmap (host discovery) or openvas (vulnerabilities); targets are
IPs or CIDR ranges. You can also pass a saved configurationId instead of
tool/targets. Reading hosts or vulnerabilities before the scan completes
returns 409 Conflict.
Endpoint reference
Section titled “Endpoint reference”The interactive spec at /api/docs is authoritative and always current. The
tables below summarize the endpoints most useful for automation.
| Method & path | Purpose |
|---|---|
GET /api/sites | List your sites (with each site’s UUID and stats). |
GET /api/sites/{siteId}/routes | List a site’s configured routes (and their UUIDs). |
Reports — run and track
Section titled “Reports — run and track”| Method & path | Purpose |
|---|---|
POST /api/report/create/for-target/{targetId} | Create a report (run a scan/test). |
POST /api/report/create/for-target/{targetId}/scheduled | Create a recurring schedule. |
GET /api/report/{reportId}/progress | Overall progress of a report. |
GET /api/report/{reportId}/overview | Summary + the per-product sub-report IDs. |
GET /api/report/security/{id}/progress | Detailed Vortex scan progress. |
Vortex results
Section titled “Vortex results”| Method & path | Purpose |
|---|---|
GET /api/report/vortex/{vortexReportId}/alerts | Findings + risk summary (paginated, filterable by risk, confidence, search). |
GET /api/report/vortex/{vortexReportId}/risk-levels | Severity breakdown. |
GET /api/report/vortex/{vortexReportId}/cwe-counts | Findings grouped by CWE. |
GET /api/report/vortex/{vortexReportId}/dns-scan | DNS scan results. |
GET /api/report/vortex/{vortexReportId}/whois-scan-results | WHOIS results. |
Maelstrom results
Section titled “Maelstrom results”| Method & path | Purpose |
|---|---|
GET /api/report/maelstrom/{scalingReportId}/error-rates | Error-rate series. |
GET /api/report/maelstrom/{scalingReportId}/histogram | Latency histogram. |
GET /api/report/maelstrom/{scalingReportId}/rps | Requests per second. |
GET /api/report/maelstrom/{scalingReportId}/response-codes-by-virtual-users | Response codes vs. load. |
AI remediation
Section titled “AI remediation”| Method & path | Purpose |
|---|---|
POST /api/ai/remediation | Start a fix for an alert. |
GET /api/ai/remediation/{securityAlertId}/status | Remediation status. |
GET /api/ai/remediation/{securityAlertId}/pull-requests | Pull requests for the alert. |
Network scans
Section titled “Network scans”| Method & path | Purpose |
|---|---|
POST /api/network-scans | Start a network scan. |
GET /api/network-scans | List network scans. |
GET /api/network-scans/{scanId} | Get one scan’s status/detail. |
GET /api/network-scans/{scanId}/hosts | Discovered hosts (Nmap). |
GET /api/network-scans/{scanId}/vulnerabilities | Findings (OpenVAS). |
POST /api/network-scans/{scanId}/cancel | Cancel a running scan. |
Agent distribution
Section titled “Agent distribution”| Method & path | Purpose |
|---|---|
GET /api/network-scans/agent/manifest | Agent package metadata + a download URL (rate-limited). |
GET /api/network-scans/agent/download | Redirect to the agent download (rate-limited). |
The agent endpoints additionally require a token with the agent:download
scope, which you select when creating the token.