Azure DevOps Container Scan
The QualysContainerScan@1 task scans Docker/OCI container images for vulnerabilities, secrets, and malware. It supports local images, registry images, and integrates with Azure DevOps Advanced Security for SARIF publishing.
Task Name: QualysContainerScan@1
Task Inputs
Service Connection
| Input |
Required |
Default |
Description |
qualysConnection |
Yes |
- |
Qualys API service connection name |
Scan Target
| Input |
Required |
Default |
Description |
imageId |
Yes |
- |
Container image to scan (name:tag or digest) |
imageTar |
No |
- |
Path to tar archive of the image |
platform |
No |
linux/amd64 |
Target platform for multi-arch images |
Scan Options
| Input |
Required |
Default |
Description |
scanSecrets |
No |
false |
Enable secrets detection in container layers |
scanMalware |
No |
false |
Enable malware detection |
offlineMode |
No |
false |
Scan without uploading to Qualys platform |
Threshold Configuration
| Input |
Required |
Default |
Description |
maxCritical |
No |
-1 |
Maximum critical vulnerabilities allowed (-1 = unlimited) |
maxHigh |
No |
-1 |
Maximum high vulnerabilities allowed (-1 = unlimited) |
maxMedium |
No |
-1 |
Maximum medium vulnerabilities allowed (-1 = unlimited) |
maxLow |
No |
-1 |
Maximum low vulnerabilities allowed (-1 = unlimited) |
Policy Configuration
| Input |
Required |
Default |
Description |
usePolicyEvaluation |
No |
false |
Enable Qualys cloud policy evaluation |
failOnAudit |
No |
false |
Fail pipeline when policy result is AUDIT |
Output Options
| Input |
Required |
Default |
Description |
publishResults |
No |
false |
Publish SARIF to Azure DevOps Advanced Security |
Work Item Creation
| Input |
Required |
Default |
Description |
createWorkItems |
No |
false |
Create Azure Boards work items for vulnerabilities |
workItemSeverities |
No |
4,5 |
Severity levels to create work items for (comma-separated) |
workItemType |
No |
Bug |
Work item type to create |
workItemAreaPath |
No |
- |
Area path for created work items |
workItemIterationPath |
No |
- |
Iteration path for created work items |
Complete Example
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
displayName: 'Build Container Image'
inputs:
command: build
Dockerfile: Dockerfile
tags: $(Build.BuildId)
- task: QualysContainerScan@1
displayName: 'Qualys Container Scan'
inputs:
qualysConnection: 'QualysConnection'
imageId: 'myapp:$(Build.BuildId)'
platform: 'linux/amd64'
scanSecrets: true
scanMalware: true
maxCritical: 0
maxHigh: 5
usePolicyEvaluation: false
publishResults: true
createWorkItems: true
workItemSeverities: '4,5'
workItemAreaPath: 'MyProject\Security'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- script: |
echo "Vulnerabilities: $(qualysContainerScan.vulnerabilityCount)"
echo "Critical: $(qualysContainerScan.criticalCount)"
echo "Scan passed: $(qualysContainerScan.scanPassed)"
displayName: 'Display Scan Results'
Scanning Remote Images
To scan images from private registries, authenticate before running the scan:
steps:
- task: Docker@2
displayName: 'Login to ACR'
inputs:
command: login
containerRegistry: 'myAcrConnection'
- task: QualysContainerScan@1
displayName: 'Scan ACR Image'
inputs:
qualysConnection: 'QualysConnection'
imageId: 'myacr.azurecr.io/myapp:$(Build.BuildId)'
publishResults: true
Scanning Tar Archives
steps:
- script: |
docker save myapp:$(Build.BuildId) -o $(Build.ArtifactStagingDirectory)/image.tar
displayName: 'Export Image'
- task: QualysContainerScan@1
displayName: 'Scan Image Tar'
inputs:
qualysConnection: 'QualysConnection'
imageTar: '$(Build.ArtifactStagingDirectory)/image.tar'
publishResults: true
Policy-Based Scanning
steps:
- task: QualysContainerScan@1
displayName: 'Scan with Policy'
inputs:
qualysConnection: 'QualysConnection'
imageId: 'myapp:$(Build.BuildId)'
usePolicyEvaluation: true
failOnAudit: true
Output Variables
Access scan results in subsequent tasks using these output variables:
| Variable |
Description |
$(taskName.vulnerabilityCount) |
Total number of vulnerabilities found |
$(taskName.criticalCount) |
Number of critical vulnerabilities |
$(taskName.highCount) |
Number of high vulnerabilities |
$(taskName.mediumCount) |
Number of medium vulnerabilities |
$(taskName.lowCount) |
Number of low vulnerabilities |
$(taskName.secretsCount) |
Number of secrets detected |
$(taskName.malwareCount) |
Number of malware detections |
$(taskName.policyResult) |
Policy result: ALLOW, DENY, AUDIT, or NONE |
$(taskName.scanPassed) |
true/false based on thresholds or policy |
$(taskName.sarifPath) |
Path to SARIF report file |
$(taskName.jsonPath) |
Path to JSON report file |
$(taskName.workItemsCreated) |
Number of work items created |
Using Output Variables
steps:
- task: QualysContainerScan@1
name: containerScan
displayName: 'Scan Container'
inputs:
qualysConnection: 'QualysConnection'
imageId: 'myapp:$(Build.BuildId)'
- script: |
echo "Total vulnerabilities: $(containerScan.vulnerabilityCount)"
echo "Critical: $(containerScan.criticalCount)"
echo "High: $(containerScan.highCount)"
echo "Policy result: $(containerScan.policyResult)"
echo "Scan passed: $(containerScan.scanPassed)"
displayName: 'Show Results'
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: '$(containerScan.sarifPath)'
artifactName: 'security-reports'
displayName: 'Publish SARIF Report'
Work Item Creation
To create Azure Boards work items, enable OAuth token access:
Option 1: Pipeline Setting
Enable "Allow scripts to access OAuth token" in pipeline settings.
Option 2: Environment Variable
- task: QualysContainerScan@1
displayName: 'Scan and Create Work Items'
inputs:
qualysConnection: 'QualysConnection'
imageId: 'myapp:$(Build.BuildId)'
createWorkItems: true
workItemSeverities: '4,5'
workItemType: 'Bug'
workItemAreaPath: 'MyProject\Security'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
Multi-Stage Pipeline
trigger:
- main
stages:
- stage: Build
jobs:
- job: BuildImage
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
inputs:
command: build
tags: $(Build.BuildId)
- task: Docker@2
inputs:
command: push
containerRegistry: 'myAcrConnection'
- stage: Security
dependsOn: Build
jobs:
- job: ContainerScan
pool:
vmImage: 'ubuntu-latest'
steps:
- task: QualysContainerScan@1
inputs:
qualysConnection: 'QualysConnection'
imageId: 'myacr.azurecr.io/myapp:$(Build.BuildId)'
maxCritical: 0
publishResults: true
- stage: Deploy
dependsOn: Security
condition: succeeded()
jobs:
- deployment: DeployToProduction
environment: 'production'