Skip to content

fix: evaluate combined license strings per component in the license check - #95

Merged
JarbasAl merged 1 commit into
devfrom
fix/license-check-combined-strings
Sep 2, 2026
Merged

fix: evaluate combined license strings per component in the license check#95
JarbasAl merged 1 commit into
devfrom
fix/license-check-combined-strings

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Sep 1, 2026

Copy link
Copy Markdown
Member

🤖 Auto-generated by Claude Fable 5 (claude-fable-5) via Claude Code — NOT human-reviewed. Verify before acting.

The bug

license-check.yml classifies each dependency by matching regexes against its whole license string, and exclude_licenses (default ^Mozilla Public License.*) is anchored at the start of that whole string. A package that reports a COMBINED license — e.g. orjson's Apache Software License, MIT License, Mozilla Public License 2.0 (MPL 2.0) — starts with "Apache", not "Mozilla", so the exclude regex never matches even though the only non-permissive component (MPL) is exactly what it is meant to allow. The dependency lands in WeakCopyleft and the job fails, even when every actual component license is permitted.

This was live on LeMetadatarr/py-music-assistant's license_check job (its only failing job, pinned to an older gh-automations@dev ref, before orjson was added to the central per-package whitelist here). orjson is already whitelisted by name in the current central list (PR #86), which sidesteps this specific case — but the underlying bug is generic: any package with a combined license string and a repo-specific exclude_licenses pattern hits the same anchoring failure, and the central whitelist can't be extended forever for every future combined-license package.

The fix

Added a step, Detect combined-license packages safe by component, that runs before the exclude regex is built:

  • For each installed package's License field, split it into components only when it actually contains more than one (comma/AND/OR separated) — a single-license string is skipped entirely and falls through to the existing pilosus check exactly as before.
  • Classify each component using a Python port of pilosus's own category regex lists (pip_license_checker.license), same precedence: NetworkCopyleft > StrongCopyleft > WeakCopyleft > Permissive > Other.
  • A component whose category is in fail_licenses must be matched by the caller's exclude_licenses regex (re.search, evaluated against that component alone — not the whole string) for the package to be considered safe.
  • If every offending component clears that bar, the package is added to the same exclude-by-name mechanism already used for the central whitelist, so pilosus skips it entirely instead of ever seeing the ambiguous combined string.

Compatibility

Single-license strings are untouched: the new step only acts when a License field splits into 2+ components, so a currently-passing (or currently-failing) repo with plain single-license dependencies sees no change in outcome. Verified locally against three cases:

  • orjson's combined string (Apache Software License, MIT License, Mozilla Public License 2.0 (MPL 2.0)) with the default exclude_licenses → now excluded (previously failed).
  • A plain MIT License string → fewer than 2 components, step is a no-op, behaves exactly as before.
  • A combined string with a real copyleft violation (MIT License, GNU General Public License v3 (GPLv3)) against the default exclude_licenses → still NOT excluded, still fails as it should.

(Local harness used to check this, not committed — a standalone script reproducing the three cases above with the same classifier code as the workflow step.)

YAML validated with python3 -c "import yaml; yaml.safe_load(open('.github/workflows/license-check.yml'))".

…heck

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@JarbasAl
JarbasAl marked this pull request as ready for review September 2, 2026 00:01
@JarbasAl
JarbasAl merged commit 196320e into dev Sep 2, 2026
1 check passed
@JarbasAl
JarbasAl deleted the fix/license-check-combined-strings branch September 2, 2026 00:01
JarbasAl added a commit that referenced this pull request Sep 2, 2026
The combined-license-detection step added in #95 defines FAIL_LICENSES
and EXCLUDE_LICENSES as env vars but reads them as bare Python names,
raising NameError: name 'FAIL_LICENSES' is not defined in every caller
repo's license_check job. Read them via os.environ.get(), matching how
the rest of the script accesses its env vars.

Reproduced locally: extracting the inline script and running it with
FAIL_LICENSES/EXCLUDE_LICENSES set as env vars (no read of the bare
name) raises NameError before the fix and exits 0 after.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant