A license problem in production is the worst place to find one. The product has shipped, customers are using it, marketing has run the campaign, and somebody on the legal team has just discovered that a dependency added six months ago carries a copyleft license incompatible with the company's distribution model. The remediation options range from rewriting the dependency in-house to changing the product's licensing position, and neither option is cheap. The cheapest moment to have made this decision was the moment the dependency was first proposed.
License compliance is one of the most automatable pieces of supply chain policy, and one of the most under-automated. The data is structured: every package declares a license, every license is part of a known set, and the compatibility rules between licenses and product distribution models are well-documented. Yet most organizations rely on periodic legal reviews and manual SBOM audits to catch problems, with all the latency and inconsistency those processes imply. PR-time license enforcement turns the manual process into a deterministic, automated one.
Why license policy is hard to do right manually
Manual license review fails for the same reasons manual vulnerability review fails: volume, drift, and context loss.
A modern application has hundreds of direct dependencies and thousands of transitive ones. Reviewing each one's license at release time is not feasible at scale, so most legal reviews focus on direct dependencies and trust transitives implicitly. This is exactly the wrong heuristic. The riskiest license problems often arrive transitively, where a benign-looking direct dependency pulls in a copyleft library three levels down.
License situations also drift. A dependency that was MIT-licensed when added may be relicensed by its maintainer in a later version. The lockfile updated last sprint may have pulled in a relicensed version without anyone noticing because the manifest still shows the same package name. Manual review at fixed checkpoints cannot keep up with continuous dependency churn.
And manual review loses context. The reviewer at release time has no insight into why a particular dependency was added, what alternatives were considered, or whether replacing it is feasible. The PR author at the time of intake has all of that context but is rarely asked the license question. Aligning the review moment with the intake moment puts the question to the person best able to answer it.
What automated license policy actually decides
The core of automated license policy is a small set of decisions encoded as rules.
Allowed licenses. A list of license identifiers that are unconditionally permitted for the project's distribution model — typically permissive licenses like MIT, BSD, Apache 2.0, ISC.
Conditionally allowed licenses. Licenses that are acceptable in some contexts and not others. LGPL might be allowed for dynamically linked dependencies in a server-side product but disallowed for statically linked dependencies in a client-side product. The condition is part of the rule.
Disallowed licenses. Licenses incompatible with the product's distribution model. AGPL in a closed-source SaaS product is a common example. Custom non-OSI licenses with restrictive terms also belong here.
Unknown licenses. Packages without a clear license declaration. The default policy needs a position: usually treated as block-pending-review, because no declaration is itself a problem.
License combinations. Some licenses are individually acceptable but problematic in combination. The classic example is GPL with proprietary code in the same binary. The rule needs to encode the combination, not just the individual licenses.
A rule expressed in this form can be evaluated against any package's metadata in milliseconds. The hard part is not the evaluation; it is choosing the lists, and choosing them in collaboration with legal counsel rather than from a stack-overflow checklist.
The PR-time experience
A developer adds a dependency to a manifest. The PR check fetches the dependency's license, follows its dependency tree to gather transitive licenses, and evaluates the active license rules. If everything is permitted, the check passes silently. If something fails, a PR comment appears with specifics:
- The package and version that introduced the problematic license.
- The license identifier and the rule it violated.
- The transitive path, if applicable, showing how the problematic license arrived.
- The override channel, with the named approver group.
- A short rationale link explaining the rule's purpose.
This is a substantively different conversation than the legal review failed at release. The developer has the dependency in front of them, the alternatives are still on the table, and the cost of switching is at its lowest. Many PR-time license blocks resolve without any human escalation: the developer reads the message, picks an alternative, and moves on.
Tone matters
License policy is a domain where tone determines whether developers cooperate or resent. The block message has to assume the developer did not know about the license issue, has no preference for the problematic dependency over alternatives, and wants to ship without unnecessary friction.
Bad: Policy violation: AGPL dependency.
Better: The dependency name@version carries the AGPL-3.0 license, which is not compatible with this project's distribution model (closed-source SaaS). Permitted alternatives include alt-a and alt-b. If this dependency is essential, request a review through the license-exceptions channel — typical SLA is one business day.
The better message respects the developer's time and gives them three usable next steps. The bad message makes them search Slack for who to ask.
Edge cases worth handling
Several recurring edge cases need explicit policy handling.
Multi-licensed packages. A package that offers MIT or GPL is a different situation from a package that requires MIT and GPL. The rule has to evaluate the chosen license under the project's selection, not assume the worst case.
Dual-licensed dependencies with paid commercial options. A dependency offered under AGPL with a separate commercial license needs a policy that recognizes the commercial path. Without this, the policy generates noise on dependencies the company has actually paid for.
Internal packages. Code published internally often has no formal license declaration because it is not intended for external distribution. The policy needs an internal-package allowlist that does not require manual approval per package.
Vendored sources. Dependencies vendored into the repository sometimes have license headers in source files but no manifest-level metadata. The policy needs to scan source files for embedded license headers when manifest metadata is missing.
Build-time-only dependencies. A linter or test runner that does not ship in the final product has different license implications than a runtime dependency. The policy can scope by manifest section — devDependencies versus dependencies in the npm sense — to apply less strict rules where appropriate.
Reporting and ongoing review
Beyond intake-time enforcement, the policy needs reporting. A monthly report that lists every license currently in the codebase, every dependency carrying a conditionally allowed license, and every package whose license has changed in the last reporting period gives legal counsel the visibility they need without forcing them into ad-hoc audits. The report is generated automatically from the same data the PR-time check evaluates, so the legal view and the engineering view do not diverge.
How Safeguard Helps
Safeguard treats license policy as a first-class member of the unified policy set, evaluated at every gate.
At PR time, Safeguard scans the proposed manifest changes, fetches license metadata for new direct and transitive dependencies, and evaluates the active license rules. Failed checks produce structured PR comments naming the package, the license, the rule, the transitive path, and the override channel. Permitted alternatives are surfaced when the policy includes them.
At build time, Safeguard re-evaluates the assembled SBOM against the same license rules, catching problems introduced by lockfile updates, vendored sources, or build-step generated dependencies that did not appear in the manifest.
At admission time, the Safeguard Kubernetes webhook evaluates the deployed workload's SBOM against the namespace's license policy, refusing workloads that carry licenses incompatible with the namespace's declared distribution context. A namespace tagged closed-source-product cannot admit workloads carrying AGPL transitives.
At runtime, Safeguard tracks SBOM drift and surfaces the introduction of new license obligations during a workload's lifetime — a runtime fetch that pulls in a copyleft component, for instance — so the legal posture of the running system stays observed rather than only certified at build.
License rules use the same break-glass workflow, the same audit log, and the same dashboard as the rest of the policy set. Legal counsel gets reports generated from the same data engineers see at intake, and the question do we have any AGPL exposure? has a fast, automated answer at every gate, every day, rather than a quarterly review whose results are already weeks out of date.