Title
Release workflow: cross-compile, checksums, tag automation
Summary
Implement the tag-triggered GitHub Actions release pipeline: reproducible
cross-compiled binaries for the four v1 platforms, SHA256SUMS, GitHub
Release creation, and version stamping via ldflags — per ADR-005.
Context
Release integrity is part of the security posture: pinned actions, least
privileges, checksums, and -trimpath reproducibility are what let users
verify what they run. Signing (cosign) is explicitly v2.
Scope
.github/workflows/release.yml, scripts/build_release.sh,
scripts/changelog_extract.sh, CHANGELOG.md (Keep-a-Changelog skeleton
with ## [Unreleased]), Makefile release-dry target.
Detailed Requirements
- Triggers: (a)
push of tags matching the glob v*.*.* (GitHub
Actions tag filters are globs, not regexes), with a first job step that
validates the tag against the shell regex
^v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.]+)?$ and fails otherwise;
(b) workflow_dispatch with a required version input (same regex
validation) that runs the full pipeline but ALWAYS as a dry run: build +
checksum + reproducibility check, upload artifacts to the workflow run
only, and skip the gh release create step. Workflow
permissions: contents: write on the release job only (the dispatch
dry-run job needs only contents: read); all actions SHA-pinned
(mirroring issue 02's rule).
scripts/build_release.sh <version> <outdir>: loops
GOOS/GOARCH ∈ {darwin,linux} × {amd64,arm64}; builds
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X github.com/Saber5656/worklog/internal/version.Version=<version> -X github.com/Saber5656/worklog/internal/version.Commit=<sha>" -o <outdir>/worklog_<version>_<os>_<arch>/worklog ./cmd/worklog;
packages each dir as .tar.gz (deterministic: --sort=name,
--mtime=@0, --owner=0 --group=0 — use gtar guidance on macOS or
build tars only on the ubuntu runner: pick ubuntu-only packaging,
simplest reproducible choice, document it); emits
SHA256SUMS over the tarballs.
- Workflow steps: checkout (full depth for tag) → setup-go (go.mod) → run
the full CI gate first (reuse: workflow_call the ci.yml or duplicate
the steps — implement workflow_call reuse) → build_release.sh →
gh release create <tag> --draft --verify-tag <outdir>/*.tar.gz <outdir>/SHA256SUMS --notes-file release notes extracted from
CHANGELOG section for the tag (script scripts/changelog_extract.sh <tag>; empty section → fail the job: forces changelog discipline).
Draft release — a human publishes it (merge ≠ release, per the user's
global policy).
- Version stamping verified:
worklog version on a built artifact prints
the tag and commit.
make release-dry: runs build_release.sh with a fake version into
bin/release-dry/ for local verification (no upload paths).
- Reproducibility smoke: building the linux/amd64 tarball twice in the
job yields identical SHA256 (assert in workflow; catches
non-determinism creep).
Acceptance Criteria
Validation
Workflow run URLs (green release dry-run + the demonstrated changelog
failure) in the PR; local make release-dry output.
Dependencies
01, 02.
Non-goals
Homebrew tap, signing/SLSA provenance (v2 per ADR-005), auto-tagging,
publishing (draft only — human gate), Windows builds.
Design References
docs/DESIGN.md §16, §12.2 (supply chain)
docs/decisions/ADR-005-licensing-and-distribution.md
Source of truth: docs/issues/32-release-workflow.md (PR #1, branch docs/v1-design). If this issue and the repo docs disagree, the docs win. Execution order and dependencies: docs/ISSUE_PLAN.md (this is issue 32 of 33).
Title
Release workflow: cross-compile, checksums, tag automation
Summary
Implement the tag-triggered GitHub Actions release pipeline: reproducible
cross-compiled binaries for the four v1 platforms, SHA256SUMS, GitHub
Release creation, and version stamping via ldflags — per ADR-005.
Context
Release integrity is part of the security posture: pinned actions, least
privileges, checksums, and
-trimpathreproducibility are what let usersverify what they run. Signing (cosign) is explicitly v2.
Scope
.github/workflows/release.yml,scripts/build_release.sh,scripts/changelog_extract.sh,CHANGELOG.md(Keep-a-Changelog skeletonwith
## [Unreleased]), Makefilerelease-drytarget.Detailed Requirements
pushof tags matching the globv*.*.*(GitHubActions tag filters are globs, not regexes), with a first job step that
validates the tag against the shell regex
^v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.]+)?$and fails otherwise;(b)
workflow_dispatchwith a requiredversioninput (same regexvalidation) that runs the full pipeline but ALWAYS as a dry run: build +
checksum + reproducibility check, upload artifacts to the workflow run
only, and skip the
gh release createstep. Workflowpermissions: contents: writeon the release job only (the dispatchdry-run job needs only
contents: read); all actions SHA-pinned(mirroring issue 02's rule).
scripts/build_release.sh <version> <outdir>: loopsGOOS/GOARCH ∈ {darwin,linux} × {amd64,arm64}; buildsCGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X github.com/Saber5656/worklog/internal/version.Version=<version> -X github.com/Saber5656/worklog/internal/version.Commit=<sha>" -o <outdir>/worklog_<version>_<os>_<arch>/worklog ./cmd/worklog;packages each dir as
.tar.gz(deterministic:--sort=name,--mtime=@0,--owner=0 --group=0— usegtarguidance on macOS orbuild tars only on the ubuntu runner: pick ubuntu-only packaging,
simplest reproducible choice, document it); emits
SHA256SUMSover the tarballs.the full CI gate first (reuse:
workflow_callthe ci.yml or duplicatethe steps — implement
workflow_callreuse) → build_release.sh →gh release create <tag> --draft --verify-tag <outdir>/*.tar.gz <outdir>/SHA256SUMS --notes-filerelease notes extracted fromCHANGELOG section for the tag (script
scripts/changelog_extract.sh <tag>; empty section → fail the job: forces changelog discipline).Draft release — a human publishes it (merge ≠ release, per the user's
global policy).
worklog versionon a built artifact printsthe tag and commit.
make release-dry: runs build_release.sh with a fake version intobin/release-dry/for local verification (no upload paths).job yields identical SHA256 (assert in workflow; catches
non-determinism creep).
Acceptance Criteria
workflow_dispatchdry run produces 4 tarballs + SHA256SUMS as runartifacts (no release created); checksums verify; binaries run on
macOS arm64 and linux amd64 (
worklog versionoutput pasted).v0.0.1-rc1produces a DRAFT release with the sameartifact set; the draft and tag are deleted after validation.
changelog_extract.shfails the job when the tag section is missing(demonstrated then fixed in the rc tag).
beyond
GITHUB_TOKEN.Validation
Workflow run URLs (green release dry-run + the demonstrated changelog
failure) in the PR; local
make release-dryoutput.Dependencies
01, 02.
Non-goals
Homebrew tap, signing/SLSA provenance (v2 per ADR-005), auto-tagging,
publishing (draft only — human gate), Windows builds.
Design References
docs/DESIGN.md§16, §12.2 (supply chain)docs/decisions/ADR-005-licensing-and-distribution.mdSource of truth:
docs/issues/32-release-workflow.md(PR #1, branchdocs/v1-design). If this issue and the repo docs disagree, the docs win. Execution order and dependencies:docs/ISSUE_PLAN.md(this is issue 32 of 33).