External Tool Updater

July 30, 2026 ยท View on GitHub

Purpose

The external tool updater keeps downloaded CLI versions and SHA-256 checksums in build/tools.yaml. manifest.go validates the manifest, updater.go checks release sources, and cmd/tool-updater/main.go exposes the commands used by Make and CI.

The generated build/tools.generated.mk file is committed and supplies the metadata to the installer recipes in build/tools.mk. Do not edit the generated file directly.

Commands

Update pinned versions

make update-tools

This command checks every configured release source, advances enabled tools to newer releases when available, refreshes platform checksums, synchronizes declared versionFiles, and regenerates the committed build/tools.generated.mk file. Tools with update: false remain pinned at their current version.

make update-tools reaches the network and modifies repository files. It does not install tools on the local machine.

Install a pinned tool

make install-yq
make install-kubectl

Use make install-<tool> to download and install the version pinned in build/tools.yaml. Installer targets read versions and checksums from build/tools.generated.mk and install into a user-owned binary directory. They do not update the manifest.

Run the updater binary directly

Make builds the updater into bin/ before executing it. This stable path is important on Windows, where security software may block the temporary executable created by go run.

To invoke the compiled updater directly:

bin/tool-updater.exe update --manifest build/tools.yaml --makefile build/tools.generated.mk

Use bin/tool-updater instead of bin/tool-updater.exe on non-Windows systems. The other subcommand regenerates only the Make include:

bin/tool-updater.exe generate-make --manifest build/tools.yaml --output build/tools.generated.mk

There is no separate Make target for regeneration only. The generate-make subcommand is the binary-level equivalent, and Make runs it automatically when the committed generated include is stale.

Manifest reference

The manifest is YAML with the following top-level properties:

PropertyTypeAllowed or required valuesDescription
schemaVersioninteger1Manifest schema version.
cooldownDaysintegerNon-negative integer; omitted or 0 disables the cooldownMinimum age, in days, before a release is adopted.
platformslist of stringsOne or more unique values matching linux_amd64, linux_arm64, darwin_amd64, or darwin_arm64Platforms for which checksums and assets are recorded.
toolslist of objectsOne or more toolsTool definitions described below.

Tool properties

PropertyTypeAllowed or required valuesDescription
namestringLowercase letters, numbers, and hyphens; must start with a lowercase letter or numberStable tool identifier.
makePrefixstringUppercase letters, numbers, and underscores; must start with an uppercase letterPrefix used for generated Make variables such as YQ_VERSION.
versionstringNon-emptyCurrently pinned release version. The value may include a leading v when the upstream uses one.
updatebooleantrue or false; omitted means trueSet to false to check the source while keeping the current version pinned.
notesstringOptionalHuman-readable compatibility or pinning rationale.
sourceobjectRequiredDescribes how the latest version is discovered.
downloadTemplatestringRequired unless checksumSource.type is noneURL template for an asset download.
platformsmapRequired for checksum-bearing tools; must contain every top-level platformAsset and checksum data for each supported platform.
checksumSourceobjectRequiredDescribes how the updater obtains or computes SHA-256 checksums.
versionFileslistOptionalAdditional repository files whose embedded version must stay synchronized.

source properties

PropertyTypeAllowed or required valuesDescription
typestringgithub-release, stable-text, or hashicorp-checkpointVersion source parser selected by the updater.
repositorystringowner/repository; required for github-releaseGitHub repository; stable-text uses it for release dates.
tagPrefixstringOptionalPrefix added to the pinned version to form a release tag, such as jq-.
latestURLstringNon-empty HTTPS URLEndpoint queried for the latest version.

For github-release, the endpoint must return a GitHub release object with tag_name. stable-text reads the trimmed response body, and hashicorp-checkpoint reads current_version from the JSON response.

The cooldown needs a release date. github-release reads published_at and hashicorp-checkpoint reads current_release. A stable-text response carries no date, so the updater reads published_at from the GitHub release matching the resolved tag in repository. When a cooldown is configured, every updatable tool must be able to resolve a date this way or the manifest fails validation.

checksumSource properties

typeRequired propertiesBehavior
github-release-filefileTemplate, format; also orderFileTemplate when format is yqReads a checksum file from the GitHub release.
url-fileurlTemplate, formatReads a checksum file from an arbitrary URL.
downloadNoneDownloads the asset and hashes its bytes locally.
noneintegrityRecords a non-SHA-256 integrity method, such as go-sumdb; the tool has no platform asset map.

Supported checksum formats are standard (filename in the second column), basename (compare only the filename after a path), first (use the first field), and yq (use checksums_hashes_order to locate the SHA-256 column). Every stored checksum must be exactly 64 lowercase hexadecimal characters.

Platform entries

Each platform entry has these properties:

PropertyTypeAllowed or required valuesDescription
assetstringNon-empty; may contain template variablesRelease asset name.
checksumstringLowercase 64-character SHA-256 valueExpected checksum for the asset.
osstringOptionalOverrides the operating-system value used in templates.
archstringOptionalOverrides the architecture value used in templates.

Templates

Asset, download, checksum-file, and checksum-URL templates may use these variables:

VariableValue
{repository}source.repository
{tag}source.tagPrefix plus the requested version
{version}Requested version, including its leading v when present
{version_no_v}Requested version without a leading v
{asset}Expanded platform asset name
{os}Platform OS, or the entry's os override
{arch}Platform architecture, or the entry's arch override

Unknown or unterminated template variables are errors.

Version files

A versionFiles entry keeps another repository file synchronized when a tool version changes:

PropertyTypeAllowed or required valuesDescription
pathstringRepository-relative pathFile to update. Paths outside the repository are rejected.
formatstringplain or replaceReplace the whole file with the version, or replace text between markers.
prefixstringRequired for replace; empty for plainText immediately before the embedded version.
suffixstringRequired for replace; empty for plainText immediately after the embedded version.

The replace prefix must occur exactly once. Terraform uses versionFiles for .terraform-version, the Go fallback, and the Helm chart default.

Update behavior

  • The updater checks the latest version source for every tool.
  • A version changes only when the source is a greater semantic version; downgrades are ignored.
  • A newer release is adopted only once it is at least cooldownDays old. A younger release is reported as held and the current version stays pinned until a later run.
  • A tool with update: false remains pinned, but its source and current-version checks still run.
  • Checksums are refreshed for every configured platform at the selected version.
  • The manifest, generated Make include, Terraform compatibility file, and declared version consumers are updated only after source checks succeed.

Verification

Run the focused tests and static checks after changing the updater or manifest:

go test ./internal/tooling ./cmd/tool-updater
go vet ./internal/tooling ./cmd/tool-updater
make --no-print-directory -n update-tools

The Make dry run should invoke bin/tool-updater or bin/tool-updater.exe, not go run.

Troubleshooting

  • Windows reports an elevation error for go run. Use make update-tools, or build and run bin/tool-updater.exe directly. The Make target avoids Go's temporary executable directory.
  • A newer release is reported as held. The release is younger than cooldownDays. Wait for it to age, or change cooldownDays in the manifest.
  • The updater reports that a source has no release date. The source stopped returning published_at or current_release. Confirm the release exists upstream, and check that a stable-text source names a repository that publishes GitHub releases for its tags.
  • A checksum is not found. Check the release asset name, version/tag prefix, checksum-file template, and checksum format together. The updater matches the expanded asset name exactly.
  • Manifest validation fails. Ensure every checksum-bearing tool defines every platform listed at the manifest's top level, every checksum is 64 lowercase hexadecimal characters, and any versionFiles path stays inside the repository.