Skip to content

Scans

Run and manage infrastructure drift scans from the CLI.

Trigger a Scan

Start a new drift scan:

bash
controlinfra scan run owner/repo

Output:

✓ Scan started: a1b2c3d4e5f6

Check status with: controlinfra scan status a1b2c3d4e5f6

Wait for Completion

To wait for the scan to complete:

bash
controlinfra scan run owner/repo --wait

Output:

◐ Scan status: planning
◐ Scan status: analyzing
✓ Scan completed successfully

2 drift(s) detected
View drifts with: controlinfra drifts list --scan a1b2c3d4e5f6

Options

OptionDescriptionDefault
--waitWait for scan to complete-
--timeout <seconds>Timeout for --wait600
--runner <id>Use specific runner-
--fail-on-driftExit 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-onlyOnly fail on new drifts, ignore recurring-

Use Specific Runner

bash
controlinfra scan run owner/repo --runner my-runner-id

CI/CD Drift Gate

Fail your pipeline when drift is detected:

bash
# 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-only

When 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 exceeded

Check Scan Status

Get the current status of a scan:

bash
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:

bash
controlinfra scan list

Output:

┌──────────┬─────────────────────────┬───────────┬────────┬──────────┬─────────────┐
│ 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

OptionDescription
--repo <id>Filter by repository
--status <status>Filter by status (running, completed, failed)
--limit <n>Number of scans to show (default: 20)
bash
# Filter by repository
controlinfra scan list --repo myorg/infrastructure

# Only completed scans
controlinfra scan list --status completed

# Last 5 scans
controlinfra scan list --limit 5

View Scan Logs

Get detailed logs and timing information:

bash
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:

bash
controlinfra scan wait <scan-id>

Options

OptionDescriptionDefault
--timeout <seconds>Maximum wait time600
--fail-on-driftExit with code 1 if any drift is detected-
--fail-on-severity <level>Exit with code 1 if drift severity >= level-
--fail-on-new-onlyOnly fail on new drifts, ignore recurring-

Timeout

Set a custom timeout (in seconds):

bash
controlinfra scan wait <scan-id> --timeout 300

Drift Gate with Wait

You can also use drift gate options with scan wait:

bash
# Wait for scan and fail if critical drifts found
controlinfra scan wait <scan-id> --fail-on-severity critical

Cancel a Scan

Stop a running scan:

bash
controlinfra scan cancel <scan-id>

Output:

✓ Scan cancelled

CI/CD Integration

Use the drift gate options to automatically fail your pipeline when infrastructure drift is detected.

Exit Codes

CodeMeaning
0Success - no drift or within threshold
1Drift detected - threshold exceeded
2Error - scan failed, timeout, or cancelled

Environment Variables

Set drift gate defaults via environment variables:

VariableDescription
CONTROLINFRA_TOKENAuthentication token
CONTROLINFRA_FAIL_ON_DRIFTSet to true to fail on any drift
CONTROLINFRA_FAIL_ON_SEVERITYFail on drift >= severity (critical/high/medium/low)
CONTROLINFRA_FAIL_ON_NEW_ONLYSet to true to only fail on new drifts

GitHub Actions Examples

Basic - Fail on any drift:

yaml
- name: Check for Infrastructure Drift
  env:
    CONTROLINFRA_TOKEN: ${{ secrets.CONTROLINFRA_TOKEN }}
  run: controlinfra scan run ${{ github.repository }} --wait --fail-on-drift

Fail only on critical/high severity:

yaml
- name: Check for Critical Drift
  env:
    CONTROLINFRA_TOKEN: ${{ secrets.CONTROLINFRA_TOKEN }}
  run: controlinfra scan run ${{ github.repository }} --wait --fail-on-severity high

Using environment variable defaults:

yaml
- name: Check for Drift
  env:
    CONTROLINFRA_TOKEN: ${{ secrets.CONTROLINFRA_TOKEN }}
    CONTROLINFRA_FAIL_ON_SEVERITY: critical
  run: controlinfra scan run ${{ github.repository }} --wait

Get JSON output for custom processing:

yaml
- 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"
    fi

GitLab CI Example

yaml
drift-check:
  stage: test
  script:
    - controlinfra scan run $CI_PROJECT_PATH --wait --fail-on-severity high
  variables:
    CONTROLINFRA_TOKEN: $CONTROLINFRA_TOKEN
  allow_failure: false

Azure DevOps Example

yaml
- 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)

Next Steps

AI-powered infrastructure drift detection