Consider scoping vulnerabilities by report type in MarkAsResolvedService for all usages

Why are we doing this work

The MarkAsResolvedService takes the IDs of recently ingested vulnerabilities for a project which had been previously detected by the same scanner, and marks them as resolved1 no longer detected on the default branch if they were not detected again.

This service is used during the generic security report ingestion process and it is called once after all security reports of all report types have been ingested. This works as long as the project CI configuration complies with this requirement: all the scans from a given scanner must always run together in the same pipeline.

Though, this approach prevents some optimizations that would allow to execute scans from the same scanner in a more granular way (e.g. A project build and scans multiple container images, but sometimes they only build and scan a single one).

Additionnaly, while the scanners we use at GitLab have historically been focused on generating a single type of vulnerabilities, some third party scanners and the more recent GitLab Sbom Vulnerability Scanner are capable of reporting different types of vulnerabilities (in different scans still).

This can lead to the undesired behavior when the MarkAsResolvedService flags all vulnerabilities created by a given scanner without considering the report type of the scan currently being processed. Again, as long as all scans from that scanner are always executed together, the current logic would still work. But with our expension to execute security scans outside of the CI pipeline workflow, and mixing different workflow in the same project, this is becoming a restricting limitation and an increasing risk of incorrectly flagging vulnerabilities as no longer detected.

For instance, the GitLab Sbom Vulnerability Scanner is not leveraging that generic ingestion process since these scans are not executed in the CI pipeline but after an Sbom report has been processed (so it still somehow tied to a pipeline, but it is handled asynchronously rather than within the generic ingestion logic).

flowchart TD
    subgraph Vulnerability-Ingestion
    direction LR
        A[Ingest Security Reports] --> B[MarkAsResolved]     
    end
    Vulnerability-Ingestion -->|async| SBOM-Ingestion
    subgraph SBOM-Ingestion
    direction LR
        C[Ingest SBOM reports]
    end
    SBOM-Ingestion -->|async| SBOM-Scanning
    subgraph SBOM-Scanning
    direction LR
        AA[SBOM security scanning + create vulnerabilities] -->CC[MarkAsResolved]
    end

Supporting a fully granular situation where we could run partial scans in different workflows on a given project and mix these results in a coherent way is a bigger task. As a first step, we wanted to at least consider the ability to run scans of different types but from the same scanner in different timelines. This was a need for the GitLab Sbom Vulnerability Scanner supporting both Dependency Scanning and Container Scanning vulnerability scanning types. So in Allow MarkAsResolvedService to scope by report ... (!179117 - merged) we've introduced an optional report_type parameter that allows to circumvent this problem. Though, this parameter is only used in SBOM based scanning workflows maintained by groupcomposition analysis .

The purpose of this issue it to consider the relevancy of applyng this report_type scoping to all scanners.

Relevant links

Non-functional requirements

  • Documentation:
  • Feature flag:
  • Performance:
  • Testing:

Implementation plan

Verification steps

  1. The term "resolve on the default branch" is present in several places of our codebase and can be misleading. It actually refers to marking a vulerability as "no longer detected in the default branch" which is a specific property of a vulnerability record, independently from its state. This must note be mixed with the "RESOVLED" state of a vulnerability record for instance. To add to the confusion, the recently added feature to automatically set the state to "RESOLVED" via the vulnerability management policy is triggered using that same MarkAsResolvedService service.

Edited by Olivier Gonzalez