Cerbi Scanner — Azure DevOps ExtensionRun Cerbi's local scanner in Azure DevOps to catch risky, sensitive, and costly logging patterns before production. The extension is intentionally a Marketplace/pipeline wrapper: it installs or resolves the
Scanner contractCerbi findings are expected to use stable rule IDs and include automation-friendly metadata: rule ID, title, message, severity, file path, line, column when available, excerpt when available, recommendation, confidence, and detected field or pattern category when available.
Policy-as-codeThe scanner should discover policy files named:
You can also pass an explicit policy path with the task Local scanner installation (.NET 10 LTS)Cerbi Scanner is distributed as the
For reproducible enterprise builds, pin .NET 10 LTS upgrade notes
Pipeline usageInstall .NET 10 explicitly with Demo/report mode (
|
| Input | Default | Description |
|---|---|---|
scanPath |
$(Build.SourcesDirectory) |
Solution, project, folder, or file path passed to cerbi-scanner scan --path. |
policyPath |
empty | Optional policy path passed to --policy. If omitted, scanner discovery/default behavior applies. |
failOn |
none |
error | blocker | warning | info | low | medium | high | critical | none. |
failOnNew |
none |
New-finding threshold passed to --fail-on-new when a baseline is used. |
ci |
true |
Pass --ci for concise console output and standard CI report behavior. |
reports |
markdown,json,sarif |
Comma-separated report formats passed as repeated --report values. |
outputDir |
$(Build.ArtifactStagingDirectory) |
Directory passed to --output-dir for scanner-managed report placement. |
baseline |
empty | Optional baseline file passed to --baseline. |
createBaseline |
empty | Optional output path passed to --create-baseline. |
verbose |
false |
Pass --verbose when detailed scanner logs are needed. |
jsonOutput |
$(Build.ArtifactStagingDirectory)/cerbi-results.json |
JSON report path passed to --format json --output. |
sarifOutput |
$(Build.ArtifactStagingDirectory)/cerbi-results.sarif |
SARIF report path passed to --sarif. |
markdownSummary |
$(Build.ArtifactStagingDirectory)/cerbi-report.md |
Markdown report path passed to --summary and published to the build summary when generated. |
includeSnippets |
false |
Include source snippets when the scanner supports them. Disabled by default for safer shared reports. |
publishArtifacts |
true |
Publish generated JSON and SARIF reports as build artifacts. |
uploadToCerbiShield |
false |
Explicitly disabled by default. This wrapper keeps scans local and does not upload findings. |
scannerVersion |
latest |
NuGet version of Cerbi.Scanner to install. Pin 1.1.0 or later in regulated pipelines. |
installScanner |
true |
Install/update the scanner before running. Disable for self-hosted agents with a preinstalled, approved scanner. |
scannerInstallDirectory |
$(Agent.ToolsDirectory)/cerbi-scanner |
Tool-path install directory used before PATH/global-tool probing. |
packageSource |
empty | Optional NuGet feed URL or local source for private feeds or mirrored packages. |
installDotNet |
true |
Install the .NET 10 SDK with the official dotnet-install script when the agent does not already provide .NET 10. |
dotNetVersion |
10.0.x |
.NET SDK version/channel used by the fallback installer. |
dotNetInstallDirectory |
$(Agent.ToolsDirectory)/dotnet10 |
SDK install directory used by the fallback installer and prepended for the current task. |
additionalArguments |
empty | Advanced extra arguments passed directly to cerbi-scanner scan. |
Legacy inputs (policyFile, failThreshold, outputFile, sarifOutputFile, markdownSummaryFile, and failOnSeverity) are still read as aliases where practical, but new pipelines should use the scanner-first inputs above.
CLI behavior invoked by the task
The wrapper verifies that the installed scanner supports scan. If cerbi-scanner scan --help is unavailable, the task fails clearly instead of silently falling back to legacy audit behavior:
Cerbi Scanner version X does not support the scan command. Upgrade to Cerbi.Scanner >= 1.1.0.
The wrapper then runs one scanner-first command:
cerbi-scanner scan --path <scanPath> --policy <policyPath> --ci --fail-on <failOn> --output-dir <outputDir> --report markdown --report json --report sarif --format json --output <jsonOutput> --sarif <sarifOutput> --summary <markdownSummary>
--policy is omitted when policyPath is empty. Baseline inputs append --baseline, --create-baseline, and --fail-on-new only when configured. The task also appends --no-snippets unless includeSnippets: true is configured.
Exit codes are interpreted as:
| Code | Meaning |
|---|---|
0 |
Scan complete, no findings meet the fail threshold |
1 |
Findings found at or above the configured threshold |
2 |
Scanner/configuration error |
Implementation plan for scanner changes
Smallest safe plan for the scanner repository:
- Keep detection in the local
Cerbi.ScannerCLI and expose one shared finding contract for console, JSON, SARIF, markdown, and Azure DevOps. - Add policy loading for the three supported names plus
--policy, with safe defaults when absent. - Normalize severities to
warning,error, andblocker; apply rule enablement and overrides before output/fail decisions. - Implement or verify
CERBI001-CERBI006in the existing supported analyzer path only. If only .NET/Roslyn is currently implemented, document that clearly and keep future language scanners behind the same contract. - Add focused fixtures and tests for each rule, policy overrides, fail threshold, JSON, SARIF, markdown, and this Azure DevOps wrapper argument/report-publishing mapping.
Baseline adoption examples
Create a starting baseline without blocking the build:
- task: CerbiScan@1
inputs:
scanPath: $(Build.SourcesDirectory)
ci: true
failOn: none
createBaseline: $(Build.ArtifactStagingDirectory)/cerbi/cerbi-baseline.json
Fail only on new high/critical findings while allowing known legacy findings to remain tracked:
- task: CerbiScan@1
inputs:
scanPath: $(Build.SourcesDirectory)
policyPath: $(Build.SourcesDirectory)/cerbi-policy.yml
ci: true
baseline: $(Build.SourcesDirectory)/.cerbi/cerbi-baseline.json
failOn: none
failOnNew: high
Enterprise agent configuration
Recommended Marketplace defaults are safe for hosted agents: install the scanner into $(Agent.ToolsDirectory)/cerbi-scanner, scan $(Build.SourcesDirectory), publish SARIF, publish a markdown summary, suppress snippets, and only fail when failOn is configured. For regulated or offline environments:
- task: CerbiScan@1
inputs:
scannerVersion: 1.1.0
installScanner: true
scannerInstallDirectory: $(Agent.ToolsDirectory)/cerbi-scanner
packageSource: https://pkgs.dev.azure.com/your-org/_packaging/security/nuget/v3/index.json
installDotNet: true
dotNetVersion: 10.0.x
dotNetInstallDirectory: $(Agent.ToolsDirectory)/dotnet10
scanPath: $(Build.SourcesDirectory)
policyPath: $(Build.SourcesDirectory)/cerbi-policy.yml
failOn: error
jsonOutput: $(Build.ArtifactStagingDirectory)/cerbi/cerbi-results.json
sarifOutput: $(Build.ArtifactStagingDirectory)/cerbi/cerbi-results.sarif
markdownSummary: $(Build.ArtifactStagingDirectory)/cerbi/cerbi-report.md
includeSnippets: false
publishArtifacts: true
uploadToCerbiShield: false
If your self-hosted image already contains an approved scanner, set installScanner: false. The task will resolve the scanner from scannerInstallDirectory, PATH, or the .NET user tools directory without contacting a package feed.
Privacy & security
- The extension delegates to a local scanner process; it does not upload source or findings to a Cerbi service.
- Keep
includeSnippets: falsefor shared reports unless code excerpts are explicitly required. - Pin
scannerVersionin enterprise pipelines for reproducible governance behavior.
Troubleshooting
Missing .NET runtime or SDK
Symptoms usually look like dotnet was not found, You must install or update .NET, or a scanner launch failure after Cerbi.Scanner installs successfully. Fix this in one of three supported ways:
- Preferred for Microsoft-hosted agents: add
UseDotNet@2beforeCerbiScan@1withversion: 10.0.x. - Marketplace fallback: leave
installDotNet: trueso the task installs the .NET 10 SDK into$(Agent.ToolsDirectory)/dotnet10when .NET 10 is missing. - Self-hosted regulated agents: preinstall a pinned .NET 10 SDK/runtime and set
installDotNet: falseonly afterdotnet --list-sdksordotnet --list-runtimesshows a10.0.*entry.
If installScanner: true is enabled, the task needs a .NET SDK, not only a runtime, because dotnet tool install is an SDK command. If installScanner: false and the scanner is preinstalled, a compatible .NET 10 runtime is sufficient to run the tool.
Exact sample YAML
Copy this baseline for the .NET 10 Cerbi.Scanner release:
trigger:
- main
pool:
vmImage: ubuntu-latest
steps:
- task: UseDotNet@2
displayName: Install .NET 10 SDK
inputs:
packageType: sdk
version: 10.0.x
- task: CerbiScan@1
displayName: Cerbi logging governance scan
inputs:
scanPath: $(Build.SourcesDirectory)
policyPath: $(Build.SourcesDirectory)/cerbi-policy.yml
failOn: error
jsonOutput: $(Build.ArtifactStagingDirectory)/cerbi/cerbi-results.json
sarifOutput: $(Build.ArtifactStagingDirectory)/cerbi/cerbi-results.sarif
markdownSummary: $(Build.ArtifactStagingDirectory)/cerbi/cerbi-report.md
scannerVersion: latest
installScanner: true
scannerInstallDirectory: $(Agent.ToolsDirectory)/cerbi-scanner
installDotNet: true
dotNetVersion: 10.0.x
dotNetInstallDirectory: $(Agent.ToolsDirectory)/dotnet10
includeSnippets: false
publishArtifacts: true
uploadToCerbiShield: false
Requirements
- Azure DevOps agent with the .NET 10 LTS SDK installed (for example
UseDotNet@2withversion: 10.0.x) or taskinstallDotNet: trueso the task can install it locally. - Network access to the configured NuGet source when
installScanner: true, unless the agent already has the tool installed andinstallScanner: falseis used. - Self-hosted enterprise agents can pin
scannerVersion, setpackageSourceto an internal feed, or disable install and pre-provision the scanner in the agent image.