Building from source
This chapter is for contributors and operators who want to build roksbnkctl themselves — whether to test an unreleased change, to verify a release artefact, or to embed a custom HCL fork into the binary.
For users who just want to install the binary, Chapter 4 — Installation is the right page. This chapter is the build-side companion.
Go version requirement
The minimum Go version is the one pinned in go.mod:
go 1.25.0
We pin to a recent toolchain for two reasons:
- The IBM Cloud Go SDKs (
go-sdk-core/v5,platform-services-go-sdk,ibm-cos-sdk-go) andk8s.io/client-gov0.30+ both make liberal use of Go’s modern generics — pre-1.21 toolchains won’t build. - Several dependencies (
miekg/dns,docker/docker) test on the current and previous minor only; we follow upstream.
Install Go via your package manager (brew install go, apt-get install golang-1.25, etc.) or from go.dev/dl. Verify with go version.
Quick build
The shortest path from a fresh clone to a working binary:
git clone https://github.com/jgruberf5/roksbnkctl.git
cd roksbnkctl
go build -o roksbnkctl ./cmd/roksbnkctl
./roksbnkctl --version
go build produces a static binary in the working directory. Cross-compilation to a different OS/arch needs GOOS / GOARCH set:
GOOS=linux GOARCH=amd64 go build -o roksbnkctl-linux-amd64 ./cmd/roksbnkctl
GOOS=darwin GOARCH=arm64 go build -o roksbnkctl-darwin-arm64 ./cmd/roksbnkctl
GOOS=windows GOARCH=amd64 go build -o roksbnkctl.exe ./cmd/roksbnkctl
A full multi-platform build is easier through goreleaser:
goreleaser release --snapshot --clean
# Output lands in dist/
The --snapshot --clean flags produce a local build without trying to publish to GitHub. The release shape is described in .goreleaser.yml — Linux + macOS × amd64 + arm64, plus a Windows compile-only check.
Build via the Makefile
The repo’s Makefile wraps the common build steps and stamps version metadata into the binary:
make build # builds bin/roksbnkctl with -ldflags version stamping
make test # go test ./...
make vet # go vet ./...
make tidy # go mod tidy
make test-short # go test -short ./...
make test-integration # testcontainers-go-backed integration tests (needs Docker)
make test-cred-audit # the security-spine regression suite
make lint # gofmt + vet + staticcheck (if installed)
The version stamp comes from three ldflags variables baked into internal/cli:
var (
Version = "dev"
Commit = "none"
BuildDate = "unknown"
)
make build passes -X github.com/jgruberf5/roksbnkctl/internal/cli.Version=$VERSION (and the others) so roksbnkctl --version reports the actual git-rev and build timestamp rather than the placeholders. Set VERSION explicitly when stamping a release:
VERSION=v1.0.0 make build
The embedded HCL
The Terraform source tree at terraform/ is compiled into the binary via Go’s //go:embed directive. The embed declaration lives at the repo root in embedded.go (and is wired through internal/tf/ to be served as the tf_source: embedded provider).
Two implications:
- Rebuilding the binary picks up HCL changes. If you’re hacking on the HCL,
make buildproduces a binary that ships your changes embedded. No separate “deploy the HCL” step. - The HCL is read-only at runtime. The binary extracts it to a temporary directory on first use; the extracted copy is what terraform operates on. The original embedded source is immutable.
For users who want to not use the embedded HCL, the tf_source: github or tf_source: local options in the workspace config bypass it entirely. See Chapter 12 §“tf_source:”.
The bundled tools images
The tools/docker/ directory holds Dockerfiles for the images the docker and k8s backends use:
tools/docker/
├── Makefile
├── ibmcloud/
│ └── Dockerfile # roksbnkctl-tools-ibmcloud
└── iperf3/
└── Dockerfile # roksbnkctl-tools-iperf3
tools/docker/Makefile builds both images locally as :dev:
cd tools/docker
make ibmcloud # builds roksbnkctl-tools-ibmcloud:dev
make iperf3 # builds roksbnkctl-tools-iperf3:dev
make all # both
The :dev tag is what a from-source roksbnkctl resolves to when the binary’s Version is dev. A tag-released binary (v1.0.0) resolves to ghcr.io/jgruberf5/roksbnkctl-tools-ibmcloud:v1.0.0 instead — the resolver logic lives in internal/exec/ (SetToolImageTag is wired in internal/cli/root.go::init). See Chapter 17 §“:dev tag resolution”.
The GitHub Actions workflow tools-images.yml builds and pushes the published images on a tag push or when tools/docker/** changes.
The book build
The book is built with mdBook. Install:
cargo install mdbook
# or
brew install mdbook
The book source lives under book/src/ with book.toml as the config. Common operations:
make book-serve # mdbook serve book/ --open
# opens http://localhost:3000 with live-reload
make book # mdbook build book/
# static HTML at book/book/
make book-clean # rm -rf book/book
The published site at https://jgruberf5.github.io/roksbnkctl/book/ is built and deployed by .github/workflows/book.yml on every push to main. The workflow runs mdbook build book/ and pushes the output to the gh-pages branch via peaceiris/actions-gh-pages.
For PR-time verification, .github/workflows/spellcheck.yml runs cspell on book/src/**/*.md — a warning, not a gate, but worth eyeballing the output before merging.
The auto-generated chapters
Two reference chapters are generated rather than hand-written. The generators live under tools/refgen/:
# Chapter 27 — command reference (walks the cobra command tree)
go run ./tools/refgen/cobra-md > book/src/27-command-reference.md
# Chapter 29 — terraform variable reference (parses terraform/variables.tf)
go run ./tools/refgen/tfvars-md > book/src/29-terraform-variable-reference.md
When to re-run:
- Chapter 27: any change to the cobra command tree under
internal/cli/orcmd/roksbnkctl/— new commands, renamed flags, editedLong:/Example:strings. - Chapter 29: any change to
terraform/variables.tfor any submodulevariables.tfreferenced from the root — new variables, default-value changes, edited descriptions.
Both generators emit deterministic output — the same input HCL or cobra tree always produces the same markdown — so you can commit the rendered output to source control without worrying about spurious diff churn.
Cross-compile matrix
goreleaser covers the canonical matrix:
| OS | Architecture | Status |
|---|---|---|
| Linux | amd64 | Fully supported |
| Linux | arm64 | Fully supported |
| macOS | amd64 (Intel) | Fully supported |
| macOS | arm64 (Apple Silicon) | Fully supported |
| Windows | amd64 | Compile-only; SSH TTY support degraded |
| Windows | arm64 | Compile-only; same caveat |
| FreeBSD | amd64 | Not tested |
The Windows caveat is real: golang.org/x/crypto/ssh’s PTY allocation isn’t complete on Windows, so roksbnkctl shell --on jumphost falls back to a non-TTY shell. The other commands (exec, ibmcloud, kubectl) work fine on Windows.
Output from goreleaser release --snapshot --clean lands in dist/:
dist/
├── roksbnkctl_linux_amd64_v1/
│ └── roksbnkctl
├── roksbnkctl_linux_arm64/
│ └── roksbnkctl
├── roksbnkctl_darwin_amd64_v1/
│ └── roksbnkctl
├── roksbnkctl_darwin_arm64/
│ └── roksbnkctl
└── ...
Each archive bundles the binary plus LICENSE, README.md, and the rendered book/book/ directory (when the snapshot is built from a tagged commit).
Release process
Tagged releases are cut on the main branch:
# Update CHANGELOG.md with the release notes
git tag -a v1.0.0 -m "v1.0.0 — book launch + full E2E coverage"
git push origin v1.0.0
The push triggers release.yml, which runs goreleaser release to:
- Cross-compile the binary for the supported OS/arch matrix.
- Build the matching tools images and push to
ghcr.io/jgruberf5/roksbnkctl-tools-*:<tag>. - Attach the binaries, checksums (
checksums.txt), and the rendered book PDF (if mdbook-pdf is configured) to the GitHub release. - Generate release notes from the CHANGELOG and the commits since the previous tag.
The release-gate criteria — what has to hold before tagging — are documented in PLAN.md §“v1.0 (M4)”. The most important: full E2E green for 3 consecutive nights on the release branch.
Cross-references
- Chapter 4 — Installation — for users who just want the binary, not the source.
- Chapter 17 §“:dev tag resolution” — how a from-source binary picks tool images.
- Chapter 32 — Extending roksbnkctl — once you’ve built, what to actually hack on.
docs/PLAN.md— the release-gate policy.