-
Notifications
You must be signed in to change notification settings - Fork 0
azure devops
This guide covers all aspects of integrating Purplemet security analyses into Azure DevOps pipelines.
- Prerequisites
- Quick Start
- Installation Methods
- Parameters
- Security Gates
- Output Variables
- Complete Pipeline Examples
- Results and Exit Codes
- Advanced Usage
- FAQ / Common Errors
Create a token at cloud.purplemet.com.
The token must have the Operator role. The Administrator role is discouraged for CI/CD usage — the CLI will display a warning if an Administrator token is detected.
Install the Purplemet extension from the Azure DevOps Marketplace.
For Azure DevOps Server (on-premises), the extension must be uploaded manually by an administrator.
Add PURPLEMET_API_TOKEN as a secret pipeline variable:
Option A — Pipeline variable:
- Edit your pipeline
- Click Variables
- Click New variable
- Name:
PURPLEMET_API_TOKEN - Value: your API token
- Check Keep this value secret
Option B — Variable group (recommended for multi-pipeline use):
- Go to Pipelines → Library
- Create a new Variable group
- Add
PURPLEMET_API_TOKENwith the lock icon (secret) - Link the variable group to your pipelines
Azure-hosted agents can reach the Purplemet API by default. For self-hosted agents, ensure outbound HTTPS access to api.purplemet.com.
Add to your azure-pipelines.yml:
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
failSeverity: 'high'Uses the official Purplemet task from the Azure DevOps Marketplace.
steps:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
failSeverity: 'high'Uses the official Docker image directly. No extension needed.
steps:
- script: |
docker run --rm \
-e PURPLEMET_API_TOKEN=$(PURPLEMET_API_TOKEN) \
ppmsupport/purplemet-cli analyze https://your-app.com \
--json --fail-on-severity high \
| tee $(Build.ArtifactStagingDirectory)/purplemet-report.json
displayName: 'Purplemet Security Analysis'
- publish: $(Build.ArtifactStagingDirectory)/purplemet-report.json
artifact: purplemet-report
condition: always()Downloads and installs the CLI binary.
steps:
- script: |
curl -sSL https://raw.githubusercontent.com/purplemet/cli/main/scripts/install.sh | sh
purplemet-cli analyze https://your-app.com \
--json --fail-on-severity high \
| tee $(Build.ArtifactStagingDirectory)/purplemet-report.json
displayName: 'Purplemet Security Analysis'
env:
PURPLEMET_API_TOKEN: $(PURPLEMET_API_TOKEN)
- publish: $(Build.ArtifactStagingDirectory)/purplemet-report.json
artifact: purplemet-report
condition: always()When using the Marketplace extension (Method 1), all gates and options are exposed as task inputs:.
| Input | Default | Description |
|---|---|---|
apiToken |
— | API token (use secret variable $(PURPLEMET_API_TOKEN)) |
targetUrl |
— | URL of the web application to analyze |
| Input | Default | Description |
|---|---|---|
failSeverity |
high |
Severity threshold: critical, high, medium, low, info
|
timeout |
1800000 |
Polling timeout in milliseconds (30 min, 0 = unlimited) |
version |
latest |
CLI version to use (e.g. v1.2.0) |
format |
json |
Output format: json, human, sarif, html
|
baseUrl |
— | API base URL override |
basicUser |
— | HTTP Basic Auth user (dev API only) |
basicPass |
— | HTTP Basic Auth password (dev API only, use secret variable) |
noCreate |
false |
Do not auto-create site if URL not found |
| Input | Default | Description |
|---|---|---|
failRating |
— | Fail if rating is at or below this grade (A–F) |
failCvss |
0 |
Fail if any CVE has CVSS score ≥ this value (e.g. 9.0) |
failOnEol |
false |
Fail on end-of-life components |
failOnSsl |
false |
Fail on SSL/TLS protocol issues |
failOnCert |
false |
Fail on certificate issues |
failOnHeaders |
false |
Fail on HTTP security header issues (CSP, HSTS, X-Frame-Options) |
failOnCookies |
false |
Fail on insecure cookies (HttpOnly, Secure, SameSite) |
failOnUnsafe |
false |
Fail on unsafe component issues |
failOnKev |
false |
Fail on CISA Known Exploited Vulnerabilities |
failOnEpss |
0 |
Fail if any issue has EPSS score ≥ this value (0.0–1.0) |
failOnActiveExploits |
false |
Fail on actively exploited vulnerabilities |
failOnOssfScore |
0 |
Fail if any technology has OpenSSF Scorecard score below this value (0–10) |
failOnCertExpiry |
0 |
Fail if certificate expires within N days |
failOnIssueCount |
0 |
Fail if total issue count ≥ this value |
requireWaf |
false |
Fail if no WAF is detected |
failOnSensitiveServices |
false |
Fail if sensitive services are exposed on the site IP |
excludeTech |
— | Fail if specified technologies are detected (comma-separated) |
YAML types: booleans are unquoted (failOnKev: true), numeric thresholds are quoted strings (failCvss: '9.0').
Methods 2 and 3 don't use task inputs — they run analyze.sh which reads PURPLEMET_* environment variables. These are not needed when using the extension.
| Variable | Default | Description |
|---|---|---|
PURPLEMET_API_TOKEN |
— | API authentication token (required) |
PURPLEMET_TARGET_URL |
— | URL to analyze (required) |
PURPLEMET_FAIL_SEVERITY |
— | Severity threshold |
PURPLEMET_FAIL_RATING |
— | Rating threshold: A–F
|
PURPLEMET_FAIL_CVSS |
0 |
CVSS score threshold |
PURPLEMET_FAIL_ON_EOL |
false |
Block on end-of-life components |
PURPLEMET_FAIL_ON_SSL |
false |
Block on SSL/TLS issues |
PURPLEMET_FAIL_ON_CERT |
false |
Block on certificate issues |
PURPLEMET_FAIL_ON_HEADERS |
false |
Block on HTTP security header issues |
PURPLEMET_FAIL_ON_COOKIES |
false |
Block on insecure cookies |
PURPLEMET_FAIL_ON_UNSAFE |
false |
Block on unsafe components |
PURPLEMET_FAIL_ON_KEV |
false |
Block on CISA Known Exploited Vulnerabilities |
PURPLEMET_FAIL_ON_EPSS |
0 |
EPSS score threshold |
PURPLEMET_FAIL_ON_ACTIVE_EXPLOITS |
false |
Block on actively exploited vulnerabilities |
PURPLEMET_FAIL_ON_OSSF_SCORE |
0 |
Min OpenSSF Scorecard score |
PURPLEMET_FAIL_ON_CERT_EXPIRY |
0 |
Block if certificate expires within N days |
PURPLEMET_FAIL_ON_ISSUE_COUNT |
0 |
Block if total issues ≥ threshold |
PURPLEMET_REQUIRE_WAF |
false |
Block if no WAF detected |
PURPLEMET_FAIL_ON_SENSITIVE_SERVICES |
false |
Block if sensitive services exposed |
PURPLEMET_EXCLUDE_TECH |
— | Block if specified technologies detected |
PURPLEMET_WAIT_TIMEOUT |
1800000 |
Polling timeout (ms) |
PURPLEMET_FORMAT |
json |
Output format: json, human, sarif, html
|
PURPLEMET_BASE_URL |
— | API base URL override |
Multiple gates can be combined — the analysis fails (exit code 1) if any gate triggers.
steps:
- script: |
curl -sSL https://raw.githubusercontent.com/purplemet/cli/main/scripts/install.sh | sh
purplemet-cli analyze https://your-app.com \
--json \
--fail-on-severity high \
--fail-on-eol \
--fail-on-kev \
--fail-on-ssl \
--require-waf \
--fail-on-cert-expiry 30
displayName: 'Security Analysis (Strict)'
env:
PURPLEMET_API_TOKEN: $(PURPLEMET_API_TOKEN)The PurplemetAnalyze@1 task exposes output variables for use in subsequent steps:
| Variable | Description | Example |
|---|---|---|
PurplemetExitCode |
Exit code of the analysis | 0 |
PurplemetRating |
Security rating | B |
PurplemetIssues |
Total number of issues | 12 |
steps:
- task: PurplemetAnalyze@1
name: analysis
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
continueOnError: true
- script: |
echo "Rating: $(analysis.PurplemetRating)"
echo "Issues: $(analysis.PurplemetIssues)"
echo "Exit code: $(analysis.PurplemetExitCode)"
displayName: 'Check Results'trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
failSeverity: 'high'trigger:
- main
pool:
vmImage: 'ubuntu-latest'
stages:
- stage: Build
jobs:
- job: Build
steps:
- script: make build
- script: make test
- stage: Deploy
dependsOn: Build
jobs:
- deployment: DeployStaging
environment: staging
strategy:
runOnce:
deploy:
steps:
- script: ./deploy.sh staging
- stage: Security
dependsOn: Deploy
jobs:
- job: Analysis
steps:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://staging.example.com'
failSeverity: 'high'
timeout: '600000'
- stage: Production
dependsOn: Security
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployProd
environment: production
strategy:
runOnce:
deploy:
steps:
- script: ./deploy.sh productiontrigger: none
schedules:
- cron: '0 6 * * 1' # Every Monday at 6:00 UTC
displayName: 'Weekly Security Analysis'
branches:
include:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://production.example.com'
failSeverity: 'medium'
timeout: '600000'trigger:
- main
pool:
vmImage: 'ubuntu-latest'
strategy:
matrix:
app1:
targetUrl: 'https://app1.example.com'
app2:
targetUrl: 'https://app2.example.com'
api:
targetUrl: 'https://api.example.com'
steps:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: $(targetUrl)
failSeverity: 'high'steps:
- task: PurplemetAnalyze@1
name: analysis
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
failSeverity: 'high'
continueOnError: true
- script: |
if [ "$(analysis.PurplemetExitCode)" = "1" ]; then
echo "##vso[task.logissue type=warning]Security analysis found $(analysis.PurplemetIssues) issue(s) — rating: $(analysis.PurplemetRating)"
fi
displayName: 'Report Results'
condition: always()- Add the Purplemet Security Analysis task from the task catalog
- Configure:
-
API Token:
$(PURPLEMET_API_TOKEN)(link a secret variable) - Target URL: your application URL
-
Fail Severity:
high
-
API Token:
- Optionally check Continue on error for non-blocking mode
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
stages:
- stage: Build
jobs:
- job: BuildAndTest
steps:
- script: make build && make test
- stage: Deploy
dependsOn: Build
jobs:
- deployment: Staging
environment: staging
strategy:
runOnce:
deploy:
steps:
- script: ./deploy.sh
- stage: Security
dependsOn: Deploy
jobs:
- job: StrictAnalysis
steps:
- script: |
curl -sSL https://raw.githubusercontent.com/purplemet/cli/main/scripts/install.sh | sh
purplemet-cli analyze https://staging.example.com \
--json \
--fail-on-severity high \
--fail-on-eol \
--fail-on-kev \
--fail-on-ssl \
--fail-on-cert-expiry 30 \
--require-waf
displayName: 'Security Analysis (Strict)'
env:
PURPLEMET_API_TOKEN: $(PURPLEMET_API_TOKEN)
- stage: Production
dependsOn: Security
jobs:
- deployment: Prod
environment: production
strategy:
runOnce:
deploy:
steps:
- script: ./deploy.sh production| Code | Meaning | Task Result |
|---|---|---|
| 0 | No issues above threshold | Succeeded |
| 1 | Issues found above threshold | Succeeded with issues |
| 2 | Analysis error on Purplemet | Failed |
| 3 | Timeout exceeded | Failed |
| 4 | Network or API error | Failed |
| 5 | Usage error (bad arguments) | Failed |
| 6 | API contract error | Failed |
Ratings (A–F) and severity levels (CRITICAL/HIGH/MEDIUM/LOW/INFO) are computed and defined by the Purplemet platform. See the official Purplemet documentation for authoritative definitions.
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
version: 'v1.2.0'For json, sarif, and human formats, the PurplemetAnalyze@1 task automatically uploads the analysis output as a build artifact named purplemet-report. Open the pipeline run → Summary tab → Published section to download it. No extra step required.
For html format, the CLI writes purplemet-report.html directly to the pipeline workspace (not to stdout), so you must publish it explicitly:
steps:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
format: 'html'
failSeverity: 'high'
- task: PublishPipelineArtifact@1
condition: always() # publish even if the gate fails
inputs:
targetPath: '$(System.DefaultWorkingDirectory)/purplemet-report.html'
artifact: 'purplemet-report-html'
publishLocation: 'pipeline'Download the artifact from Summary → Published and open it locally. Azure DevOps does not render HTML inline — install the HTML Report Publisher extension if you want a dedicated tab inside the run.
If you're using the binary directly (no extension):
steps:
- script: |
curl -sSL https://raw.githubusercontent.com/purplemet/cli/main/scripts/install.sh | sh
purplemet-cli analyze https://your-app.com \
--format html --output-file $(Build.ArtifactStagingDirectory)/report.html \
--fail-on-severity high || true
displayName: 'Generate HTML Analysis Report'
env:
PURPLEMET_API_TOKEN: $(PURPLEMET_API_TOKEN)
- publish: $(Build.ArtifactStagingDirectory)/report.html
artifact: security-report
condition: always()cd integrations/azure-devops
npm install -g tfx-cli
tfx extension create --manifest-globs vss-extension.json
tfx extension publish --token <PAT>The pipeline variable is missing.
Fix: Add PURPLEMET_API_TOKEN as a secret variable:
Edit pipeline → Variables → New variable → check Keep this value secret.
Or use a Variable group: Pipelines → Library → New variable group.
The API token is invalid or expired.
Fix:
- Verify:
purplemet-cli auth check - Create a new token at cloud.purplemet.com
- Update the pipeline variable
Fix: Increase the timeout:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
timeout: '600000' # 10 minutesExit code 1 means vulnerabilities were found. The task reports Succeeded with issues by default.
To fully suppress the failure:
- task: PurplemetAnalyze@1
inputs:
apiToken: $(PURPLEMET_API_TOKEN)
targetUrl: 'https://your-app.example.com'
continueOnError: trueFor on-premises installations, upload the extension manually:
- Download the
.vsixfrom the Marketplace - Go to Organization Settings → Extensions → Browse local extensions → Upload
Self-hosted agents may not have access to the Purplemet API.
Fix: Ensure outbound HTTPS access to api.purplemet.com. If behind a proxy, configure HTTP_PROXY / HTTPS_PROXY.
Use a matrix strategy (see Multi-Site Analysis example).
- Pipeline log: Summary in the task output
-
Pipeline artifacts: Download
purplemet-report.json -
Output variables: Access
PurplemetRating,PurplemetIssuesin subsequent steps - Purplemet dashboard: cloud.purplemet.com for detailed results