Skip to content
Back to skills

License Audit

ASecurity

Scan the dependency tree for license-policy violations — copyleft in proprietary, unknown licenses, license downgrades. Use before release, during a compliance review, or when adding a new dependency.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentspythonrustgobash

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add bakw00ds/yakos --skill license-audit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of License Audit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for License Audit
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bakw00ds-license-audit/badge)](https://www.skillsdirectory.com/skills/bakw00ds-license-audit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: license-audit
description: Scan the dependency tree for license-policy violations — copyleft in proprietary, unknown licenses, license downgrades. Use before release, during a compliance review, or when adding a new dependency.
allowed-tools: Bash Read
argument-hint: "[--policy <file>] [--baseline <file>] [--ecosystem npm|pip|cargo|go|maven]"
mode: [audit]
---

# License Audit

## Purpose

Scan the project's dependency tree against a license policy file and
report violations: copyleft licenses (GPL/AGPL/SSPL) in a proprietary
codebase, unknown / missing licenses, license downgrades on update
(e.g., MIT→GPL), and unapproved license families. Primary consumer:
`supply-chain-auditor` (audit) and `maintainer` (gate on dep-update PRs).

## Scope

- Reads the project's lock file (package-lock.json, pnpm-lock.yaml,
  poetry.lock, Cargo.lock, go.sum, etc.) and resolves declared
  licenses for every direct + transitive dependency.
- Compares each license against `.claude/license-policy.json`
  (project-supplied).
- Diffs against a previous-run baseline to flag downgrades.
- Emits a markdown report with categorized findings; exits non-zero
  if any blocking violation exists.

## When to use

- On every dep-update PR, as a CI gate.
- Before a release, against the locked dep set going to prod.
- When onboarding a new dep — manually, before the dep is added.
- For compliance audits (open-source-program-office reviews,
  acquisition due-diligence, customer license inquiries).

## When NOT to use

- For pure internal tooling that ships nothing externally — copyleft
  obligations attach to distribution. Verify with legal that "no
  external distribution" applies before opting out.
- As a replacement for legal review — this skill flags the obvious
  cases. Edge cases (dual-licensed deps, license-with-exception,
  patent-grant clauses) need a human lawyer.

## Automated pass

1. Detect ecosystem and locate lockfile:
   ```sh
   case "${ECOSYSTEM:-auto}" in
       npm)   lockfile="package-lock.json" ;;
       pip)   lockfile="poetry.lock" ;;
       cargo) lockfile="Cargo.lock" ;;
       go)    lockfile="go.sum" ;;
       maven) lockfile="pom.xml" ;;
       auto)
           for f in package-lock.json pnpm-lock.yaml poetry.lock \
                    Cargo.lock go.sum pom.xml; do
               [ -f "$f" ] && lockfile="$f" && break
           done
           ;;
   esac
   ```

2. Run the ecosystem-native scanner. Tool choice per ecosystem:
   ```sh
   # npm / pnpm
   npx license-checker --json > /tmp/licenses.json
   # python
   pip-licenses --format=json > /tmp/licenses.json
   # rust
   cargo deny check licenses --format json > /tmp/licenses.json
   # go
   go-licenses report ./... > /tmp/licenses.json
   # maven
   mvn license:aggregate-add-third-party
   ```

3. Load the policy:
   ```sh
   policy="${POLICY:-.claude/license-policy.json}"
   # Expected shape:
   # {
   #   "allow":  ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC"],
   #   "warn":   ["MPL-2.0", "LGPL-2.1", "LGPL-3.0"],
   #   "deny":   ["GPL-2.0", "GPL-3.0", "AGPL-3.0", "SSPL-1.0", "BUSL-1.1"],
   #   "unknown_policy": "deny"
   # }
   ```

4. Classify every dep:
   - In `allow` → ok.
   - In `warn` → finding, severity warn.
   - In `deny` → finding, severity err, blocks merge.
   - Not in any list AND `unknown_policy: deny` → finding, severity err.
   - License field empty / "UNKNOWN" → finding, severity err
     regardless of policy (auditor must resolve).

5. Diff against baseline (`--baseline` or last run cached at
   `.claude/license-baseline.json`). For each dep, compare the
   license; if it changed, classify the change:
   - **Downgrade** (MIT → GPL, BSD → AGPL, etc.) → severity err.
   - **Upgrade** (GPL → MIT) → severity info.
   - **Cosmetic** (Apache-2.0 → Apache 2.0) → ignore.

6. Compose markdown report:
   - Summary: count by severity, total deps audited, policy file,
     baseline file.
   - Section: blocking findings (deny + downgrade + unknown).
   - Section: warn-level findings.
   - Section: changes since baseline.
   - Per-finding: dep name, version, license (SPDX id),
     direct-or-transitive, parent if transitive, suggested
     remediation (replace dep / pin to last-acceptable version /
     get legal sign-off / update policy).

7. Exit non-zero if any err-level finding. CI gates on the exit code.

## Manual pass

For a quick read on the current license mix:

```sh
npx license-checker --summary           # npm
pip-licenses --summary                  # python
cargo deny check licenses               # rust
go-licenses csv ./... | sort -t, -k3    # go (group by license)
```

…or to investigate one suspect dep:

```sh
npx license-checker --packages "left-pad@1.3.0" --json | jq
```

## Known gotchas

- **SPDX ids vs free-text.** Older deps declare `"License: BSD"`
  ambiguously (could be 2-clause, 3-clause, original-with-
  advertising-clause). Treat ambiguous strings as `unknown` and
  resolve manually — the difference matters legally.
- **Dual-licensed deps.** A dep offered under "MIT OR GPL-3.0" is
  fine if you choose MIT, but the lockfile may not record the
  choice. Document the chosen license in
  `.claude/license-choices.json`; the skill respects that file.
- **License-with-exception.** GPL-2.0-with-classpath-exception is
  not GPL-2.0 for linking purposes. The deny list should target
  the SPDX identifier exactly; don't substring-match "GPL".
- **Transitive churn on minor bumps.** A patch-level bump of a
  direct dep can pull in a new transitive with a different
  license. Always re-run audit on dep updates, not just on
  direct-dep additions.
- **Vendored deps.** Code copy-pasted into the repo (`vendor/`,
  `third_party/`) doesn't appear in the lockfile. The skill does
  NOT scan vendored sources; configure a separate scanner
  (scancode-toolkit) for that.
- **Private deps.** Internal monorepo packages often have no
  license declaration. Add them to `.claude/license-policy.json`
  under `internal:` to suppress noise.

## References

- `lib/agents/supply-chain-auditor.md` — primary consumer.
- `lib/agents/maintainer.md` — gates dep-update PRs on this skill.
- SPDX license list: https://spdx.org/licenses/
- `.claude/license-policy.json` (project-supplied).
- `.claude/license-baseline.json` (regenerated by this skill).
- `lib/skills/dependency-update/SKILL.md` — pairs with this skill
  in the dep-update flow.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…