Skip to content

Commit c7e8791

Browse files
EmilienMclaude
andcommitted
feat: Rewrite license-checker skill to use Fedora License Data
Replace SPDX OSI-approval classification with Fedora License Data as the authoritative policy source for Red Hat redistribution decisions. License detection is now deterministic: the skill clones the source repo via python-packaging-source-finder and git-shallow-clone, then reads LICENSE files directly instead of relying on PyPI metadata. This addresses seven documented gaps: correct policy basis, AGPL-3.0 caveat handling, dual-license AND/OR parsing, source repo verification with mismatch detection, proprietary license escalation paths, build compliance flagging, and export compliance flagging. Output is a structured six-field verdict block. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Emilien Macchi <emacchi@redhat.com>
1 parent 0d41f30 commit c7e8791

File tree

2 files changed

+161
-127
lines changed

2 files changed

+161
-127
lines changed

docs/data.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
},
143143
{
144144
"name": "python-packaging-license-checker",
145-
"description": "Assess license compatibility for Python package redistribution using SPDX.org license database. Evaluates whether a given license allows building and distributing wheels, with real-time license information lookup.",
145+
"description": "Check whether a Python package license is compatible with redistribution in Red Hat products, using the Fedora License Data as the authoritative policy source. Produces a structured six-field verdict with escalation guidance for non-trivial cases.",
146146
"category": "general",
147147
"file_path": "helpers/skills/python-packaging-license-checker/SKILL.md",
148148
"id": "python-packaging-license-checker",
Lines changed: 160 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,195 @@
11
---
22
name: python-packaging-license-checker
3-
description: Assess license compatibility for Python package redistribution using SPDX.org license database. Evaluates whether a given license allows building and distributing wheels, with real-time license information lookup.
4-
allowed-tools: WebFetch
3+
description: Check whether a Python package license is compatible with redistribution
4+
in Red Hat products, using the Fedora License Data as the authoritative policy source.
5+
Produces a structured six-field verdict with escalation guidance for non-trivial cases.
6+
allowed-tools: Bash Skill WebFetch
57
---
68

79
# Python Package License Compatibility Checker
810

9-
This skill helps you evaluate whether a Python package license is compatible with redistribution, particularly for building and distributing wheels in enterprise environments. It uses the authoritative SPDX License List for accurate, up-to-date license information.
11+
Evaluate whether a Python package license permits redistribution in Red Hat products.
1012

11-
## Assessment Instructions
12-
13-
When a user provides a license name and asks about compatibility for redistribution, building wheels, or licensing restrictions, follow this methodology:
14-
15-
### Step-by-Step Process
16-
17-
1. **Fetch Current SPDX Data**:
18-
```
19-
Use WebFetch to query: https://raw.githubusercontent.com/spdx/license-list-data/main/json/licenses.json
20-
```
21-
22-
2. **License Matching**:
23-
- Try exact SPDX ID match first
24-
- Try case-insensitive SPDX ID match
25-
- Try full name matching
26-
- Try partial/fuzzy matching for common variations
27-
28-
3. **Risk Classification** (check strong copyleft FIRST to prevent misclassification):
29-
```
30-
IF (strong_copyleft_pattern):
31-
Risk = High, Status = Restricted/Incompatible
32-
# GPL, AGPL are ALWAYS restricted regardless of OSI/FSF status
33-
ELIF (NOT isOsiApproved):
34-
Risk = High, Status = Restricted/Incompatible
35-
ELIF (isOsiApproved AND weak_copyleft_pattern):
36-
Risk = Medium, Status = Compatible with Requirements
37-
ELIF (isOsiApproved AND isFsfLibre AND permissive_pattern):
38-
Risk = Low, Status = Compatible
39-
ELSE:
40-
Risk = High, Status = Unknown - requires manual review
41-
```
13+
**Policy basis**: Red Hat redistribution policy follows the Fedora Linux license
14+
policy. Use the Fedora License Data as the authoritative source -- NOT OSI-approval
15+
status.
4216

43-
4. **Generate Assessment**:
44-
- Include all SPDX metadata
45-
- Provide clear compatibility guidance
46-
- List specific requirements
47-
- Add Red Hat context where relevant
17+
## Inputs
4818

49-
## License Assessment Framework
19+
- **package_name**: Python package name
20+
- **source_available**: whether buildable source exists (if already known)
21+
- **upstream_org**: name and primary country of the maintaining organisation (if already known)
5022

51-
### Input Processing
52-
Accept various formats and normalize them:
53-
- **SPDX Identifiers**: "MIT", "Apache-2.0", "GPL-3.0-only"
54-
- **Full Names**: "MIT License", "Apache License 2.0", "GNU General Public License v3.0"
55-
- **Common Aliases**: "Apache 2", "BSD 3-Clause", "GPLv3"
56-
- **Case Variations**: Handle case-insensitive matching
23+
## Step 1: Locate and clone the source repository
5724

58-
### SPDX Data Analysis
59-
When processing SPDX license data, examine these key fields:
60-
- `licenseId`: Official SPDX identifier
61-
- `name`: Full license name
62-
- `isOsiApproved`: OSI approval status (boolean)
63-
- `isFsfLibre`: FSF Free Software status (boolean)
64-
- `isDeprecatedLicenseId`: Whether license is deprecated (boolean)
65-
- `reference`: URL to full license details
66-
- `seeAlso`: Array of additional reference URLs
25+
Use the python-packaging-source-finder skill to find the upstream repo URL:
6726

68-
### License Pattern Definitions
27+
```
28+
Skill: python-packaging-source-finder
29+
```
6930

70-
Use these explicit pattern lists for classification. Match against the SPDX `licenseId` field (case-insensitive).
31+
Then use the git-shallow-clone skill to clone the repository locally:
7132

72-
#### Permissive Patterns (permissive_pattern)
73-
Licenses where the `licenseId` contains or matches any of:
74-
- `MIT`, `Apache-`, `BSD-`, `ISC`, `Unlicense`, `0BSD`, `PSF-`, `Python-`, `Zlib`, `BSL-1.0`, `CC0-`, `WTFPL`, `MulanPSL-`
33+
```
34+
Skill: git-shallow-clone
35+
```
7536

76-
#### Weak Copyleft Patterns (weak_copyleft_pattern)
77-
Licenses where the `licenseId` contains or matches any of:
78-
- `LGPL-`, `MPL-`, `EPL-`, `CDDL-`, `CPL-`, `CeCILL-2.1`, `EUPL-`
37+
This gives a local path to the cloned repo for deterministic license inspection.
7938

80-
#### Strong Copyleft Patterns (strong_copyleft_pattern)
81-
Licenses where the `licenseId` contains or matches any of:
82-
- `GPL-` (but NOT `LGPL-`), `AGPL-`, `SSPL-`, `OSL-`, `CeCILL-` (but NOT `CeCILL-2.1`), `EUPL-` (when used with strong copyleft intent)
39+
## Step 2: Read the license from source
8340

84-
**CRITICAL**: `GPL-2.0`, `GPL-3.0`, `GPL-2.0-only`, `GPL-2.0-or-later`, `GPL-3.0-only`, `GPL-3.0-or-later` are ALL strong copyleft. They are NOT permissive. They MUST be classified as Restricted/Incompatible for commercial wheel redistribution.
41+
Search the cloned repo root for license files in this order:
42+
LICENSE, LICENSE.txt, LICENSE.md, COPYING, COPYING.txt, LICENCE, LICENCE.txt
8543

86-
### Compatibility Assessment Logic
44+
```bash
45+
find <clone_path> -maxdepth 1 -iname "license*" -o -iname "copying*" -o -iname "licence*" | head -5
46+
```
8747

88-
Use SPDX flags and the pattern definitions above to determine compatibility:
48+
Read the first 30 lines of the found file and map to an SPDX identifier.
8949

90-
#### ✅ Highly Compatible (Low Risk)
91-
- OSI Approved AND FSF Libre AND matches permissive_pattern
92-
- Examples: MIT, Apache-2.0, BSD-3-Clause, ISC, PSF-2.0
93-
- No copyleft requirements of any kind
50+
Also check `pyproject.toml` or `setup.cfg` for a `license` field as a secondary
51+
signal. If the PyPI metadata license differs from the source file, set
52+
Source verified: MISMATCH (PyPI: [X], repo: [Y]) and use the source file as
53+
authoritative.
9454

95-
#### ⚠️ Compatible with Requirements (Medium Risk)
96-
- OSI Approved AND matches weak_copyleft_pattern
97-
- Examples: LGPL-2.1-only, LGPL-3.0-or-later, MPL-2.0
98-
- File-level or library-level copyleft only
55+
**Normalise to SPDX ID** using exact then fuzzy matching:
56+
- "Apache 2" -> Apache-2.0, "GPL v2" -> GPL-2.0-only, "BSD" -> BSD-3-Clause,
57+
"GPLv3" -> GPL-3.0-or-later, "MIT License" -> MIT, "LGPLv2.1" -> LGPL-2.1-only
9958

100-
#### ❌ Restricted/High Risk
101-
- Matches strong_copyleft_pattern (GPL, AGPL) — regardless of OSI or FSF status
102-
- Non-OSI approved licenses
103-
- Proprietary or unclear terms
104-
- GPL licenses require ALL derivative works to be released under the same GPL license, making them incompatible with proprietary or commercial redistribution of binary wheels
59+
**Compound expressions**: If the license contains `AND` or `OR`:
60+
- `AND`: split and evaluate each component. Apply the license governing the
61+
importable library API (not a bundled CLI). Document the split in Notes.
62+
- `OR`: evaluate each component; use the most permissive allowed one. If none are
63+
allowed, the overall verdict is the best individual verdict.
10564

106-
### Output Format
65+
If no license file found and no SPDX mapping possible: Verdict: NEEDS-HUMAN-REVIEW.
10766

108-
Provide a structured assessment with:
109-
110-
1. **SPDX Information**:
111-
- Official SPDX ID
112-
- Full license name
113-
- OSI Approved: Yes/No
114-
- FSF Libre: Yes/No
115-
- Deprecated: Yes/No (if applicable)
116-
117-
2. **Compatibility Assessment**:
118-
- Status: Compatible/Restricted/Incompatible
119-
- Redistribution: Allowed/Restricted/Prohibited
120-
- Commercial Use: Allowed/Restricted/Prohibited
121-
122-
3. **Requirements**: Key compliance obligations
123-
4. **Risk Level**: Low/Medium/High for enterprise use
124-
5. **Red Hat Context**: Special considerations if applicable
67+
Clean up the clone when done:
12568

69+
```bash
70+
rm -rf <clone_parent_dir>
71+
```
12672

127-
## Red Hat Vendor Agreements
128-
129-
Red Hat has specific licensing agreements with the following hardware vendors:
73+
## Step 3: Look up license in Fedora License Data
13074

131-
- **NVIDIA**: Agreement covers CUDA libraries, runtimes, and related NVIDIA proprietary components
132-
- **Intel Gaudi**: Agreement covers Gaudi AI accelerator software and libraries
133-
- **IBM Spyre**: Agreement covers IBM Spyre AI hardware and associated software components
75+
Fetch the live data:
13476

135-
When evaluating packages with dependencies on these vendor-specific components, note that Red Hat has explicit redistribution rights under these agreements.
77+
```
78+
WebFetch: https://gitlab.com/fedora/legal/fedora-license-data/-/jobs/artifacts/main/raw/fedora-licenses.json?job=json
79+
```
13680

137-
## Error Handling
81+
Search for an entry matching the SPDX ID (case-insensitive on `spdx_abbrev`).
82+
Each entry has `status`: "allowed" or "not-allowed".
83+
84+
- `allowed` -> proceed to Step 4 (verdict refinement)
85+
- `not-allowed` -> Verdict: BLOCKED
86+
- not found -> Verdict: NEEDS-HUMAN-REVIEW
87+
88+
**Fallback table** (use only when the JSON fetch fails):
89+
90+
| Status | SPDX identifiers (representative) |
91+
|---|---|
92+
| allowed | MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, PSF-2.0, CC0-1.0 |
93+
| allowed | GPL-2.0-only, GPL-2.0-or-later, GPL-3.0-only, GPL-3.0-or-later |
94+
| allowed | LGPL-2.0-only, LGPL-2.1-only, LGPL-2.1-or-later, LGPL-3.0-or-later |
95+
| allowed | AGPL-3.0-only, AGPL-3.0-or-later, MPL-2.0, EUPL-1.2, EPL-2.0 |
96+
| not-allowed | SSPL-1.0, BUSL-1.1, Commons-Clause |
97+
| ESCALATE | Any custom/proprietary license not in SPDX |
13898

139-
### SPDX Data Fetch Failures
140-
If the SPDX license list cannot be retrieved, exit early and warn the user.
99+
When using fallback, append to Notes: "Fedora License Data unreachable; fallback
100+
table used. Verify at https://docs.fedoraproject.org/en-US/legal/allowed-licenses/"
141101

142-
### License Not Found in SPDX
143-
When a license identifier is not found in the SPDX license list:
144-
1. Check for common typos or variations
145-
2. Suggest SPDX-compliant alternatives
146-
3. Recommend contacting package maintainer
147-
4. Provide conservative risk assessment
102+
## Step 4: Verdict refinement (apply in order)
148103

149-
### Deprecated Licenses
150-
For deprecated SPDX licenses:
151-
1. Note the deprecation status
152-
2. Suggest migrating to current equivalent
153-
3. Provide assessment based on deprecated license terms
154-
4. Recommend updating package licensing
104+
**Rule A -- Proprietary or custom license** (not in Fedora data):
155105

156-
For complex licensing scenarios involving multiple packages or custom license terms, recommend consultation with legal counsel.
106+
First check the Vendor Agreements table below. If covered by an agreement:
107+
Verdict: ALLOWED, Notes: "Covered by Red Hat [Vendor] redistribution agreement."
157108

158-
## Integration Notes
109+
Otherwise:
110+
- Red Hat / IBM-owned upstream (e.g. Neural Magic):
111+
Verdict: ESCALATE-TO-LEGAL.
112+
Notes: "Red Hat-owned proprietary license. Must be relicensed before inclusion.
113+
Open a ServiceNow opensource-legal ticket."
114+
- Third-party proprietary:
115+
Verdict: ESCALATE-TO-LEGAL.
116+
Notes: "Third-party proprietary license. May be includable as a EULA-listed
117+
component. Open a legal-review task."
118+
119+
**Rule B -- AGPL-3.0** (status=allowed, SPDX is AGPL-3.0-only or -or-later):
120+
Verdict: ALLOWED-WITH-CAVEAT.
121+
Notes: "AGPL-3.0 is allowed for redistribution but is frequently part of a
122+
dual-licensing strategy, increasing risk. PM sign-off required."
123+
124+
**Rule C -- All other allowed licenses**:
125+
Verdict: ALLOWED. Notes: omit unless compliance note needed (e.g. LGPL dynamic
126+
linking does not propagate copyleft).
127+
128+
**Rule D -- Not-allowed**:
129+
Verdict: BLOCKED.
130+
Notes: "License is on the Fedora not-allowed list."
131+
132+
## Step 5: Compliance checks
133+
134+
**Build compliance** (independent of license verdict):
135+
If `source_available` is false or no buildable source exists (no setup.py,
136+
pyproject.toml, or equivalent):
137+
- Build compliance: BUILD-COMPLIANCE-FLAG
138+
- Append to Notes: "No buildable source. Options: (1) request upstream sdist,
139+
(2) make dependency optional,
140+
(3) file PSX exception with 6-month deadline per PSS.SBR.02.02."
141+
- Otherwise: Build compliance: OK
142+
143+
**Export compliance** (independent of license verdict):
144+
If upstream org's primary country is on the US OFAC sanctions list, EU Consolidated
145+
Sanctions List, or flagged by Red Hat geopolitical policy:
146+
- Export compliance: EXPORT-COMPLIANCE-FLAG
147+
- Append to Notes: "Upstream org may require export compliance review. Contact
148+
exportcompliance@redhat.com. Geopolitical sensitivity does not automatically block
149+
inclusion (precedent: Yandex/Russia cleared for catboost)."
150+
- Otherwise: Export compliance: OK
151+
152+
## Output Format
153+
154+
Produce ONLY this six-field block. No preamble, no extra text.
155+
156+
```
157+
_License:_ [SPDX expression, or "non-SPDX: [raw string]" if unmappable]
158+
_Source verified:_ YES | NO | MISMATCH (PyPI: [X], repo: [Y])
159+
_Verdict:_ ALLOWED | ALLOWED-WITH-CAVEAT | NEEDS-HUMAN-REVIEW | ESCALATE-TO-LEGAL | BLOCKED
160+
_Build compliance:_ OK | BUILD-COMPLIANCE-FLAG
161+
_Export compliance:_ OK | EXPORT-COMPLIANCE-FLAG
162+
_Notes:_ [Actionable guidance. Omit if verdict is ALLOWED and all flags are OK.]
163+
```
164+
165+
## Vendor Agreements
166+
167+
| Vendor | Covered components |
168+
|---|---|
169+
| NVIDIA | CUDA libraries, runtimes, NCCL, and related NVIDIA components |
170+
| Intel Gaudi | Gaudi AI accelerator software and libraries |
171+
| IBM Spyre | IBM Spyre AI hardware and associated software components |
172+
173+
## Quick Reference
174+
175+
| Scenario | Verdict | Build | Export |
176+
|---|---|---|---|
177+
| MIT, Apache-2.0, BSD-*, ISC, PSF-2.0 | ALLOWED | OK | OK |
178+
| GPL-*, LGPL-* | ALLOWED | OK | OK |
179+
| AGPL-3.0-* | ALLOWED-WITH-CAVEAT | OK | OK |
180+
| SSPL-1.0, BUSL-1.1, Commons-Clause | BLOCKED | -- | -- |
181+
| RH-owned proprietary | ESCALATE-TO-LEGAL | -- | -- |
182+
| Third-party proprietary (no vendor agreement) | ESCALATE-TO-LEGAL | -- | -- |
183+
| PyPI/repo license mismatch | per repo license (MISMATCH noted) | OK | OK |
184+
| No buildable source | per license | FLAG | OK |
185+
| OFAC/sanctions-flagged upstream | per license | OK | FLAG |
186+
187+
## Error Handling
159188

160-
This skill works best when combined with:
161-
- **python-packaging-license-finder** - Use to find license names before compatibility assessment
189+
- **Fedora data unreachable**: Use fallback table; append note.
190+
- **Source repo not found**: If python-packaging-source-finder returns null/low
191+
confidence, set Source verified: NO, verdict: NEEDS-HUMAN-REVIEW.
192+
- **Source repo private/inaccessible**: Set Source verified: NO. Verdict:
193+
NEEDS-HUMAN-REVIEW.
194+
- **Multiple conflicting LICENSE files**: Source verified: MISMATCH, verdict:
195+
NEEDS-HUMAN-REVIEW. Note the conflicting files.

0 commit comments

Comments
 (0)