Add vulnerability-scanning capability to the Run command
What does this MR do and why?
This MR introduces the vulnerability and report packages that provide vulnerability scanning capabilities for SBOM files, bringing back security analysis results into the context of the analyzer to address the objective of Bring security scan results back into the Depen... (gitlab-org&17150 - closed)
Workflow
- Validation - Verify required GitLab API configuration
- Upload - Send SBOM files to GitLab's scanning service API via multipart upload
- Poll - Wait for scan completion using configurable initial delay and static backoff
- Download - Retrieve vulnerability findings as JSON
- Report - Generate standardized GitLab security report format
- Output - Save gl-dependency-scanning-report.json artifact
Warning
This functionality is designed to be solely used within the context of a GitLab CI job, as it leverages a new rest API endpoint in the GitLab rails application that requires a CI job token for authentication.
In development environments and workflows requiring a manual execution of the analyzer, the vulnerability scanning operation will be skipped. This is achieved by checking the if the CI environment variable is set to true, which is done automatically when running within GitLab CI/CD.
Flowchart
flowchart TD
Start([Start Vulnerability Scanning]) --> WorkerLoop{"For each SBOM file (3 concurrent workers)"}
WorkerLoop --> UploadSBOM[Upload SBOM File]
UploadSBOM --> UploadResponse{Response Status}
UploadResponse -->|Network Error| UploadRetry{Retries left?}
UploadResponse -->|4xx/5xx Error| UploadRetry
UploadResponse -->|403 Forbidden| UploadFailed[❌ Upload failed]
UploadResponse -->|2xx Success| ExtractDownloadURL[Extract Download URL & Scan ID]
UploadRetry -->|Yes| RetryUpload["⚠️ Retry Upload (after backoff delay)"]
UploadRetry -->|No| UploadFailed
RetryUpload --> UploadSBOM
%% Download Process
ExtractDownloadURL --> WaitInitialDelay["Wait initial delay (default: 3s)"]
WaitInitialDelay --> DownloadResults[Download Scan Results]
DownloadResults --> DownloadResponse{Response Status}
DownloadResponse -->|410 Gone| ScanFailed[❌ Scan failed permanently]
DownloadResponse -->|202 Accepted| StillProcessing[⏳ Scan still processing]
DownloadResponse -->|Network Error| DownloadRetry{Retries left?}
DownloadResponse -->|4xx/5xx Error| DownloadRetry
DownloadResponse -->|200 Success| ExtractFindings[Extract Vulnerability Findings]
StillProcessing --> DownloadRetry
DownloadRetry -->|No| DownloadFailed[❌ Download failed after retries]
DownloadRetry -->|Yes| RetryDownload["⚠️ Retry Download (after backoff delay)"]
RetryDownload --> DownloadResults
%% Results Processing
ExtractFindings --> WorkerComplete[✅ Worker completed]
WorkerComplete --> AllWorkersComplete{All SBOM files scanned?}
AllWorkersComplete -->|No| WorkerLoop
AllWorkersComplete -->|Yes| AggregateFindings[Aggregate All Findings]
AggregateFindings --> CreateReport[Create Security Report]
CreateReport --> Success[✅ Vulnerability scanning completed]
%% Styling
classDef errorNode fill:#ffebee,stroke:#f44336,stroke-width:2px
classDef warningNode fill:#fff3e0,stroke:#ff9800,stroke-width:2px
classDef successNode fill:#e8f5e8,stroke:#4caf50,stroke-width:2px
classDef processNode fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
class UploadFailed,ScanFailed,DownloadFailed,PartialFailure errorNode
class RetryUpload,RetryDownload,StillProcessing warningNode
class Success,WorkerComplete successNode
class ValidateParams,UploadSBOM,DownloadResults,AggregateFindings,CreateReport processNode
Key Features
Concurrent SBOM Processing:
- Up to 3 concurrent workers for parallel processing.
- Automatic retry logic with early exit on unrecoverable failures (e.g. 403-Forbidden)
- Fail early the command if any SBOM can't be scanned (no partial scan support)
GitLab API Integration (async):
- Multipart file upload for SBOM files to GitLab's scanning service
- Polling mechanism to retrieve vulnerability scan results
- Job-token based authentication for CI/CD pipeline integration
Simple Configuration:
- Timeout controls for API requests (min: 5, max: 300, default: 10
- Initial delay before attempting to download scan results (min: 1, max: 120, default: 3)
NB: above boundaries related to the API will possibly be revisited after the API implementation is approved and we have determined what's sustainable for the backend.
Architecture
-
vulnerability/scanner.go- Core scanning engine that processes multiple SBOM files concurrently, collect and format results -
vulnerability/client.go- HTTP API client for uploading SBOMs and downloading scan results -
cli/flags/vulnerability.go- CLI configuration flags with validation and environment variable support
See initial implementation and related pending questions.
Add a vulnerability-scanning command to scan SBOM files for vulnerabilities.
This command finds all CycloneDX SBOM files generated by the run command, uploads them to the GitLab API for scanning, and retrieves the security findings.
Warning
This MR is WIP and it brings some concepts worth reconsidering
SBOM file finder
A finder is used by the vulnerability-scanning command at the beginning of its execution to find all CycloneDX sbom files in the target dir that match the pattern we use in the run command when generating sbom.
It might be more relevant to orchestrate both the dependency detection/SBOM generation and vulnerability-scanning commands in a single one. This would allow to memorize the list of generated SBOM files and pass it directly to the vulnerability scanning task, instead of redoing a file search.
A benefit of keeping the finder is the ability for the DS analyzer to take 3rd party SBOMs provided by preceding jobs. Though, if we were to do that, we'd probably implement the functionallity slighlty differently and could still end up having a list of sbom reports as argument for the vulnerability scanning task.
Scan results format
For now the DS API (not implemented, PoC MR here) takes a single SBOM document and returns an array of Security::FindingGitlab::Ci::Reports::Security::Finding objects serialized in JSON, and the command simply dump that content into a file called dependency_scanning_findings.json, colocated to the corresponding sbom file.
To finalize the feature we must implement a solution that provides a dependency-scanning security report that follows our securit-report-schema, like in the gemnasium analyzer.
Multiple options are available and one key aspect is where to format the content as a DS report: in the rails API or in the analyzer? It's worth remembering that we can only have a single DS report per job (see this attempt to remove the limitation). So even if the API returns a response formated as a DS report, we still need to aggregate/merge them on the analyzer side to only have a single DS report artifact.
Also, even if we remove that CI job artifact limitation, we might still face situations where a merge/dedupe or a file renaming would be needed. Indeed, in the same directory we can have 2 SBOM reports with a different file name (e.g. one for npm and one for maven) but we still can't have 2 DS reports with the same name.
This leaves us with the following options (stack ranked by simplicity IMO):
- Collect these API responses, dedupe/merge the findings, and convert them into a dependency-scanning security-report file at the root of the project. Note that we can only have a single DS report per job.
- Modify the API to make it return a response already formatted as a DS security report, and dedupe/merge them in the analyzer to create a single file.
- Modify the API to make it return a response already formatted as a DS security report, add support for multiple DS report artifact per job, and use a dynamic file naming scheme to prevent conflicts.
- Modify the API and the analyzer proposal to send all SBOMs in the same request and make the rails backend do the merged/dedupe and returning a single DS report.
Related issues
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Screenshots or screen recordings
See demo below.
How to set up and validate locally
Please watch this demo for instructions: