feat(build): ship third-party license attribution and gate dependency licenses - #141
Merged
Merged
Conversation
… licenses The ofga binary statically links 126 third-party modules under MIT, BSD and Apache-2.0. All three require reproducing the module's copyright notice and license text when distributing in binary form, and none of our artifacts carried any: archives shipped only our own LICENSE, and the deb/rpm/apk packages shipped no license file at all (nfpm's `license:` field sets package metadata, it installs nothing). Nine dependencies also ship a NOTICE that Apache-2.0 section 4(d) requires travel with derivative distributions. tools/licensegen enumerates the modules linked into ./cmd/ofga, reproduces every license and NOTICE file, and writes THIRD_PARTY_LICENSES. It is scoped to the binary rather than ./... so build-time-only tooling stays out of what we have to attribute. Detection uses google/licensecheck, which reports every match in a file — 13 of our dependencies are multi-licensed, and reporting one license each would understate them. The generator doubles as the gate: it refuses to emit a bundle containing a license outside the allowlist, or text it cannot identify. Carve-outs are recorded per module with a reason rather than by widening the allowlist, so the next dependency arriving under the same license still fails. CI runs the generator and diffs, which catches both a disallowed license and a stale bundle. Added as a step beside the docs freshness check, not a new job, so branch protection's pinned job names are unaffected. The bundle now ships in the archives, deb/rpm/apk (alongside our own LICENSE at the conventional /usr/share/doc/ofga/copyright), both container images, and the AUR package. The Homebrew cask inherits it from the archive.
Build constraints make the linked module set platform-specific, so generating the bundle from whichever machine happened to run the tool under-attributed the other platforms. github.com/ebitengine/purego (Apache-2.0) is reachable only on darwin: the macOS archives were shipping an attribution list that omitted a module those binaries actually link, which is the violation this tool exists to prevent, just narrowed to one platform. The generator now unions `go list -deps` across the full goos/goarch matrix from .goreleaser.yaml. Over-attributing on a given platform is harmless — the bundle is a superset — while omitting a linked module is not. This also makes the output host-independent, so `make licenses` produces the same bundle on macOS and Linux. Without it a macOS contributor regenerating the bundle would have produced a 123-module file that CI then rejected. A test pins releaseTargets to the matrix in .goreleaser.yaml so the two cannot drift apart silently.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📝 Summary
The
ofgabinary statically links 127 third-party modules under MIT, BSD and Apache-2.0. All three require reproducing the module's copyright notice and license text when distributing in binary form — and none of our artifacts carried any. Archives shipped only our ownLICENSE; the deb/rpm/apk packages shipped no license file at all (nfpm'slicense:field sets package metadata, it installs nothing). Nine dependencies also ship aNOTICEthat Apache-2.0 §4(d) requires travel with derivative distributions.This adds
tools/licensegen, which generatesTHIRD_PARTY_LICENSESand doubles as an allowlist gate, and ships the bundle in every artifact.No copyleft exposure was found. Every linked module is permissive, so nothing had to be removed or replaced — the gap was attribution only:
Design notes
go list -depsis platform-dependent:github.com/ebitengine/purego(Apache-2.0) is reachable only on darwin. Generating from whichever machine ran the tool under-attributed the others — the macOS archives would have shipped a list omitting a module those binaries actually link. The generator now queries all fourgoos/goarchtargets from.goreleaser.yamland unions the result. Over-attributing on a given platform is harmless; omitting a linked module is the violation. This also makes output host-independent, somake licensesgives the same bundle on macOS and Linux — otherwise a Mac contributor would regenerate a 123-module file that CI then rejected. A test pinsreleaseTargetsto.goreleaser.yamlso the two cannot drift../cmd/ofga, not./...— build-time-only tooling (go-md2man,blackfriday,licensecheckitself) ships to nobody and stays out of what we attribute.google/licensecheckfor detection — it reports every match in a file. 13 dependencies are multi-licensed (gopkg.in/yaml.v3is MIT + Apache-2.0 split by file;klauspost/compressis Apache-2.0 + BSD-3 + MIT), and reporting one license each would understate them.opencontainers/go-digest, whoseLICENSE.docsis CC-BY-SA-4.0 but covers that repo's prose only.🏷 Type of change
🔗 Related issues
None.
✅ How to verify
Artifact coverage was verified against a real
make release-snapshot, opening each package rather than trusting the config:.tar.gz(Linux and Darwin)THIRD_PARTY_LICENSES/usr/share/doc/ofga/{copyright,THIRD_PARTY_LICENSES}/usr/share/licenses/ofga/THIRD_PARTY_LICENSES/usr/share/licenses/ofga-bin/THIRD_PARTY_LICENSESAlso checked:
go list -depsacross all four release targets exactly — nothing missing.package()script was simulated against the real release tarball; both license files install.make license-checkfail, andmake licensesrestores it.Not covered: the release workflow itself has not run with these changes. Snapshot mode exercises archives, packages and images but skips signing, publishing, AUR upload and the Homebrew tap; none of those steps were modified. Test-only dependencies are deliberately unscanned — they create no distribution obligation, but a copyleft test dependency would not trip the gate.
📋 Checklist
--helpexamples) if behavior changedmake checkpasses locally🤖 Generated with Claude Code