Implementing a robust license compliance policy within a software supply chain is a non-trivial exercise, particularly when the goal is to proactively block components with non-commercial or otherwise restrictive licenses. While JFrog Xray provides the mechanism, its effectiveness hinges on precise configuration. This post details a step-by-step methodology for creating a policy that not only identifies but actively prevents the download of artifacts with undesirable licenses, moving beyond simple reporting.
The core challenge is defining "non-commercial" in a machine-operable way. Xray's default license taxonomy is extensive, but policy logic requires a clear set. We must first curate a target list. Through analysis of SPDX identifiers and common internal compliance lists, I propose a foundational blocklist. This should be tailored, but a strong starting point includes:
- `AGPL-3.0`, `AGPL-3.0-or-later` (viral nature)
- `SSPL-1.0` (MongoDB's controversial license)
- `CC-BY-NC-*` (Creative Commons Non-Commercial family)
- `Facebook-Platform` (example of a restrictive commercial clause)
- `JSON` (historically problematic, though now more permissive, often still flagged)
The policy creation process within the Xray UI is sequential. The critical nuance lies in the rule configuration and its attachment to Watches. Here is the exact procedure, annotated with key decisions.
**1. Create a Custom License Set**
Navigate to **Admin → Policies → License Sets** and create a new set, e.g., `Non-Commercial-Restrictive`. Populate it with the curated SPDX license keys. This set becomes the atomic unit for rule logic.
**2. Define the Policy Rule**
Go to **Admin → Policies → Rules** and create a new rule.
- **Name:** `Block-NonCommercial-Licenses`
- **Criteria:** Under "Licenses," select your custom `Non-Commercial-Restrictive` set. Set the condition to `Is one of`.
- **Actions:** This is the pivotal step. For a blocking policy, you must configure:
- **Fail Build:** Enabled (for CI/CD integration).
- **Notify Webhook:** Optional for alerting.
- **Set Vulnerability Context:** Less relevant for pure license issues.
- **Custom Message:** Provide a clear directive, e.g., "Component {component_name} uses prohibited license(s): {license_list}".
**3. Construct the Policy**
Navigate to **Admin → Policies → Policies** and create a new policy.
- **Name:** `Compliance-Block-NonCommercial`
- **Type:** `License`
- **Rules:** Add the `Block-NonCommercial-Licenses` rule created above. The priority should be set high if you have other license policies.
**4. Apply Policy via a Watch**
Policies are inert without a Watch. In **Admin → Policies → Watches**, create or edit a Watch.
- **Resources:** Assign the repositories (e.g., `docker-prod-local`, `npm-remote`) where blocking should occur.
- **Assigned Policies:** Add the `Compliance-Block-NonCommercial` policy. Ensure the "Blocked" checkbox is selected. This is the enforcement trigger; without it, the policy only generates violations.
**Verification and Operational Considerations**
To test, attempt to download a component with an AGPL license (e.g., a known test package) from a repository under this Watch. The request should be blocked with a 403 Forbidden error, and the Artifactory log will contain the policy denial message. For CI/CD builds, the build will fail at the Xray scan stage.
Important nuances:
- This policy acts on *download* events, not on existing artifacts already in the repository. A retrospective scan via the UI will show violations but won't remove them. Consider a preemptive scan job.
- License detection is not always perfect. Some components may have multiple licenses or ambiguous declarations. The policy will act on any license in the set that Xray detects, which may lead to false positives. Regular review of the `Non-Commercial-Restrictive` set is advised.
- For a layered approach, consider a second, lower-priority policy that warns on "gray area" licenses (like `LGPL-2.1`) without blocking, creating a tiered compliance model.
This configuration transforms Xray from a passive scanner to an active gatekeeper, enforcing license compliance at the point of consumption. The data flow is: artifact request → Watch evaluation → policy rule check → license set lookup → block action. This deterministic pipeline is essential for auditability and consistent enforcement across all development channels.