Metadata-Version: 2.4
Name: copyleft-audit
Version: 0.1.1
Summary: Fail your CI build when a dependency's licence breaks policy. Detects GPL, AGPL, SSPL and LGPL in installed packages. Zero dependencies, stdlib only.
Project-URL: Homepage, https://pypi.org/project/copyleft-audit/
Project-URL: Changelog, https://pypi.org/project/copyleft-audit/#history
Keywords: copyleft,gpl,agpl,lgpl,sspl,license,licence,license-compliance,license-checker,open-source-compliance,sbom,ci,audit,due-diligence,dependencies
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Legal Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: System :: Software Distribution
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# copyleft-audit

**Fail your CI build when a dependency's licence breaks policy.**
Detects GPL, AGPL, SSPL, LGPL, MPL and friends in the packages actually
installed in your environment — and exits non-zero so the pipeline stops.

Zero runtime dependencies. Standard library only. It will not touch your
dependency tree, and it makes no network calls.

```bash
pip install copyleft-audit
copyleft-audit
```

## Why this exists

`pip-licenses` and similar tools *list* licences for a human to read. That is a
different job from *enforcing* a policy in CI. If you ship closed-source
software, the question is not "what licences are in here" but "does the build
stop when someone adds an AGPL package". This tool answers the second question:
one command, an exit code, no configuration file required.

Typical triggers for needing it: legal asks you to prove no copyleft code ships
in the product; an acquirer's due-diligence checklist asks the same; or you just
want the check to run automatically instead of once a year.

## Usage

```
copyleft-audit [--fail-on {strong,weak,unknown}] [--ignore PKG[,PKG...]]
               [--format {text,json}] [--quiet]
```

| Exit code | Meaning |
|---|---|
| `0` | Clean — no policy violations |
| `1` | Policy violation |
| `2` | Usage or internal error |

GitHub Actions:

```yaml
- name: Licence gate
  run: |
    pip install copyleft-audit
    copyleft-audit --fail-on strong
```

Stricter, for a product that cannot even take weak copyleft or unresolvable
metadata:

```bash
copyleft-audit --fail-on unknown --ignore mypackage,internal-sdk
```

Machine-readable output, for feeding another tool:

```bash
copyleft-audit --format json
```

```json
{
  "packages":  [{"name": "...", "version": "...", "license": "...",
                 "license_source": "...", "tier": "...", "ignored": false}],
  "violations": ["... same shape ..."],
  "warnings":   ["... same shape ..."],
  "summary":   {"tool_version": "...", "fail_on": "strong", "scanned": 0,
                "unreadable": 0, "ignored": [], "counts": {}, 
                "violation_count": 0, "warning_count": 0, "exit_code": 0}
}
```

The JSON schema is stable within the `0.1.x` line; new keys may be added, and
existing keys will not change meaning without a version bump.

## Risk tiers

| Tier | Licences | Default |
|---|---|---|
| `STRONG_COPYLEFT` | GPL-2.0, GPL-3.0, AGPL-3.0, SSPL, OSL, EUPL | **fail** |
| `WEAK_COPYLEFT` | LGPL-2.1, LGPL-3.0, MPL-2.0, EPL-2.0, CDDL, CPL | warn |
| `PERMISSIVE` | MIT, BSD, Apache-2.0, ISC, PSF, Unlicense, CC0, Zlib, … | pass |
| `UNKNOWN` | no resolvable licence metadata | warn |

`--fail-on weak` promotes weak copyleft to a failure. `--fail-on unknown`
promotes both weak copyleft and unknown metadata to a failure.

## How it decides, precisely

Licence metadata is read in this order, and the first source that resolves wins:
`License-Expression` (PEP 639) → `License ::` trove classifiers → the free-text
`License` field. The source used is reported in `license_source`, so you can see
what the verdict rests on.

Deliberate design choices worth knowing about:

- **`UNKNOWN` is a real answer.** When metadata is missing, empty, or not
  recognised, the tool says `UNKNOWN`. It never guesses a tier. A confident
  wrong answer here would be worse than no answer.
- **A package whose metadata cannot be parsed is reported as `UNKNOWN`, never
  skipped.** Silently dropping a package would produce a false clean report.
- **`LGPL` and `AGPL` are never read as `GPL`.** Matching is on whole tokens and
  masked phrases, not substrings — the classic mis-tiering bug in naive
  scanners.
- **`MIT OR GPL-3.0` resolves to permissive**, because you may take the MIT
  option. `AND` resolves to the stricter operand. Parenthesised SPDX expressions
  are not parsed and are scored conservatively (highest risk wins).
- **Multiple licence classifiers are read as a choice**, so the lowest-risk one
  governs — but every licence string found is printed, so nothing is hidden.

## Limits — please read before trusting it

- It reads **declared package metadata only**. It does not scan source files,
  vendored code, bundled binaries, or transitively linked native libraries. A
  package that declares MIT while vendoring GPL code will read as MIT.
- It classifies what is **installed in the current environment**, so run it in
  the same environment your build produces.
- **This is not legal advice**, and the output is not a legal opinion. It is a
  metadata heuristic that helps engineers catch the obvious cases early. Real
  licence compliance decisions belong with your counsel.

## Paid: auditor-ready attestation report

The tool is free and stays free — nothing is gated behind payment.

If you need the output as a **document you can hand to an acquirer, an auditor,
or your own legal team**, there is a one-time paid report for a single project:
every installed dependency with its declared licence, the metadata field that
licence was read from, its risk tier, and an explicit list of everything that
came back `UNKNOWN` with what is missing. Delivered as PDF plus the raw JSON.
$149, one project, one-time.

→ **[Order the attestation report](https://buy.stripe.com/3cI8wP9libJt5Xrdd7a7C08)**

Same honesty applies: the report documents declared metadata, and it is not a
legal opinion.

## Disclosure

This package was written by an AI agent (Claude) operating autonomously, and is
published and maintained under human ownership. It is deliberately small,
dependency-free and standard-library-only so that it can be read end to end and
verified by inspection before you trust it in a pipeline. Please do read it.

Licensed MIT.
