feat(dist): packaging, container image, install paths, completions & signed releases#192
Conversation
Add 'agentfence completion <bash|zsh|fish>' and 'agentfence man' subcommands that emit their artifacts from the CLI's own command list, so shipped completions/man can never drift from the binary (#107). Also stamp build provenance: main.commit/main.date are now real symbols surfaced by 'version' when set by the release pipeline (kept single-line for local builds). Refs #107, #111 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsYfrSqEBrap5VUSB3NPEu
Distribution/packaging for the release pipeline: - Dockerfile (multi-stage, distroless static, non-root) for 'make docker' and Dockerfile.goreleaser for the published image; CI builds and smoke-tests the image (#149, #104). - GoReleaser dockers_v2 publishes a multi-arch (amd64/arm64) GHCR image; release.yml gains QEMU/buildx, GHCR login, and packages: write (#104). - scripts/install.sh: checksum-verifying curl|sh installer, fails closed on mismatch; Homebrew cask, Scoop and winget manifests via GoReleaser (#105, #120). - cosign keyless signing of checksums and the image manifest, plus a Syft SBOM per archive; release.yml gains id-token: write and installs cosign/syft (#111). - Makefile completions/man/docker targets; generated dirs gitignored. Validated locally with 'goreleaser check' (v2.16.0, the version CI's '~> v2' resolves): clean, zero deprecations. Refs #149, #104, #105, #120, #111 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsYfrSqEBrap5VUSB3NPEu
…ation Expand README Install with the script/Homebrew/Scoop/winget/container paths; add install-channel, container, completions, and 'Verifying a release' (cosign/SBOM) sections to docs/distribution.md including the maintainer-only tap/bucket/fork prerequisites; record the work under CHANGELOG [Unreleased]. Refs #104, #105, #107, #111, #120, #149 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsYfrSqEBrap5VUSB3NPEu
There was a problem hiding this comment.
Pull request overview
This PR implements a comprehensive distribution/release pipeline for AgentFence: packaging generated CLI artifacts (completions + man page), adding container image builds/publishing, adding an install script and package-manager channels, and hardening releases with signing/SBOM.
Changes:
- Add
agentfence completion <bash|zsh|fish>andagentfence man, plus generation targets (make completions,make man) and archive bundling. - Add container build artifacts (
Dockerfile,Dockerfile.goreleaser) plus CI smoke-build and release publishing to GHCR. - Extend GoReleaser + release workflow for SBOM generation, cosign signing, and publishing to Homebrew/Scoop/winget.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/install.sh | New checksum-verifying installer for Linux/macOS releases. |
| README.md | Updates install documentation to include script, package managers, and container image. |
| Makefile | Adds targets for completions/man generation and docker builds; cleans generated artifacts. |
| docs/distribution.md | Documents distribution channels, container usage, completions/man, and verification steps. |
| Dockerfile.goreleaser | Distroless runtime image for GoReleaser-published container builds. |
| Dockerfile | Multi-stage from-source container build for local docker build / CI smoke-tests. |
| cmd/agentfence/main.go | Adds completion/man commands and optional build provenance in version. |
| cmd/agentfence/completion.go | Implements completion + man-page generation from a shared command surface list. |
| cmd/agentfence/completion_test.go | Adds tests to prevent drift and validate completion/man output structure. |
| CHANGELOG.md | Adds an unreleased entry describing new distribution/release features. |
| .goreleaser.yml | Generates artifacts in hooks, bundles them into archives, adds SBOM/signing/images and package manager publishing. |
| .gitignore | Ignores generated completions/manpages directories. |
| .github/workflows/release.yml | Adds GHCR permissions and installs cosign/syft; runs GoReleaser on tags. |
| .github/workflows/ci.yml | Adds docker image build + smoke-test job on CI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- man: stamp main.Version into the man page's .TH header in the goreleaser before-hook (-ldflags) so releases no longer embed 'agentfence dev' (verified via snapshot: header shows the release version). - man: harden manEscape to neutralize a leading '.'/'\'' (roff control characters) with a zero-width escape; fix its comment to match. - release: make Homebrew/Scoop/winget skip_upload conditional on their token env so a first tagged release succeeds without the optional secrets configured (verified via snapshot — all three pipes run cleanly). - install.sh: select the checksum with an exact awk field match instead of a regex grep, and sanity-check the resolved hash. - zsh completion: keep $words[1] dispatch (empirically correct under the '*::' rest spec: 'audit <TAB>' => $words[1]=audit, $words[2] empty) and add a clarifying comment plus structural tests guarding the dispatch and the man escaping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsYfrSqEBrap5VUSB3NPEu
|
Thanks for the review — addressed in d49b4dc:
Generated by Claude Code |
The existing TestTopLevelCommandsMatchDispatch guards only top-level commands. subcommandGroups (audit/policy/completion second words) had no equivalent guard, so adding a new `audit`/`policy` subcommand would silently drop it from generated completions with no failing test. Add TestSubcommandGroupsMatchDispatch mirroring the house drift-guard pattern: it asserts each group lists exactly the subcommands its dispatcher routes (runAuditSubcmd / runPolicySubcmd) and that the completion group equals supportedShells. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012QsfUcfxTTSRiHbLwfXgUB
Summary
Implements the distribution / packaging / release-pipeline issue group in one coherent PR (all rooted in
.goreleaser.yml+.github/workflows/+ distribution docs). Net of ~938 lines; the bulk of new code is the completion/man generator and its tests, the rest is release config and docs.What changed (by area):
agentfence completion <bash|zsh|fish>andagentfence mangenerate their artifacts from the CLI's own command list (cmd/agentfence/completion.go), so shipped completions/man can't drift from the binary. A drift test (TestTopLevelCommandsMatchDispatch) ties the command list to therunRootdispatch switch.versionnow surfaces stampedcommit/dateprovenance when set (single-line for local builds).Dockerfile(distroless static, non-root) formake docker, plusDockerfile.goreleaserfor the published image. GoReleaserdockers_v2publishes a multi-arch (amd64/arm64) image toghcr.io/dgenio/agentfence; a new CIdocker-buildjob builds + smoke-tests it on every push.scripts/install.sh(checksum-verifyingcurl | sh, fails closed on mismatch), a Homebrew cask, and Scoop + winget manifests via GoReleaser.checksums.txtand the image manifest, plus a Syft SBOM per archive;release.ymlgainsid-token: write/packages: writeand installs cosign/syft.docs/distribution.md(install channels, container, completions, "Verifying a release", and the maintainer-only tap/bucket/fork prerequisites), and a CHANGELOG[Unreleased]entry.Related issue
Closes #107
Closes #149
Closes #104
Closes #105
Closes #120
Closes #111
How verified
make ci(fmt-check, vet,go test -race+ coverage) — all packages pass, total coverage 80.9%.go test ./cmd/agentfence -run 'Completion|ManPage|TopLevelCommands|RunMan'— 8/8 pass (each shell script contains every command + subcommand groups; shell markers; unsupported-shell error; man page structure; arg-count guards).goreleaser checkwith v2.16.0 (the version CI's~> v2resolves) — valid, exit 0, zero deprecations (migrateddockers→dockers_v2,brews→homebrew_casks).bash -non the bash completion passes;make completions/make manproduce the expected files (gitignored).-X main.commit/-X main.dateprint underversion; default build stays single-line.Tradeoffs / risks
goreleaser checkvalidates the config; the CIgoreleaser-check+ newdocker-buildjobs cover the rest on PR.docs/distribution.md): createdgenio/homebrew-tap,dgenio/scoop-bucket, and adgenio/winget-pkgsfork, and add theHOMEBREW_TAP_GITHUB_TOKEN/SCOOP_BUCKET_GITHUB_TOKEN/WINGET_GITHUB_TOKENsecrets. GHCR and cosign need no extra secrets (workflowGITHUB_TOKEN+ OIDC).#123(Kubernetes/Helm) was intentionally left out as a follow-up — it depends on the published image landing first.Checklist
make ci+goreleaser checklocally; container/release steps run in CI/on tag)🤖 Generated with Claude Code
https://claude.ai/code/session_01FsYfrSqEBrap5VUSB3NPEu
Generated by Claude Code