Scans
Run and manage infrastructure drift scans from the CLI.
Trigger a Scan
Start a new drift scan:
controlinfra scan run owner/repoOutput:
✓ Scan started: a1b2c3d4e5f6
Check status with: controlinfra scan status a1b2c3d4e5f6Wait for Completion
To wait for the scan to complete:
controlinfra scan run owner/repo --waitOutput:
◐ Scan status: planning
◐ Scan status: analyzing
✓ Scan completed successfully
2 drift(s) detected
View drifts with: controlinfra drifts list --scan a1b2c3d4e5f6Options
| Option | Description | Default |
|---|---|---|
--wait | Wait for scan to complete | - |
--timeout <seconds> | Timeout for --wait | 600 |
--runner <id> | Use specific runner | - |
--fail-on-drift | Exit with code 1 if any drift is detected | - |
--fail-on-severity <level> | Exit with code 1 if drift severity >= level (critical/high/medium/low) | - |
--fail-on-new-only | Only fail on new drifts, ignore recurring | - |
Use Specific Runner
controlinfra scan run owner/repo --runner my-runner-idCI/CD Drift Gate
Fail your pipeline when drift is detected:
# Fail if ANY drift is detected
controlinfra scan run owner/repo --wait --fail-on-drift
# Fail only on critical or high severity drifts
controlinfra scan run owner/repo --wait --fail-on-severity high
# Fail only on new drifts (ignore recurring drifts)
controlinfra scan run owner/repo --wait --fail-on-drift --fail-on-new-onlyWhen drifts are detected, the CLI shows a table with details and a link to the console:
✓ Scan completed successfully
Drifts Detected
────────────────────────────────────────────────────────────────────────────────
ID │ Resource │ Severity │ Action │ Status
d-a1b2c3 │ aws_security_group.main │ critical │ update │ new
d-d4e5f6 │ aws_instance.web │ medium │ update │ recurring
2 drift(s) found (1 critical, 1 medium)
View details: https://controlinfra.com/scans/abc123
Drift gate check FAILED - threshold exceededCheck Scan Status
Get the current status of a scan:
controlinfra scan status <scan-id>Output:
┌──────────────────────────────────────────────────────────┐
│ Scan Status │
├──────────────────────────────────────────────────────────┤
│ ID: a1b2c3d4e5f6 │
│ Repository: myorg/infrastructure │
│ Status: completed │
│ Started: 5 minutes ago │
│ Duration: 2m 34s │
│ Drifts: 2 │
└──────────────────────────────────────────────────────────┘List Scans
View recent scans:
controlinfra scan listOutput:
┌──────────┬─────────────────────────┬───────────┬────────┬──────────┬─────────────┐
│ ID │ Repository │ Status │ Drifts │ Duration │ Started │
├──────────┼─────────────────────────┼───────────┼────────┼──────────┼─────────────┤
│ a1b2c3d4 │ myorg/infrastructure │ completed │ 2 │ 2m 34s │ 5 min ago │
│ e5f6g7h8 │ myorg/terraform-modules │ running │ - │ - │ 1 min ago │
│ i9j0k1l2 │ myorg/infrastructure │ failed │ - │ 45s │ 1 hour ago │
└──────────┴─────────────────────────┴───────────┴────────┴──────────┴─────────────┘Filter Options
| Option | Description |
|---|---|
--repo <id> | Filter by repository |
--status <status> | Filter by status (running, completed, failed) |
--limit <n> | Number of scans to show (default: 20) |
# Filter by repository
controlinfra scan list --repo myorg/infrastructure
# Only completed scans
controlinfra scan list --status completed
# Last 5 scans
controlinfra scan list --limit 5View Scan Logs
Get detailed logs and timing information:
controlinfra scan logs <scan-id>Output:
Scan Logs
────────────────────────────────────────────────────────────
Timing:
Clone: 3s
Init: 12s
Plan: 45s
Analysis: 1m 34s
Total: 2m 34s
Plan Output:
────────────────────────────────────────────────────────────
Terraform will perform the following actions:
# aws_instance.web will be updated in-place
~ resource "aws_instance" "web" {
~ instance_type = "t2.micro" -> "t2.small"
}
...Wait for a Scan
Wait for an already-running scan to complete:
controlinfra scan wait <scan-id>Options
| Option | Description | Default |
|---|---|---|
--timeout <seconds> | Maximum wait time | 600 |
--fail-on-drift | Exit with code 1 if any drift is detected | - |
--fail-on-severity <level> | Exit with code 1 if drift severity >= level | - |
--fail-on-new-only | Only fail on new drifts, ignore recurring | - |
Timeout
Set a custom timeout (in seconds):
controlinfra scan wait <scan-id> --timeout 300Drift Gate with Wait
You can also use drift gate options with scan wait:
# Wait for scan and fail if critical drifts found
controlinfra scan wait <scan-id> --fail-on-severity criticalCancel a Scan
Stop a running scan:
controlinfra scan cancel <scan-id>Output:
✓ Scan cancelledCI/CD Integration
Use the drift gate options to automatically fail your pipeline when infrastructure drift is detected.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success - no drift or within threshold |
| 1 | Drift detected - threshold exceeded |
| 2 | Error - scan failed, timeout, or cancelled |
Environment Variables
Set drift gate defaults via environment variables:
| Variable | Description |
|---|---|
CONTROLINFRA_TOKEN | Authentication token |
CONTROLINFRA_FAIL_ON_DRIFT | Set to true to fail on any drift |
CONTROLINFRA_FAIL_ON_SEVERITY | Fail on drift >= severity (critical/high/medium/low) |
CONTROLINFRA_FAIL_ON_NEW_ONLY | Set to true to only fail on new drifts |
GitHub Actions Examples
Basic - Fail on any drift:
- name: Check for Infrastructure Drift
env:
CONTROLINFRA_TOKEN: ${{ secrets.CONTROLINFRA_TOKEN }}
run: controlinfra scan run ${{ github.repository }} --wait --fail-on-driftFail only on critical/high severity:
- name: Check for Critical Drift
env:
CONTROLINFRA_TOKEN: ${{ secrets.CONTROLINFRA_TOKEN }}
run: controlinfra scan run ${{ github.repository }} --wait --fail-on-severity highUsing environment variable defaults:
- name: Check for Drift
env:
CONTROLINFRA_TOKEN: ${{ secrets.CONTROLINFRA_TOKEN }}
CONTROLINFRA_FAIL_ON_SEVERITY: critical
run: controlinfra scan run ${{ github.repository }} --waitGet JSON output for custom processing:
- name: Run Controlinfra Scan
env:
CONTROLINFRA_TOKEN: ${{ secrets.CONTROLINFRA_TOKEN }}
run: |
controlinfra scan run ${{ github.repository }} --wait --json > scan-result.json
# Parse results
DRIFTS=$(jq '.summary.totalDrifts' scan-result.json)
CONSOLE_URL=$(jq -r '.consoleUrl' scan-result.json)
if [ "$DRIFTS" -gt 0 ]; then
echo "::warning::$DRIFTS drift(s) detected. View: $CONSOLE_URL"
fiGitLab CI Example
drift-check:
stage: test
script:
- controlinfra scan run $CI_PROJECT_PATH --wait --fail-on-severity high
variables:
CONTROLINFRA_TOKEN: $CONTROLINFRA_TOKEN
allow_failure: falseAzure DevOps Example
- task: Bash@3
displayName: 'Check Infrastructure Drift'
inputs:
targetType: 'inline'
script: |
controlinfra scan run $(Build.Repository.Name) --wait --fail-on-drift
env:
CONTROLINFRA_TOKEN: $(CONTROLINFRA_TOKEN)