license-check¶
End-to-End-Lizenz-Compliance-Check: SBOM, SPDX-Klassifizierung, allow/review/deny-Gate, Remediation, NOTICE und ein Audit-Artefakt.
Run an end-to-end license-compliance check on the current project per spec/project/license-check/ and produce a license-check audit artifact. Dispatches license-check-scanner agent for the read-only inventory (SBOM with resolved licenses, SPDX identification, category classification), then applies the permissive-leaning allow/review/deny policy gate against the project's own outbound license, drives per-finding remediation (replace / exception with rationale / satisfy the obligation), verifies attribution/NOTICE and REUSE, records AI provenance, and writes the artifact under .audits/license-check/. Invoke when the user asks to "run a license check," "check license compliance," "audit licenses," "do a Lizenzcheck," "prüfe die Lizenzen," or for a pre-PR / pre-release license gate. Don't use for CVE / vulnerability scanning (that's dependency-audit) or for choosing the project's own outbound license. Supports resume on re-invocation per spec/claude/resumable-work/.
- Plugin:
nolte-engineering - Phase: 6 Quality (
quality) - Tags:
audit - Quelle: skills/license-check/SKILL.md
Anwenden wenn¶
- you want a full license-compliance check on the current project
- you want a pre-PR or pre-release license gate with an allow/review/deny policy
- you want to verify own-code REUSE state, attribution/NOTICE, and AI provenance
Nicht anwenden wenn¶
- You want a CVE / vulnerability scan →
dependency-audit - You want to choose or change the project's own outbound license →
project-structure-apply
Siehe auch¶
Referenziert von¶
License Check¶
Run the end-to-end license-compliance process on the current project and produce a single license-check audit artifact. This skill reports, gates, and (with confirmation) drives remediation; it never edits a LICENSE, allowlist, or dependency on its own.
Implements spec/project/license-check/ — the spec defines the pipeline, the SPDX anchoring, the license categories and their obligations, the compatibility rules, the default policy, and the AI-provenance requirements. This skill is the license-compliance authority; dependency-audit's license pass implements this spec's policy for the dependency slice only.
German trigger phrases¶
This skill also triggers on equivalent German-language requests, including:
- "Lizenzcheck durchführen" / "ausführlichen Lizenzcheck machen"
- "Lizenz-Compliance prüfen"
- "Lizenzen auditieren"
User-language policy¶
Detect the user's language from their message and respond in it. The audit artifact uses English section headings (so downstream tooling can parse it reliably); prose around it is localised.
Inputs¶
- Repo root: default is the current working directory.
- Outbound license: read from the root
LICENSE. This is the compatibility anchor; every conveyed dependency is checked against it. Stop and ask when noLICENSEexists rather than guessing. - Policy: the permissive-leaning default from
spec/project/license-check/§Default policy, overridable only by a recorded, rationale-bearing repository policy.
The pipeline¶
Run the spec's ordered chain; each stage consumes the previous one:
Inventory/Discovery → SBOM → SPDX identification → classification → policy gate → remediation → attribution/NOTICE → continuous CI check
The SBOM stage is generated by this skill (it may install and write); the inventory, SPDX-identification, and classification stages are delegated to the read-only scanner agent; the policy gate through the CI check stay in this skill.
Operations¶
0. Generate the SBOM, then dispatch the read-only scan agent¶
First generate the SBOM yourself — a skill may install and write, the read-only scanner agent may not. Run the repo's task license:sbom target when it exists; otherwise generate per stack (Python: cyclonedx-py environment against an ephemeral venv, removed after; Node: cyclonedx-node-npm; Go: cyclonedx-gomod). Use the Python environment mode, not requirements mode, because only the former resolves licenses, including transitive ones.
Then dispatch license-check-scanner (Agent) for the read-only inventory, passing the repo root, the generated SBOM path, and the outbound license read in Inputs. The agent reads the SBOM, maps every component to a canonical SPDX identifier, classifies each into a category, resolves any remaining gaps read-only, and returns the project's own outbound license plus REUSE state and AI-provenance hints. Wait for its inventory before applying the gate.
1. Determine conveyed vs. arm's-length¶
Per spec/project/license-check/ §Scope, mark every component the scanner returned as either conveyed (shipped, linked, or offered over a network as part of the product) or executed at arm's length (build / dev / docs / CI tool, not shipped). When the use context can't be determined, record unknown-use-context and route the component to review. This distinction decides whether a strong-/network-copyleft finding is deny or review.
2. Apply the policy gate¶
Apply the three-tier default policy from the spec, anchored to the outbound license:
- allow (passes automatically): the permissive and public-domain categories (the default allowlist is SPDX-anchored and seeded from the CNCF set:
0BSD, BSD-2-Clause, BSD-3-Clause, MIT, MIT-0, ISC, Apache-2.0, PSF-2.0, Python-2.0, PostgreSQL, Zlib, X11, Unlicense, CC0-1.0). - review (manual decision, gate is
blockednotpass): weak/file-level copyleft; source-available / restricted; open-weight model licenses; the BSD-4-Clause advertising-clause exception; anyLicenseRef-*/NOASSERTION; any combination not positively confirmed compatible with the outbound license; strong-/network-copyleft components that are arm's-length only. - deny (fails automatically): strong copyleft (GPL family) and network copyleft (AGPL) in any conveyed, linked, or networked component.
Run the compatibility checks from the spec against the outbound license (for example: Apache-2.0 may go into a GPLv3 work but not the reverse; Apache-2.0 is incompatible with GPLv2). Route any combination you can't positively confirm to review. Never downgrade a category on local judgement; disagreement is a recorded exception with rationale, not a reclassification.
3. Remediate (per non-allow finding, with confirmation)¶
Per spec/project/license-check/ §Remediation, every non-allow finding gets exactly one of three responses inside a bounded window. Don't execute any of these without explicit confirmation:
- replace: swap the component for a compatibly-licensed alternative.
- exception with rationale: record a named, time-bounded (
valid-until, ISO 8601) exception with a one-line rationale and the approver; permitted forreviewfindings and, only with explicit sign-off, for a deny-tier override. Revisit each on itsvalid-untildate; never renew without a fresh rationale. - satisfy the obligation: keep the component and produce what its license requires (attribution/NOTICE entry; source-availability offer; relink-capable form for LGPL).
Never silence a finding by editing the allowlist without a rationale or by reclassifying the license.
4. Own-code, attribution/NOTICE, and AI provenance¶
- Confirm the root
LICENSEdeclares a valid outbound SPDX identifier, and report the REUSE state the scanner returned (LICENSES/<id>.txt+ per-file or blanketREUSE.toml). When REUSE is not configured, record it as aSHOULDgap. - Verify the third-party attribution/NOTICE output the dependency licenses oblige exists. The verified cross-stack default generator is the ORT reporter's NOTICE templates (
PlainTextTemplate/NOTICE_SUMMARY); for Go,go-licenses save. For Apache-2.0 dependencies, confirmNOTICEcontents are propagated. When the plugin/product ships no third-party code, record that no third-party NOTICE is obligated. - Record machine-readable AI provenance for every committed AI-generated artefact (generator / model / tier). Classify open-weight model licenses as
review, notallow, and pin the model artefact version. Keep "license laundering" framing labelled as interpretation, not as a primary-source claim.
5. Persist the audit artifact¶
Per spec/project/license-check/ §Audit artifact, write the result to the portfolio-wide .audits/license-check/ path (default .audits/license-check/license-YYYY-MM-DD.md). The artifact MUST record: date; trigger (pre-PR / pre-release / manifest-change); scope (stacks and subroots checked / skipped, with reasons); the tool(s) and version(s) used; the pinned SPDX License List version; the per-component SPDX identifier, category, policy tier, and response decision; the conveyed/arm's-length status of every strong-/network-copyleft component; and the Git revision checked. Link to the prior artifact so the progression stays traceable.
6. Gate result and CI¶
Report the gate result: pass (no deny, every non-allow finding has a response) or blocked (open review findings or an unaddressed deny). Per the spec, the check runs in CI on changes to a dependency manifest, lockfile, the LICENSE file, or committed AI-generated artefacts, and before every release tag; it shares cadence and artifact conventions with dependency-audit rather than duplicating it.
Report shape¶
```text
License Check¶
Scope: ,
Trigger:
Git revision:
Policy gate¶
- allow:
- review:
(blocked until each has a response) - deny:
(must be replaced or under a signed-off, time-bounded exception)
Findings (non-allow only, grouped by tier)¶
deny — ¶
@ —— — use-context: — response: , approver \ ) | satisfy>
review — ¶
(same structure)
Own code & attribution¶
- Outbound LICENSE:
(valid: yes/no) - REUSE:
(LICENSES/, REUSE.toml) - Third-party NOTICE:
AI provenance¶
— — output license: — provenance recorded: yes/no - Open-weight model licenses:
Verdict¶
Gotchas¶
- A license SBOM needs resolved licenses, not just a dependency list.
cyclonedx-py requirementslists components without licenses; onlycyclonedx-py environment(against an installed venv) or the repo'stask license:sbomtarget resolves licenses, including transitive ones. The scanner preferstask license:sbom; verify the SBOM's "components with resolved license" count matches the component count before trusting a clean result. - Transitive copyleft hides behind permissive top-level manifests. A top-level-only scan misses weak-copyleft transitives (for example
certifi/pathspecunder MPL-2.0). Always gate on the transitive SBOM, not the manifest. - The conveyed/arm's-length split is the load-bearing decision for copyleft. The same GPL tool is
denywhen shipped andreviewwhen only executed at build time. Decide it per component; default toreview(unknown-use-context) when unsure, never toallow. go-licensesand Syft can mislabel.go-licenseswarns on non-Go code (which can conceal further requirements) and can fail to resolve a license URL; Syft historically marked unmatched license text as "unlicensed" before itsinclude-unknown-license-contentoption. Treat any unresolved component asreview, never a silent pass.- The FSF static=dynamic-linking position is the conservative default, not settled law. Use it to gate, but record in the artifact that it is the FSF interpretation.
Examples¶
- Read
examples/01-permissive-python-pass.mdwhen running the first check on a permissive project that should pass cleanly. - Read
examples/02-transitive-mpl-review.mdwhen a transitive dependency carries weak (file-level) copyleft and must be routed toreview. - Read
examples/03-conveyed-gpl-deny.mdwhen a conveyed component carries strong copyleft and the gate mustdenyit.
Resumability¶
Per spec/claude/resumable-work/, this skill is resumable: true. State is persisted to .resume/license-check/<run-id>.yml after every successful user-approval gate and after each named phase boundary. On re-invocation, scan that directory for files with status: in_progress whose inputs: snapshot matches the current invocation; if one matches, prompt the operator with Resume run <run_id> from phase <phase> (last checkpoint <last_checkpoint_at>)? [resume / start-new / discard]. The state-file envelope (schema_version, run_id, inputs, phase, decisions[], status, ...) and the fail-closed semantics on schema or YAML errors are load-bearing in the spec; don't duplicate those rules here.
Source triangulation¶
Per spec/claude/research-triangulate/, before this skill presents any repo-external assertion beyond a tool's own machine-readable output — a license's compatibility ruling, an SPDX identifier resolved by hand, or a generator's output-license terms — triangulate it instead of trusting a single source:
- Independent sources by blast radius. At least two independent sources; at least three when the assertion will direct a write outside the working copy (a deny-tier override, a sister-repo path).
- Anchor in SPDX. Resolve a license's full text via its SPDX identifier (
spdx.org/licenses/<ID>.json) so the obligations behind any finding are checkable; pin the SPDX List version in the artifact. - Surface conflicts, never silent-vote. When sources disagree on a license's category or compatibility, name the most likely explanation and let the operator decide.
- Mark
unverifiedwhen under-triangulated. If the required source count is unreachable, mark the assertionunverifiedand route the component toreview.
Hard rules¶
- Never edit a
LICENSE,REUSE.toml, allowlist, NOTICE, or dependency without explicit user confirmation. This skill reports and gates; mutations are a confirmed follow-up. - Never place a conveyed or networked strong-/network-copyleft component in
allow. It isdenyunless replaced or under a signed-off, time-bounded exception. - Never downgrade a license's category on local judgement. Disagreement is a recorded exception with rationale, not a reclassification.
- Never treat an unresolved or unmatched license as a clean pass. It is
review. - Never classify an open-weight model license (OpenRAIL / Llama / Gemma custom terms) as
allow; it isreview, with the model artefact version pinned. - Never run a CVE / vulnerability scan or duplicate
dependency-audit; consume its license pass as an implementer of this spec's policy, not as a competing authority. - Always anchor every finding in a canonical SPDX identifier (or an explicit
LicenseRef-*/NOASSERTION) whose full text is resolvable. - Always gate on the transitive SBOM, and record the conveyed/arm's-length status of every copyleft finding.
- Always persist the audit artifact under
.audits/license-check/with the pinned SPDX List version and the Git revision. - When
spec/project/license-check/and this skill disagree, the spec wins; this skill needs the update.
Why this is a skill, not an agent¶
This skill follows the hybrid pattern: the read-only inventory phase is delegated to the license-check-scanner agent (context-window isolation, tool restriction), while the policy gate and follow-up actions stay in the skill.
- Orchestration role: typical callers run this as one step inside a larger flow (pre-PR gate, release cut, periodic compliance review); the output flows back into the main conversation so the operator can triage.
- Mid-flow interactivity: the remediation actions in Step 3 need per-finding user approval — replacing a dependency, recording a dated exception, generating a NOTICE — so the interactivity favours the skill side.
- Persistent artifact: the deliverable is an on-disk audit artifact under
.audits/license-check/; skills own persistent state. - Hybrid split: the pure inventory half (detect stack, generate SBOM, resolve SPDX, classify) is self-contained and benefits from context-window isolation; the
license-check-scanneragent handles it. The policy gate and remediation stay here so the operator can decide each tier interactively.