Repository navigation
Embed license notices in the binary and trim the release archive - #14
Merged
Merged
Conversation
The binary statically contains third-party modules and the Go standard library, whose licenses require their texts to accompany every binary copy, and the archives carry only the project's own LICENSE. The plan embeds the texts in the binary, as GitHub CLI does, so that they travel with the binary itself, and trims the archive to what a user needs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
The binary statically contains the Go standard library and third-party modules whose licenses require their texts to accompany every binary copy. The texts are now embedded in the binary itself, as GitHub CLI does, so that they travel with it even when it is taken out of the archive, and tfscli licenses prints them. The Go license is a committed copy, embedded in every build and kept equal to the toolchain's by a test. The third-party set differs by platform, so each release platform embeds its own directory through a file named for it; the release build fills that directory, and a committed placeholder beside the generated third-party/ keeps go:embed compiling everywhere else. Such a build says that the third-party texts are only in the release builds. The list of components comes from the directory names, since the set is generated without a shell to capture a report. The command reads neither the credential nor the config file. The two tasks are committed together because the package alone would be unused. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
goreleaser now installs go-licenses v2.0.1 before the builds, and each build saves the licenses of its target's dependencies into the directory internal/licenses embeds for that target. GOOS and GOARCH are set on the hook, since the dependencies differ by platform: mousetrap is linked only on Windows. Each target writes to its own directory because the builds run in parallel. The tool is installed in a before hook rather than run with go run in the build hook, which would build it for the target's platform and fail to execute it. The tasks file now counts eight third-party modules: the earlier nine included tfscli itself. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
The archive scattered six entries into whatever directory it was unpacked in. It now unpacks into a directory named like the archive and holds only what a user needs beside the binary: the project's LICENSE and the agent skill, which the README tells the user to copy from it. The README and the changelog are read on GitHub and on the release page, and the third-party licenses travel inside the binary. config.example.json is deleted rather than only dropped from the archive: it held the same three lines the README shows, so nothing else needs it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
make check now fails when a dependency linked into the binary is under a license other than MIT, BSD-3-Clause, or Apache-2.0, so that a new license is noticed on the pull request that brings it rather than at the release. go-licenses runs through go run with a pinned version, which needs nothing installed and leaves go.mod alone, so the tools make check requires stay the same. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
The README describes tfscli licenses and what a binary built from source prints for it, and the archive section names the new contents and the directory it unpacks into. The changelog records the command and the change to the archives for users. The architecture records go-licenses as a build tool, with the reasons the texts are embedded per platform rather than shipped beside the binary or committed, and adds the licenses package. CONTRIBUTING covers the new target and what the release and a snapshot now do; the agent skill and CLAUDE.md name the command. Closes docs/archive/2026-10-06-tasks-third-party-licenses.md Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
The project owes no notice to itself, but whoever passes the binary on owes one for tfscli, and now finds it in the binary like every other notice. The license is a committed copy, which a test keeps equal to LICENSE, rather than part of the generated set: every build carries it, and it is not listed among the third-party modules. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
make licenses checked only the platform it ran on, so a dependency linked on Windows or macOS alone could bring a license outside the allowed list unnoticed. tools/check-licenses.go now runs go-licenses check for each of the six release platforms. It installs go-licenses for the platform it runs on first: go run with a target's GOOS would build the tool for that target, and setting GOOS in a make recipe would need a Unix shell. Nothing verified that a release binary actually carries its licenses: a build hook that generated nothing would have shipped binaries saying the texts exist only in release builds. The release workflow now builds a snapshot before it pushes, checks that every platform's set holds spf13/cobra, which every platform links, and that the linux/amd64 binary prints it, so such a failure stops the release before the tag. The real release builds the same commit with the same tools and modules. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015w3YJNX9AzYUZq25WyQFDp
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.
The binary statically links the Go standard library and eight third-party modules whose licenses (MIT, BSD-3-Clause, Apache-2.0) require their text to accompany every binary copy; the archives carried only our own
LICENSE. The texts are now embedded in the binary, as GitHub CLI does.Changes
tfscli licensesprints the components built into the binary and the license text of each: tfscli, the Go standard library, and, in release builds, the third-party modules.go-licenses save(v2.0.1, a build tool, not ingo.mod); each binary embeds its own platform's set.tfscli-<version>-<os>-<arch>/and hold only the binary,LICENSE, and the agent skill.config.example.jsonis removed.make checkrunsgo-licenses checkfor all six release platforms; the release workflow builds a snapshot before tagging and verifies every binary carries its licenses.