Skip to content

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

  1. Validation - Verify required GitLab API configuration
  2. Upload - Send SBOM files to GitLab's scanning service API via multipart upload
  3. Poll - Wait for scan completion using configurable initial delay and static backoff
  4. Download - Retrieve vulnerability findings as JSON
  5. Report - Generate standardized GitLab security report format
  6. 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::Finding Gitlab::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):

  1. 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.
  2. 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.
  3. 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.
  4. 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:

https://youtu.be/1iG4_G7tCtA

Edited by Olivier Gonzalez

Merge request reports

Loading