Azure DevOps Pipelines¶
The examples assume the repository carries ci/agentsmith.yml with an agent named ci-scan, as described on the CI/CD overview.
Security scan (code analysis)¶
Run the security-scan pipeline for static patterns, git history scanning, dependency auditing and the security master's review of the source. The Markdown report becomes a tab on the run page, and the whole output directory is published as an artifact.
# azure-pipelines.yml
trigger:
branches:
include: [main]
pool:
vmImage: ubuntu-latest
steps:
- checkout: self
fetchDepth: 500 # history for the git history scan
- task: Bash@3
displayName: Download Agent Smith
inputs:
targetType: inline
script: |
curl -fsSL -o $(Agent.TempDirectory)/agent-smith \
https://github.com/holgerleichsenring/agent-smith/releases/latest/download/agent-smith-linux-x64
chmod +x $(Agent.TempDirectory)/agent-smith
- task: Bash@3
displayName: Run security scan
env:
ANTHROPIC_API_KEY: $(ANTHROPIC_API_KEY)
inputs:
targetType: inline
script: |
$(Agent.TempDirectory)/agent-smith security-scan \
--config ci/agentsmith.yml \
--agent ci-scan \
--source-path $(Build.SourcesDirectory) \
--output console,sarif,markdown \
--output-dir $(Build.ArtifactStagingDirectory)/security
- task: Bash@3
displayName: Publish summary tab
condition: always()
inputs:
targetType: inline
script: |
REPORT=$(Build.ArtifactStagingDirectory)/security/findings.md
if [ -f "$REPORT" ]; then
echo "##vso[task.uploadsummary]$REPORT"
fi
- task: PublishBuildArtifacts@1
displayName: Publish security report
condition: always()
inputs:
pathToPublish: $(Build.ArtifactStagingDirectory)/security
artifactName: security-scan-report
Summary tab
The ##vso[task.uploadsummary] command attaches a Markdown file as a tab on the pipeline run page. Team members see the findings without digging into logs.
Security scan vs API scan
security-scan analyzes source code. Use api-scan for runtime testing of a deployed API with Nuclei, Spectral and ZAP.
API scan¶
api-scan probes a running API, so it needs the OpenAPI description (--swagger, a path or URL) and the base URL (--target). Point it at a test or staging deployment.
- task: Bash@3
displayName: Run API security scan
env:
ANTHROPIC_API_KEY: $(ANTHROPIC_API_KEY)
inputs:
targetType: inline
script: |
$(Agent.TempDirectory)/agent-smith api-scan \
--config ci/agentsmith.yml \
--agent ci-scan \
--swagger https://api.staging.example.com/swagger/v1/swagger.json \
--target https://api.staging.example.com \
--output console,sarif,markdown \
--output-dir $(Build.ArtifactStagingDirectory)/api-security
Add --source-path $(Build.SourcesDirectory) when the API's source is checked out, so the master can anchor a finding to a file and line. The Microsoft-hosted ubuntu-latest image has Docker, so the scanner tools run in containers. On a self-hosted agent without Docker they run as local processes and must be on PATH, see Tool configuration.
Docker variant¶
For agents where you would rather run the CLI image than download the binary:
- task: Bash@3
displayName: Run Agent Smith (Docker)
env:
ANTHROPIC_API_KEY: $(ANTHROPIC_API_KEY)
inputs:
targetType: inline
script: |
docker run --rm \
-e ANTHROPIC_API_KEY \
-v $(Build.SourcesDirectory):/repo \
-v $(Build.ArtifactStagingDirectory)/security:/output \
holgerleichsenring/agent-smith-cli:latest \
security-scan --config /repo/ci/agentsmith.yml --agent ci-scan \
--source-path /repo --output console,sarif,markdown --output-dir /output
Mount /var/run/docker.sock as well when you run api-scan this way, so the scanner tools can start their containers.
Security gate¶
Fail the pipeline when Critical or High findings are present. They carry the SARIF level error:
- task: Bash@3
displayName: Check findings
inputs:
targetType: inline
script: |
SARIF=$(Build.ArtifactStagingDirectory)/security/findings.sarif
if [ -f "$SARIF" ]; then
CRITICAL=$(jq '[.runs[].results[] | select(.level == "error")] | length' "$SARIF")
if [ "$CRITICAL" -gt 0 ]; then
echo "##vso[task.logissue type=error]Found $CRITICAL critical or high security findings"
exit 1
fi
fi
Variables setup¶
Add these as pipeline variables and mark them secret:
| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY |
Yes | Key for the claude agent; use your provider's variable for another agent type |