Implement License Scanning SBOM scanner
<!--
Implementation issues are used break-up a large piece of work into small, discrete tasks that can
move independently through the build workflow steps. They're typically used to populate a Feature
Epic. Once created, an implementation issue is usually refined in order to populate and review the
implementation plan and weight.
Example workflow: https://about.gitlab.com/handbook/engineering/development/threat-management/planning/diagram.html#plan
-->
## Why are we doing this work
To achieve https://gitlab.com/groups/gitlab-org/-/epics/9400+, we need to implement a License Scanning SBOM Scanner that inherits `LicenseScanning::BaseScanner`, and that returns licenses of project dependencies using the SBOM reports.
NOTE: The SBOM Scanner is behind a feature flag. See https://gitlab.com/gitlab-org/gitlab/-/issues/384935+
## Further details
The [`SbomScanner`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/license_scanning/sbom_scanner.rb) class has been introduced in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105747 but its methods haven't been implemented.
The SBOM scanner responds to `report`, `has_data?`, and `data_available?`. See https://gitlab.com/gitlab-org/gitlab/-/issues/384934
`#report` should do the following:
1. Fetch projet dependencies for the given project or pipeline using SBOM component fetchers.
2. TBD: Normalize component names, unless the SBOM component fetchers already do it. See https://gitlab.com/gitlab-org/gitlab/-/issues/384932#note_1230139272
3. Get the licenses of package versions using another fetcher.
4. Build and return a [`Ci::Reports::LicenseScanning::Report`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/ci/reports/license_scanning/report.rb).
The SBOM scanner works even when the SBOM reports don't contain normalized component names. For instance, it should return the correct licenses for a component whose PURL is `pkg:pypi/djanGO`. (Canonical name is `Django`, and normalized name is `django`.)
`#has_data?` and `#data_available?` should behave as documented in
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105533:
| method | description |
| -- | -- |
| `#has_data?` | Evaluates if the scanner had license scanning data. In terms of the artifact scanner, it will evaluate to true if there was a job that returns a `license_scanning` report. For the SBoM scanner, this may materialize as having SBoM generator jobs. |
| `#data_available?` | Evaluates if the scanner has completed "scanning". In terms of artifact scanning, this is determined if the pipeline with the license scanning report has a status of `success`. |
`PipelineComponents` needs to be updated to return a name that can't be directly compared to `pm_packages.name`. It's normalized, and it includes the namespace (npm) or group ID (Maven). Code: `#{component.purl.namespace}/#{component.purl.name}` See https://gitlab.com/gitlab-org/gitlab/-/issues/384932#note_1243704431
## Relevant links
- Existing skeleton: https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/license_scanning/sbom_scanner.rb
- Definition of the Scanner interface: https://gitlab.com/gitlab-org/gitlab/-/issues/384934
- Implementation of SBOM fetchers: https://gitlab.com/gitlab-org/gitlab/-/issues/384536
- Implementation of licenses fetcher: https://gitlab.com/gitlab-org/gitlab/-/issues/384888
## Non-functional requirements
- [ ] Documentation: https://gitlab.com/gitlab-org/gitlab/-/issues/388439
- [ ] Feature flag: TBD
- [ ] Performance: toggle feature flag and compare response time (SBOM Scanner vs Artifact Scanner)
- [ ] Testing: implement specs in https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/spec/lib/gitlab/license_scanning/sbom_scanner_spec.rb
## Implementation plan
- [ ] Update `PipelineComponents` to return full normalized names. See https://gitlab.com/gitlab-org/gitlab/-/issues/384932#note_1243704431
- [ ] Implement the `SbomScanner`, and update its specs.
- [ ] Add a new `license_scanning_sbom_scanner` feature flag.
- [ ] Change [Gitlab::LicenseScanning.scanner_class](https://gitlab.com/gitlab-org/gitlab/-/blob/39536a8451e1b00eec06bf2f51568f2888c949fb/ee/lib/gitlab/license_scanning.rb#L21-23) to use `SbomScanner` instead of `ArtifactScanner` when the `license_scanning_sbom_scanner` is enabled.
## Verification steps
Check `license_scanning_sbom_scanner` feature flag. Enable `license_scanning_sbom_scanner` feature flag in a project where Dependency Scanning is used to generate SBOMs:
1. Set up a project supported by Dependency Scanning and License DB.
1. Enable feature flag for that project. See #384935
1. Add Dependency Scanning to the CI config, and add dependencies to project.
1. Check licenses in `License Compliance` page.
1. Check other features that have already been refactored as part of https://gitlab.com/groups/gitlab-org/-/epics/8532.
Non-regression test
* Go to a projet where License Scanning has been configured, and that has License Scanning artifacts.
* Use any License Scanning feature that's been refactored as part of https://gitlab.com/groups/gitlab-org/-/epics/8532+.
* Make sure that there's no regression.
The verification tests are blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/384935+.
Also, check whether https://gitlab.com/gitlab-org/gitlab/-/issues/333839+ is fixed when enabling `license_scanning_sbom_scanner`. See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109447#note_1263301787
issue