Exclude packages from Merge Request Approval Policies for License Approval Rules
# Release notes
This new enhancement to License Approval Policies gives legal and compliance teams more precise control over which packages can use specific licenses. You may now create exceptions for pre-approved packages, even when they use licenses that would normally be blocked by your organization's policies.
With this release, you can now:
* Define package-specific exceptions to your license approval rules using Package URL (PURL) format
* Allow specific packages to use otherwise restricted licenses
* Block specific packages from using generally allowed licenses
* Apply these exceptions globally or to specific groups and projects
**Why is this important?**
Previously, license policies were all-or-nothing. If you blocked a license like AGPL-3.0, it was blocked for all packages across your organization. This created challenges when:
* Your legal team pre-approved specific packages with otherwise restricted licenses
* You needed to use the same package across hundreds of projects
* Different teams required different license exceptions
Now you can maintain strict license governance while allowing necessary exceptions, significantly reducing approval bottlenecks and manual reviews.
**How it works**
When creating or editing a License Approval Policy, you can now:
1. Navigate to your group's **Security & Compliance \> Policies**
2. Create or edit a License Approval Policy
3. Find the new package exception options in the visual editor or configure in YAML mode
4. Choose between allowlist or denylist mode for licenses
5. Add specific licenses to your policy
6. For each license, define package exceptions using PURL format (e.g., `pkg:npm/@angular/animation@12.3.1`)
7. Specify whether to include or exclude these packages from the license rule
The policy will then enforce your license rules while respecting the defined exceptions, giving you granular control over license compliance across your organization.
# Problem to solve
When creating a License Approval policy, the options available to define rules are not granular enough. As a legal or compliance professional, our team will pre-approve a package with our legal department for use in our product (despite the license being disallowed in the general policy). I want to be able to filter out components for license approval policies, so my team doesn't have to approve the license for hundreds of projects that may end up using the approved package.
# Intended users
* [Cameron (Compliance Manager)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#cameron-compliance-manager)
* [Alex (Security Operations Engineer)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#alex-security-operations-engineer)
# Proposal & design
### :tv: [Feature Proposal Walkthrough](https://youtu.be/aBkVIr8l8Nk)
### Proposal - Updated Sep 25, 2024
<table>
<tr>
<th>Step</th>
<th>Description</th>
<th>Mockup</th>
</tr>
<tr>
<td>
1\. Create a new license approval policy
</td>
<td>Create a new license approval policy and choose between allowlist or denylist to define licenses for license compliance.</td>
<td>
[Step 1](https://gitlab.com/gitlab-org/gitlab/-/issues/479782/designs/deny-1.png)
</td>
</tr>
<tr>
<td>
2\. Edit License Approval Policy licenses
</td>
<td>Choose an option to create a policy that denies or allows licenses by choosing Allowed or Denied in the dropdown.</td>
<td>
[Step 2 - Allow](https://gitlab.com/gitlab-org/gitlab/-/issues/479782/designs/allow-1.png)
[Step 2 - Deny](https://gitlab.com/gitlab-org/gitlab/-/issues/479782/designs/deny-1.png)
</td>
</tr>
<tr>
<td>
3\. Add licenses and package exceptions via denylist
</td>
<td>A modal will appear allowing users to add licenses that are allowed or denied. For this step, the design shows the flow for a denylist. You can then apply package exceptions per each license. Enter the package details, including name, type, and version (or PURL).</td>
<td>
[Step 3 - Empty Set](https://gitlab.com/gitlab-org/gitlab/-/issues/479782/designs/deny-modal-empty.png)
[Step 3 - Configure denylist](https://gitlab.com/gitlab-org/gitlab/-/issues/479782/designs/deny-modal-filled.png)
</td>
</tr>
<tr>
<td>
4\. Add licenses and package exceptions via allowlist
</td>
<td>A modal will appear allowing users to add licenses that are allowed or denied. For this step, the design shows the flow for an allowlist. You can then apply package exceptions per each license. Enter the package details, including name, type, and version (using PURL).</td>
<td>
[Step 3 - Configure allowlist](https://gitlab.com/gitlab-org/gitlab/-/issues/479782/designs/allow-modal.png)
</td>
</tr>
<tr>
<td>
4\. YAML mode
</td>
<td>Manage the policy settings in YAML. This is the suggested YAML from UX.</td>
<td>
[Step 4](https://gitlab.com/gitlab-org/gitlab/-/issues/479782/designs/Suggest_YAML.png)
</td>
</tr>
</table>
###
# Further context & details
##### License compliance tab -- removed
Here is an example of how license violations used to appear in the License Compliance tab:

**Dependency list - filtered by licenses**
View of packages/components with license information, with filters.
{width="904" height="402"}
##### Pipeline report - licenses
License report in the pipeline that detected the license compliance issue:

## Exploring terms for defining packages to be included/excluded
1. We explored using the term `component` to mean `package name + package version` but based on feedback this is not appropriate.
2. `scheme:type/namespace/name@version?qualifiers#subpath` is recommended based on [Package URL](https://github.com/package-url/purl-spec).
3. Alternatively, `package type + package name + package version` in long-form may be necessary.
#####
## Acceptance Testing
* [ ] MR widget data accurately detects if packages are excluded in the policy and therefore are not a violation
* [ ] Pipeline --\> Licenses tab should also accurately display licenses based on what is defined in the License Approval Policy
### Permissions and Security
### Documentation
### Availability & Testing
### Available Tier
### Feature Usage Metrics
### What does success look like, and how can we measure that?
### What is the type of buyer?
### Is this a cross-stage feature?
### What is the competitive advantage or differentiation for this feature?
### Risks
1. Customers may find it tedious to require updates to individual licenses across thousands of projects, resulting in one-off policy updates. More UI may be required using the `License compliance tab` through the license list displayed there. For example, to more easily go to a group/subgroup/project, go to the license compliance tab, then pick a license that you want to modify as allowed/denied for either that group/subgroup/project.
### Customer Interest
- https://gitlab.my.salesforce.com/0016100001C55u1 - ~"GitLab Ultimate", 255 seats
- https://gitlab.my.salesforce.com/0018X000032XreP?srPos=0&srKp=001 ~"GitLab Ultimate", 60 seats
# Previous Proposals
###
<details>
<summary>
### July 31, 2024
</summary>
###
<table>
<tr>
<th></th>
<th>Current State (Block if matching)</th>
<th>Block if matching, except for packages (purl format)</th>
</tr>
<tr>
<td>
**YAML**
</td>
<td>
```yaml
- type: license_finding
match_on_inclusion_license: true
license_types:
- AMD newlib License
- AGPL-3.0
license_states:
- newly_detected
branch_type: protected
```
</td>
<td>
```yaml
- type: license_finding
match_on_inclusion_license: true
licenses:
- license: AMD newlib License
- license: AGPL-3.0
package_rule:
excluding:
- pkg:npm/%40angular/animation@12.3.1
- pkg:npm/foobar@12.3.1
- pkg:nuget/EnterpriseLibrary.Common@6.0.1304
- pkg:pypi/django ## deny all versions
- pkg:pypi/django@1.11.1 ## deny only this version
license_states:
- newly_detected
branch_type: protected
```
</td>
</tr>
<tr>
<td>
**Explanation**
</td>
<td>
* Block MR if `AMD newlib License` or `AGPL-3.0` are newly detected on a protected branch.
</td>
<td>
* Block the. MR if `AMD newlib License` is detected
* Block the MR if `AGPL-3.0` is detected, except if it is detected for packages listed.
</td>
</tr>
</table>
<table>
<tr>
<th></th>
<th>Block if matching, except for packages (purl format), ignoring groups/projects</th>
<th>Allow if matching, except for packages (purl format), ignoring groups/projects</th>
</tr>
<tr>
<td>
**YAML**
</td>
<td>
```yaml
- type: license_finding
match_on_inclusion_license: true
licenses:
- license: AMD newlib License
- license: AGPL-3.0
package_rule:
excluding:
- pkg:npm/%40angular/animation@12.3.1
- pkg:npm/foobar@12.3.1
- pkg:nuget/EnterpriseLibrary.Common@6.0.1304
- pkg:pypi/django ## deny all versions
- pkg:pypi/django@1.11.1 ## deny only this version
ignore_license_package_rule:
groups:
- id: 200
projects:
- id: 1
- id: 2
license_states:
- newly_detected
branch_type: protected
```
</td>
<td>
```yaml
- type: license_finding
match_on_inclusion_license: false
licenses:
- license: AMD newlib License
- license: AGPL-3.0
package_rule:
excluding:
- pkg:npm/%40angular/animation@12.3.1
- pkg:npm/foobar@12.3.1
- pkg:nuget/EnterpriseLibrary.Common@6.0.1304
- pkg:pypi/django ## deny all versions
- pkg:pypi/django@1.11.1 ## deny only this version
ignore_license_package_rule:
groups:
- id: 200
projects:
- id: 1
- id: 2
license_states:
- newly_detected
branch_type: protected
```
</td>
</tr>
<tr>
<td>
**Explanation**
</td>
<td>
* Block the MR if `AMD newlib License` is detected
* Block the MR if `AGPL-3.0` is detected, except if it is detected for packages listed. For the groups/projects listed, ignore the license package exceptions.
</td>
<td>
* Block the MR if any licenses are detected that do not match `AMD newlib License` or `AGPL-3.0`.
* For group `200` or projects `1` and `2`, if `AGPL-3.0` is detected for the listed packages, block the MR.
</td>
</tr>
</table>
<table>
<tr>
<th></th>
<th>Possible Future State: Block MRs if license detected matches risk severity of "Critical" or "High"</th>
</tr>
<tr>
<td>
**YAML**
</td>
<td>
```yaml
- type: license_finding
match_on_inclusion_license: true
licenses:
severity_levels:
- high
- critical
- license: AGPL-3.0
package_rule:
excluding:
- pkg:npm/%40angular/animation@12.3.1
- pkg:npm/foobar@12.3.1
- pkg:nuget/EnterpriseLibrary.Common@6.0.1304
- pkg:pypi/django ## deny all versions
- pkg:pypi/django@1.11.1 ## deny only this version
ignore_license_package_rule:
groups:
- id: 200
projects:
- id: 1
- id: 2
license_states:
- newly_detected
branch_type: protected
```
</td>
</tr>
<tr>
<td>
**Explanation**
</td>
<td>
* Block if an MR is detected with a risk severity of `Critical` or `High`
* However, for any listed license, consider additional granular rules.
* If `AGPL-3.0` is detected, ignore/override the severity with this rule. Instead, block the MR except if it is detected for packages listed. For the groups/projects listed, ignore the license package exceptions.
</td>
</tr>
</table>
</details>
###
<details>
<summary>
### July 19, 2024
</summary>
1. Add a new filter to allow users to exclude certain components from a License Approval Policy rule based on `purl` format, e.g. `pkg:npm/%40angular/animation@12.3.1` .
2. Specifying the `purl` format of the package without a version (`pkg:npm/%40angular/animation`) will enforce on all packages.
3. Specifying the `purl` format of the package with a version (`pkg:npm/%40angular/animation` ) will add only that specific version of the package to the exceptions.
4. Allow for exceptions to be defined for all projects in scope of the policy, or to designate individual projects with the exception.
5. Make the UI and documentation clear in how the combination of `package type + package + version` are used and defined.
6. Ensure that when enabling a new policy that any existing allowed licenses do not get blocked by the policy.
</details>
<details>
<summary>
### July 13, 2024
</summary>
1. Add a new filter to allow users to exclude certain components (package+version) from a License Approval Policy rule.
2. ~~In the initial MVC, we will focus on excluding the package/dependency regardless of the specific version. In future iterations, we may explore adding the version granularity if we learn there is a demand for this. Decision based on ~~[~~this comment~~](https://gitlab.com/groups/gitlab-org/-/epics/10203#note_1504868284)~~.~~
3. Allow users to define the component they want to exclude in the policy with both the `package+version` with the ability to designate version ranges, for example `Lib (>=1.2.3, <2.0.0)`.
4. Allow for exceptions to be defined for all projects in scope of the policy, or to designate individual projects with the exception.
5. Make the UI and documentation clear in how components are used and defined.
6. Ensure that when enabling a new policy that any existing allowed licenses do not get blocked by the policy.
</details>
###
##
### Links / references
<!--triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION-->
_This page may contain information related to upcoming products, features and functionality. It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes. Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc._
<!--triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION-->
<!--triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION-->
_This page may contain information related to upcoming products, features and functionality. It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes. Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc._
<!--triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION-->
<!-- triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION -->
> [!important]
> This page may contain information related to upcoming products, features and functionality.
> It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes.
> Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.
<!-- triage-serverless v3 PLEASE DO NOT REMOVE THIS SECTION -->
epic