Show the license_types unknown fallback reason in the widget

What does this MR do and why?

The merge request widget's License Compliance section can label a compound SPDX expression Allowed or Denied without indicating that the classification came from the license_types unknown fallback rather than from vetting the expression's own operands.

transformLicense now reads a classification.reason field and, when it is license_types_unknown_fallback, adds a supportingText note saying so, for both the allowed and denied outcomes. For a denied license that also has dependency names to report, the note and the existing "Used by X" text combine into one sentence, since the widget shows a single line per item. Every other case (no reason, direct matches, licenses-property evaluation) is unchanged.

Screenshots

Allowed License

Screenshot_2026-09-29_at_4.51.59_PM

Denied License

Screenshot_2026-09-29_at_4.55.22_PM

How to set up and validate locally

Preconditions: GitLab Ultimate (merge request approval policies are Ultimate-tier).

  1. Enable the feature flag on the Rails console:

    Feature.enable(:license_types_unknown_expression_fallback)
  2. Create a project.

  3. Go to Secure > Policies.

  4. Select New policy, then Merge request approval policy.

  5. Switch to .yaml mode and paste:

    approval_policy:
      - name: Approved licenses
        enabled: true
        rules:
          - type: license_finding
            match_on_inclusion_license: false
            license_states:
              - newly_detected
            branch_type: protected
            license_types:
              - unknown
        actions:
          - type: require_approval
            approvals_required: 1
            role_approvers:
              - developer
          - type: send_bot_message
            enabled: true
  6. Merge the merge request this creates, to activate the policy.

  7. Add an empty Gemfile.lock file to the project.

  8. Add a file called gl-sbom-gem-bundler.cdx.json reporting the license expression MIT AND Apache-2.0:

    {
        "bomFormat": "CycloneDX",
        "specVersion": "1.4",
        "serialNumber": "urn:uuid:a15e529c-2113-4a11-a694-6bc3ea4e2b53",
        "version": 1,
        "metadata": {
            "timestamp": "2022-02-23T08:02:39Z",
            "tools": [
                {
                    "vendor": "GitLab",
                    "name": "Gemnasium",
                    "version": "2.34.0"
                }
            ],
            "authors": [
                {
                    "name": "GitLab",
                    "email": "support@gitlab.com"
                }
            ],
            "properties": [
                {
                    "name": "gitlab:dependency_scanning:input_file:path",
                    "value": "Gemfile.lock"
                },
                {
                    "name": "gitlab:dependency_scanning:package_manager:name",
                    "value": "bundler"
                },
                {
                    "name": "gitlab:meta:schema_version",
                    "value": "1"
                }
            ]
        },
        "components": [
            {
                "name": "sidekiq",
                "version": "4.2.10",
                "purl": "pkg:gem/sidekiq@4.2.10",
                "type": "library",
                "bom-ref": "pkg:gem/sidekiq@4.2.10",
                "licenses": [
                    {
                        "license": {
                            "name": "MIT AND Apache-2.0"
                        }
                    }
                ]
            }
        ]
    }
  9. Create a new merge request adding a .gitlab-ci.yml file:

    include:
      - template: Jobs/Dependency-Scanning.gitlab-ci.yml
    
    gemnasium-dependency_scanning:
      stage: test
      script: 'pwd'
      artifacts:
        reports:
          cyclonedx: gl-sbom-gem-bundler.cdx.json
  10. Wait for that merge request's pipeline to finish.

  11. Open that merge request's Reports > License compliance widget.

  12. Verify the MIT AND Apache-2.0 entry, under Allowed, shows the supporting note "Classified as unknown under a license_types policy, and allowed under that name." Without this MR, the entry would show Allowed with no such note.

  13. Edit the policy from step 5, keeping license_types: [unknown] unchanged, and switch match_on_inclusion_license to true. Merge that change.

  14. Reload the widget. Verify the entry, now under Denied, shows "Classified as unknown under a license_types policy, and denied under that name. Used by sidekiq." The dependency name comes from the SBOM fixture's single sidekiq component, and it is combined into the same note rather than replacing it.

References

Edited by Marcos Rocha

Merge request reports

Loading
Loading