{"_id":"@beneficialtechnology/repo-ip-auditor","_rev":"3-1ce777e133579aca13993e94fbfdfeb3","name":"@beneficialtechnology/repo-ip-auditor","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.1":{"name":"@beneficialtechnology/repo-ip-auditor","version":"0.1.1","keywords":["ip","license","copyleft","agpl","due-diligence","git","compliance","sbom"],"author":{"name":"Beneficial Technology"},"license":"MIT","_id":"@beneficialtechnology/repo-ip-auditor@0.1.1","maintainers":[{"name":"beneficialtechnology","email":"tyler@beneficial.technology"}],"homepage":"https://beneficial.technology/tools/repo-ip-auditor","bugs":{"url":"https://github.com/Beneficial-Technology/repo-ip-auditor/issues"},"bin":{"repo-ip-audit":"dist/cli.js"},"dist":{"shasum":"d1dc869c1788fac4cc402319b55ee5eb0c6e369b","tarball":"https://registry.npmjs.org/@beneficialtechnology/repo-ip-auditor/-/repo-ip-auditor-0.1.1.tgz","fileCount":36,"integrity":"sha512-KQGbdmIRgnKHCjxyYwFM4ncRmK2hVPFM8Zn4zXaGEX5Dw5mMziCE6XGNWF/TP//laax18aYLjI3ZcND6g95sGw==","signatures":[{"sig":"MEYCIQCd9uvgAKQXdgOLPKz0+IWta877UqJPzjcJu8n/0USBJAIhAKxz1gXt0GVNlbzeLJQ/SULIk3j7WS4V271XCEidi7Ki","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70405},"main":"dist/audit.js","type":"module","types":"dist/audit.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/audit.d.ts","import":"./dist/audit.js"},"./core":{"types":"./dist/core.d.ts","import":"./dist/core.js"}},"gitHead":"9547d8e043288cfb75d75c4e9ace97ef2b49cec5","scripts":{"test":"node dist/cli.js . --offline --min-score 1","build":"tsc","audit:self":"node dist/cli.js .","prepublishOnly":"tsc"},"_npmUser":{"name":"beneficialtechnology","email":"tyler@beneficial.technology"},"repository":{"url":"git+https://github.com/Beneficial-Technology/repo-ip-auditor.git","type":"git"},"_npmVersion":"11.13.0","description":"Audit a git repository for IP chain-of-title gaps and copyleft exposure before diligence does.","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"5.6.3","@types/node":"22.7.5","@types/react":"^18.3.12"},"_npmOperationalInternal":{"tmp":"tmp/repo-ip-auditor_0.1.1_1788021239316_0.3135705617480473","host":"s3://npm-registry-packages-npm-production"},"deprecated":"mailmap support was non-functional; use 0.1.2"},"0.1.2":{"name":"@beneficialtechnology/repo-ip-auditor","version":"0.1.2","keywords":["ip","license","copyleft","agpl","due-diligence","git","compliance","sbom"],"author":{"name":"Beneficial Technology"},"license":"MIT","_id":"@beneficialtechnology/repo-ip-auditor@0.1.2","maintainers":[{"name":"beneficialtechnology","email":"tyler@beneficial.technology"}],"homepage":"https://beneficial.technology/tools/repo-ip-auditor","bugs":{"url":"https://github.com/Beneficial-Technology/repo-ip-auditor/issues"},"bin":{"repo-ip-audit":"dist/cli.js"},"dist":{"shasum":"48aff6179cac4c8b53951bc1d98253c38f21142d","tarball":"https://registry.npmjs.org/@beneficialtechnology/repo-ip-auditor/-/repo-ip-auditor-0.1.2.tgz","fileCount":36,"integrity":"sha512-nkXFLSqxTnvIo84fVp1mNSHVzAdMuAUZNE+p0NIt+bDJ38IntHETnBxGqwMInpg4bwZStXqW8JbGHa9AsY8HbQ==","signatures":[{"sig":"MEUCIGY+3RuC6s9xkmqRuFpH5ohvnTtZydwa9DfPkcw7C7m5AiEAvaxirN6Xz83AaqZAKJlaA7kvAZoaLXH98LdGI7vXUDI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70405},"main":"dist/audit.js","type":"module","types":"dist/audit.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/audit.d.ts","import":"./dist/audit.js"},"./core":{"types":"./dist/core.d.ts","import":"./dist/core.js"}},"gitHead":"617efe3c2c9f708b3f03a0b456584168f8ffce77","scripts":{"test":"node dist/cli.js . --offline --min-score 1","build":"tsc","audit:self":"node dist/cli.js .","prepublishOnly":"tsc"},"_npmUser":{"name":"beneficialtechnology","email":"tyler@beneficial.technology"},"repository":{"url":"git+https://github.com/Beneficial-Technology/repo-ip-auditor.git","type":"git"},"_npmVersion":"11.13.0","description":"Audit a git repository for IP chain-of-title gaps and copyleft exposure before diligence does.","directories":{},"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"5.6.3","@types/node":"22.7.5","@types/react":"^18.3.12"},"_npmOperationalInternal":{"tmp":"tmp/repo-ip-auditor_0.1.2_1788022838702_0.48925153796531373","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-08-29T16:33:59.094Z","modified":"2026-08-29T17:05:18.442Z","0.1.1":"2026-08-29T16:33:59.484Z","0.1.2":"2026-08-29T17:00:38.840Z"},"bugs":{"url":"https://github.com/Beneficial-Technology/repo-ip-auditor/issues"},"author":{"name":"Beneficial Technology"},"license":"MIT","homepage":"https://beneficial.technology/tools/repo-ip-auditor","keywords":["ip","license","copyleft","agpl","due-diligence","git","compliance","sbom"],"repository":{"url":"git+https://github.com/Beneficial-Technology/repo-ip-auditor.git","type":"git"},"description":"Audit a git repository for IP chain-of-title gaps and copyleft exposure before diligence does.","maintainers":[{"name":"beneficialtechnology","email":"tyler@beneficial.technology"}],"readme":"# Repo IP Auditor\n\nAudits a git repository for IP chain-of-title gaps and copyleft exposure. Reads commit history, root license, and package manifests, then scores the result against a published rubric.\n\nBuilt by [Beneficial Technology](https://beneficial.technology). MIT licensed. Zero runtime dependencies, which felt like the minimum standard for a tool that audits your dependencies.\n\n## Why the CLI exists\n\nThe browser version reads public repos through the GitHub API. It sees at most 500 commits, cannot open private repositories, and misses the identities that matter most.\n\nThe CLI reads local git. That means:\n\n- Full history, not a page-limited slice\n- Private repos, where the contractor commits actually live\n- `.mailmap` identity resolution\n- `Co-authored-by` trailers, which is where squash-merged contributor identities survive\n- Installed dependency trees, so transitive licenses get resolved instead of guessed\n- File headers on every tracked source file, which is where copied third-party code actually shows up\n- Offline operation, so nothing about your codebase leaves the machine\n\n## The deep scan\n\n`git ls-files` is the file list. Uncommitted build output is not a chain-of-title problem; vendored third-party code that was committed is exactly the problem. Each tracked source file has its first 6 KB read, because license headers live at the top.\n\nFour findings come out of it:\n\n- **Copyleft SPDX header.** `SPDX-License-Identifier: GPL-3.0` on a file inside your repository. Stronger evidence than a manifest entry, because the code is already in your tree.\n- **Copyleft license text.** GPL, LGPL, AGPL, MPL or EPL preamble pasted into a source file.\n- **Vendored copyleft license.** A `LICENSE` or `COPYING` file in a subdirectory. At the root it is your license; in `vendor/` it is someone else's.\n- **Third-party copyright holder.** A copyright line naming an entity that is not you. Pass `--company \"Acme, Inc.\"` and declare your domains so your own notices are recognised, and use `allowCopyright` in config for holders you have already cleared.\n\nTwo rules keep it honest. If the repository's own root license is copyleft, copyleft headers are reported but not deducted, because a GPL project is not contaminated by GPL headers. And permissive license boilerplate is filtered out of copyright matching, so BSD disclaimer text does not get reported as a rights holder.\n\nSkip it with `--no-headers` for a surface scan that matches what the browser can see.\n\n## Install\n\n```bash\nnpm i -g @beneficialtechnology/repo-ip-auditor\nrepo-ip-audit .\n```\n\nOr run it once without installing:\n\n```bash\nnpx @beneficialtechnology/repo-ip-auditor .\n```\n\nRequires Node 20 or later and git on the path.\n\n## Usage\n\n```\nrepo-ip-audit [path] [options]\n\n  --domains a.com,b.com   Company email domains. Inferred from history if omitted.\n  --min-score 75          Exit 1 when the score falls below this.\n  --format text|json|md   Output format. Default: text.\n  --out FILE              Write the report to a file.\n  --offline               Skip registry lookups. Reads licenses from disk only.\n  --no-headers            Skip the file header scan (surface scan only).\n  --company \"Acme, Inc.\"  Copyright holder to treat as your own.\n  --since 2023-01-01      Limit history by date.\n  --max-commits 5000      Limit history by count.\n  --rubric                Print the scoring rubric and exit.\n```\n\nExit codes: `0` pass, `1` below threshold, `2` error.\n\n## Configuration\n\n`ipaudit.config.json` in the repo root:\n\n```json\n{\n  \"domains\": [\"acme.com\", \"acmelabs.io\"],\n  \"company\": \"Acme, Inc.\",\n  \"allowContributors\": [\"ex-contractor@gmail.com\"],\n  \"allowPackages\": [\"npm:some-lgpl-tool\"],\n  \"allowCopyright\": [\"Acme Holdings LLC\"],\n  \"minScore\": 80\n}\n```\n\n`allowContributors` is for identities whose assignment you have already papered. `allowPackages` is for copyleft you have reviewed and accepted. Both are the record of a decision, so keep them in version control and put a reason in the commit message.\n\n## GitHub Action\n\n```yaml\nname: IP audit\non: [pull_request]\n\njobs:\n  audit:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0        # required, or history is incomplete\n      - uses: Beneficial-Technology/repo-ip-auditor@v0\n        with:\n          domains: acme.com\n          company: Acme, Inc.\n          min-score: '75'\n```\n\n`fetch-depth: 0` is not optional. The default shallow clone hides most of the history, and a shallow scan produces a clean score for the wrong reason. The action emits a warning when it detects one.\n\nOutputs: `score`, `grade`, `unassigned`, `copyleft`, `report`.\n\nFindings are written to the job summary and emitted as annotations. To comment on the pull request instead:\n\n```yaml\n      - uses: Beneficial-Technology/repo-ip-auditor@v0\n        id: ip\n        with: { domains: acme.com }\n      - uses: peter-evans/create-or-update-comment@v4\n        with:\n          issue-number: ${{ github.event.pull_request.number }}\n          body: ${{ steps.ip.outputs.report }}\n```\n\nStart with `min-score: '0'` and let it report for a few weeks. Turning the gate on before the backlog is cleared just teaches the team to skip the check.\n\n## Scoring\n\nFixed deductions from a base of 100. Same rubric as the browser version, so the two agree.\n\n| Finding | Per item | Cap |\n|---|---|---|\n| Unassigned contributor, consumer email domain | -6 | 30 |\n| Unassigned contributor, other corporate domain | -9 | 30 |\n| AGPL or source-available runtime dependency | -25 | 45 shared with GPL |\n| GPL runtime dependency | -15 | 45 shared with AGPL |\n| LGPL, MPL or EPL runtime dependency | -4 | 12 |\n| Copyleft in dev dependencies only | -2 | 6 |\n| No root LICENSE file | -10 | once |\n| Root license is itself copyleft | -20 | once |\n| Committed source file under a copyleft header (deep scan) | -12 | 36 |\n| Vendored copyleft license file (deep scan) | -8 | 24 |\n| Third-party copyright holder in source (deep scan) | -5 | 20 |\n\nGrades: A 90+, B 75+, C 60+, D 40+, F below 40.\n\nDev dependencies are scored separately from runtime because a GPL build tool is not a distribution problem. Anything the classifier cannot map lands in `unresolved` and is reported rather than assumed permissive.\n\n## What it cannot tell you\n\n- Whether an agreement exists. It reads email domains, not signatures. An on-domain commit from someone who never signed an assignment scores as clean.\n- How a dependency is linked. Static linking, dynamic linking, and a separate process are three different answers, and the manifest does not say which one you have.\n- Whether a license file matches the license field. It reports what is declared.\n- Whether a copyright notice is accurate. It reads the text, not the ownership record.\n- Anything about squash-merged history beyond the trailers. If your history was rewritten, original authorship is gone and a clean score means less than it looks like.\n\nThis is an engineering signal, not a legal opinion. No attorney-client relationship is created by running it.\n","readmeFilename":"README.md"}