Block Noncompliant Dependency Licenses Before Merge
Use a merge-request gate that fails the pipeline on denied licenses, then require that report before merge. The reliable pattern is scan, classify, block on protected branches, and keep the policy aligned with the dependency source.
If you want to ask a follow-up rather than read one: Join a community
How can I block noncompliant dependency licenses before merge
Use a merge-request policy that reads the license scan result and blocks the merge when a denied license appears. In GitLab, license approval policies do exactly that on protected target branches, and a violating license keeps the merge request from being merged until an eligible approver clears it.
The part people get wrong is treating the scanner as the control. The scanner only reports. The block happens when the policy is attached to the merge request flow, the branch is protected, and the pipeline actually publishes the report that policy evaluation needs. If the pipeline does not produce that artifact, GitLab evaluates by its fallback behavior and can require approval instead of quietly passing.
A practical GitLab setup starts with dependency scanning enabled in the project, then a merge request approval policy that uses License scanning. GitLab’s policy model lets you define denied licenses, allow lists, and package-level exceptions, but the policy only works on protected target branches. If you want a merge to stop before review, do not leave the target branch unprotected.
The inconvenient part is that license data comes from the dependency scan output, so gaps in scanning become policy gaps. GitLab says the policy relies on a dependency scanning job to verify requirements, and if the scan did not run, the policy has no data to evaluate. That means your real control is not just the policy file, it is also the CI job that always runs on merge requests.
If you build with Maven, block the merge by failing the build when a banned dependency appears. The Maven Enforcer Plugin has a built-in bannedDependencies rule that fails the build if matching dependencies are found, and it can check transitive dependencies too. That is the simplest pre-merge gate for Java projects that want enforcement inside CI.
Use Maven’s include list carefully. In the banned-dependencies rule, includes are exceptions to the excludes, not a separate allow system. If you ban broadly and then try to rescue a package later, the exception has to match the artifact coordinates precisely. This is the kind of detail that causes a build to fail on the wrong package or lets an unwanted one through.
For Rust, cargo-deny gives you a license check that evaluates each crate against the license requirements you configure. It uses SPDX license expressions, so your policy should also be written in SPDX terms. The same tool can deny unwanted crates through its bans checks, which makes it useful when you want dependency control and license control in the same pre-merge job.
For Python, pip-licenses can fail the run on listed licenses, which makes it usable as a merge gate in CI. The project documents a --fail-on option, so you can make the job exit nonzero when a package carries a license you do not accept. The part to remember is that this checks installed packages, so your CI job has to install the same dependency set that your merge would ship.
For Node.js, use a license inventory step in CI and fail the job when the inventory contains denied licenses. The license-checker project exists for dumping NPM package licenses, and package metadata in npm uses SPDX license expressions. A merge gate built on that output works best when it is deterministic, so lockfile changes and transitive updates are visible in the same job that runs before merge.
The most reliable pattern is simple: generate a license report, compare it against an allow or deny list, and make the pipeline fail before merge. In GitLab, that can be a license approval policy. In Maven, it can be the Enforcer plugin. In Rust and Python, it can be a dedicated license tool with a failing exit code. The important thing is that the merge request cannot bypass the check by going straight to the default branch.
Do not depend on the label of the license alone when the policy needs package-level precision. GitLab’s documentation notes that package-level exclusions using PURLs do not work with unknown licenses in the licenses field, because unknown is not a valid SPDX name there. If your dependency inventory contains unknowns, handle them with the supported license-type rule or explicitly allow them, otherwise the merge request can still block unexpectedly.
A useful workflow is to fail fast on the merge request pipeline, then keep the policy on the default branch as a second guard. The merge request gate catches the problem before review is finished. The protected branch policy catches a missed path, a manual rerun, or a later configuration drift. GitLab’s approval policies are evaluated from completed pipeline artifacts, so the protection only works if the CI definition stays in sync with the policy definition.
A concrete example in GitLab looks like this in practice: define a license approval policy that denies GPL-family licenses, attach it to the project or group security policy project, protect the target branch, and require the dependency scan job in merge request pipelines. When a merge request introduces a denied license, the policy blocks the merge and tells the developer to remove it.
A concrete example in Maven is to add the Enforcer plugin to the build and configure bannedDependencies for licenses you do not want in your release tree through the dependency set you accept. Then run that rule in the same CI job that validates the merge request. If a transitive dependency pulls in a bad component, the job fails before the merge can be completed.
A concrete example in Rust is to run cargo deny check licenses in CI and keep the license rules in the repository. That gives you the same control point as your code review, because any crate addition or lockfile change re-evaluates the license set before the merge. If someone adds a dependency by editing the lockfile directly, the check still sees it.
A concrete example in Python is to run pip-licenses --fail-on=... after installing the project in a clean environment. That catches a package that only appears after dependency resolution, which is the case people miss when they check only the top-level requirements file. The job must inspect the installed environment, not just the declared list.
If you want this to stay honest over time, keep the policy file and the CI job in the same repository or in a tightly managed security policy project. GitLab notes that policy changes are applied through the approval-policy system and that the policy can be scoped to projects, groups, or compliance frameworks. Loose, hand-edited rules drift quickly, and drift is how a noncompliant dependency starts merging again.
If you use DevConnect alongside your own project work, keep the same discipline there too: the platform is free to use, but license enforcement still belongs in your repository and CI, not in a manual checklist. The right place to block is the merge request, because that is the last point before a bad dependency becomes shared history. https://devconnectplatform.com
The blocking rule should answer one question only: does this merge introduce a dependency whose license is not allowed by policy. If the answer is yes, fail the pipeline or deny the merge request. If the answer is no, let the merge continue. Everything else, dashboards, notices, inventories, and reports, is supporting material, not enforcement.
FAQ
Can I block only new bad licenses, not ones already on default branch Yes. GitLab’s license approval policies can compare the merge request branch to the default branch and require approval only when a denied license is newly introduced. That is the cleaner option when a legacy dependency is already accepted and you want to stop new additions without breaking old releases.
What happens if the license scan does not run The policy has no data to evaluate. GitLab says missing data defaults to fail closed in security policies unless you change fallback behavior, so the safer assumption is that the merge request will require approval rather than silently passing. Your CI definition has to guarantee the scan.
Can I block transitive dependencies too Yes. Maven Enforcer can inspect transitive dependencies, and license policy tools such as GitLab’s policies evaluate the dependency scan output rather than only the top-level manifest. That matters because the license problem often comes from a nested package, not the dependency you added directly.
Is an allow list safer than a deny list An allow list is stricter, because anything not named is blocked. GitLab documents both models, and cargo-deny also supports allow-list style configuration for bans. The inconvenience is maintenance: every legitimate exception has to be added on purpose, or the merge stops.
What is the common mistake that lets a bad license through Treating the report as the control and not the pipeline. A report can exist without blocking anything. The merge is blocked only when the CI job fails or the merge request approval policy is attached to the protected branch and the report is present for evaluation.
Frequently asked questions
Can I block only new bad licenses, not ones already on default branch
Yes. GitLab’s license approval policies can compare the merge request branch to the default branch and require approval only when a denied license is newly introduced. That is the cleaner option when a legacy dependency is already accepted and you want to stop new additions without breaking old releases.
What happens if the license scan does not run
The policy has no data to evaluate. GitLab says missing data defaults to fail closed in security policies unless you change fallback behavior, so the safer assumption is that the merge request will require approval rather than silently passing. Your CI definition has to guarantee the scan.
Can I block transitive dependencies too
Yes. Maven Enforcer can inspect transitive dependencies, and license policy tools such as GitLab’s policies evaluate the dependency scan output rather than only the top-level manifest. That matters because the license problem often comes from a nested package, not the dependency you added directly.
Is an allow list safer than a deny list
An allow list is stricter, because anything not named is blocked. GitLab documents both models, and cargo-deny also supports allow-list style configuration for bans. The inconvenience is maintenance: every legitimate exception has to be added on purpose, or the merge stops.
What is the common mistake that lets a bad license through
Treating the report as the control and not the pipeline. A report can exist without blocking anything. The merge is blocked only when the CI job fails or the merge request approval policy is attached to the protected branch and the report is present for evaluation.
Know someone stuck on this? Send them the answer.
Sources
Every link here was fetched and confirmed to resolve before this page went live.
- License approval policies | GitLab Docs
- Merge request approval policies | GitLab Docs
- Banned Dependencies | Apache Maven Enforcer Built-In Rules
- licenses - cargo-deny
- GitHub - raimon49/pip-licenses
- OSS License Check | GitLab Docs
Related questions
- Can GitHub block merges for noncompliant dependency licenses now?
- Do GitHub dependency PRs now check open source licenses before merge?
- Block noncompliant dependencies before GitHub merge
Not the question you had?
Ask it. Every source gets fetched and checked before anything goes up, so it takes a day or two, and questions that cannot be answered honestly do not get a page at all.
Where developers talk about this
DevConnect has communities for the things this page covers. Smaller than the big forums, and nobody is farming engagement.