Install¶
Every channel ships the same binary, built from the tagged commit by the release workflow, with the dashboard and the knowledge base embedded.
Which release has what
v0.2.0 is the first release built, signed and published by CI. It adds
Windows archives, deb/rpm/apk packages, cosign signatures, SBOMs, the
signed image and the OCI Helm chart, and the Homebrew tap starts with
it. v0.1.0 and v0.1.1 published linux and darwin archives with a
checksums.txt, unsigned. The rows below say where a channel starts
with v0.2.0.
| Channel | Command | Since |
|---|---|---|
| Release archive | download from Releases, verify, extract | v0.1.1 (signed from v0.2.0) |
| Homebrew | brew install abd-ulbasit/tap/upgradescope |
v0.2.0 |
| deb / rpm / apk | the packages attached to the release | v0.2.0 |
| krew | not available: krew-index declined the plugin on 2026-10-13 (#6411); use Homebrew or a release archive | — |
| Go | go install github.com/abd-ulbasit/upgradescope/cmd/upgradescope@<version> |
any |
| Container image | ghcr.io/abd-ulbasit/upgradescope:<version> (linux/amd64, linux/arm64) |
v0.2.0, signed |
| Helm chart | oci://ghcr.io/abd-ulbasit/charts/upgradescope, also on Artifact Hub |
v0.2.0, signed |
| GitHub Action | uses: abd-ulbasit/upgradescope@v0.3.0, on GitHub Marketplace; the Action's README |
v0.2.0 (listed on Marketplace from v0.2.2) |
Release archives¶
Archives are named upgradescope_<os>_<arch>.tar.gz (.zip on Windows)
for linux, darwin and windows on amd64 and arm64. Each holds the binary,
shell completions, man pages and the license notices.
VERSION=v0.2.0
base=https://github.com/abd-ulbasit/upgradescope/releases/download/$VERSION
curl -fsSLO "$base/upgradescope_linux_amd64.tar.gz"
curl -fsSLO "$base/checksums.txt"
sha256sum --ignore-missing -c checksums.txt # macOS: shasum -a 256 -c --ignore-missing checksums.txt
tar -xzf upgradescope_linux_amd64.tar.gz
sudo install upgradescope /usr/local/bin/
Verify a download¶
From v0.2.0, checksums.txt is signed keylessly by the repository's release
workflow (cosign
bundle checksums.txt.sigstore.json). Verify the signature, then the
archive against the checksums (cosign verify-blob of this bundle works from
cosign 2.4.3, the oldest tested; the image and chart need a newer one, below):
curl -fsSLO "$base/checksums.txt.sigstore.json"
cosign verify-blob checksums.txt --bundle checksums.txt.sigstore.json \
--certificate-identity "https://github.com/abd-ulbasit/upgradescope/.github/workflows/release.yml@refs/tags/$VERSION" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum --ignore-missing -c checksums.txt # macOS: shasum -a 256 -c --ignore-missing checksums.txt
cosign 2.4.1 fails on the bundle (bundle does not contain cert for
verification) unless verify-blob also gets --new-bundle-format.
Each archive also has an SPDX SBOM (<archive>.sbom.json) and a GitHub
build-provenance attestation (gh attestation verify <archive> --repo
abd-ulbasit/upgradescope).
The deb, rpm and apk packages are covered by the same checksums.txt, under
the names GitHub serves them with, so download them by those names and the
command above checks them too. (A pre-release's package names use . where
nfpm's own would use ~: upgradescope_0.2.0.rc.2_amd64.deb. release-check
fails any asset name GitHub would rewrite.) --ignore-missing skips a file
checksums.txt does not list, so confirm the output names every package you
downloaded with OK.
Homebrew¶
brew install abd-ulbasit/tap/upgradescope
Available from v0.2.0, for stable releases only: the tap skips
pre-releases (-rc.N), and its release notes do not offer it. The tap pulls
each stable release on a schedule, so a new release reaches it within about
six hours. Its formula is rendered only from releases whose checksums.txt
verifies against the release workflow's signature.
Go¶
go install github.com/abd-ulbasit/upgradescope/cmd/upgradescope@latest
The dashboard is committed in the module, so this binary serves it too, and
upgradescope version reports the module version. It does not report the commit or the build
date: the go command stamps those only for a build inside a git checkout, so
from the module proxy upgradescope version prints commit: unknown,
built: unknown and registry date: unknown (seen by the round-3 audit on
v0.2.0-rc.3, #99). make go-install-check builds from a
checkout, where the commit is stamped, so it does not cover the proxy path.
The binary is built with your toolchain rather than the release's; the
release archives, image and packages carry all three stamps.
Container image¶
docker run --rm ghcr.io/abd-ulbasit/upgradescope:0.2.0 version
A distroless, non-root (UID 65532) image with only the binary and its
license notices in /licenses/, for linux/amd64 and linux/arm64. Verify
the signature with cosign 3.x, or 2.6.3 or later:
cosign verify ghcr.io/abd-ulbasit/upgradescope:0.2.0 \
--certificate-identity-regexp '^https://github.com/abd-ulbasit/upgradescope/\.github/workflows/release\.yml@refs/tags/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Each platform image is signed too and verifies on its own, by digest.
The signatures are in cosign 3's bundle format, stored as OCI referrers. On
cosign 2.6.2 or older the command above fails with Error: no signatures
found (exit 10), though the image is signed: nothing is wrongly accepted, it
fails closed. Upgrade cosign (the default of sigstore/cosign-installer v3.10.1
is 2.6.1, too old: set cosign-release to v2.6.3 or later, or use
installer v4). From v0.2.0 on, each release run verifies every published image and
chart with this command, once with cosign v2.6.3 and once with the current
default.
Helm chart¶
helm install upgradescope oci://ghcr.io/abd-ulbasit/charts/upgradescope \
--version 0.3.0 -n upgradescope --create-namespace
The published chart pins the image of its release by digest. It is signed
with cosign (cosign verify ghcr.io/abd-ulbasit/charts/upgradescope:0.2.0
with the flags above, and the same minimum: cosign 3.x, or 2.6.3 or
later; older versions fail with no signatures found). To run unreleased
changes, install from a clone of the repository instead:
helm install upgradescope deploy/chart ..., with image.repository and
image.tag set to an image built from the clone (make docker-build): a
clone's chart defaults to the image of the release it was cut for.
Upgrade it with helm upgrade --reset-then-reuse-values (Helm 3.14 or
later), never --reuse-values, which keeps the old chart's defaults, the
pinned image digest among them: Upgrade.
What the chart installs, and the agent-only, combined and fleet-hub setups: In-cluster agent, the chart README and Helm values.
Sizing the agent¶
The agent's defaults are 50m CPU and 64Mi requested, with limits of 1 CPU and
256Mi (agent.resources). The CPU limit is a quota, not a scheduling reservation (a namespace
ResourceQuota on limits.cpu still counts it), and
the first tick after every start reads each Helm release once: measured
against 2,000 fake nodes and 1,000 releases (1,001 with the chart's own),
the whole first tick took about 23 CPU-seconds, 35 s at 1
CPU and 48 s at 500m, both finishing the Helm step (which had 59 s in those
runs), and did not finish its Helm step at 200m, the chart's default
through v0.2.0-rc.2 (it left 132 releases unread, and the report's
notAssessed said so). If you set a lower limit on a cluster with many
releases, expect the first ticks to report helm (partial) until the cache
fills. At 1 CPU the Helm step took about 28 s of the 35, and since the tick
reserve (#238) the step has at most 54 s at the default interval, so above
about 1,900 releases (arithmetic, not measured) give the agent more than
1 CPU or a longer agent.interval. With rbac.gitops.* on, each tick also lists Argo
CD Applications and Flux HelmReleases and reads their OCIRepositories: 540
requests and 3 more CPU-seconds for 1,000 of each. These reads share the
Helm step's 54 s, so the ceiling is lower (about 1,600 releases by the
same arithmetic, taking the 8.7 s the GitOps reads added to a tick with no
quota).
Memory: the agent's peak RSS was 66 to 71 MiB as a pod at that size (main
735751d, before #228's larger pod pages, which raised the benchmark's peak
RSS by about 8 MiB). A pod page holds up to 1,000 pods, so 1,000 pods of about 60 KiB each, after a
page of small ones, would take the agent past its GOMEMLIMIT at the
256Mi limit (computed from the live heap such a page held on GitHub's
linux/amd64 runner, see
the tick after #226 and #228). Raise
agent.resources.limits.memory on a cluster whose pods are that large, as
Argo Workflows pods, which carry their template, can be. The measurements,
and their limits, are in Scale and cost.
Sizes¶
What a release ships, measured on the published v0.2.0 assets (commit
62603159, GoReleaser v2.17.1, Go 1.26.9) on 2026-10-11. The image is
19.4 MiB compressed for linux/amd64 and 17.6 MiB for linux/arm64 (the
layers ghcr serves).
The binary is stripped
(CGO_ENABLED=0 -trimpath -ldflags "-s -w"); the archive is the download,
with the licenses, README, completions and man pages beside the binary.
Every platform is cross-compiled without cgo, so the build host does not
change a size; the Go version and the commit do. 1 MiB is 1,048,576 bytes.
| Platform | Binary | Archive |
|---|---|---|
| linux/amd64 | 61.5 MiB | 18.7 MiB |
| linux/arm64 | 57.7 MiB | 16.9 MiB |
| darwin/amd64 | 62.5 MiB | 19.0 MiB |
| darwin/arm64 | 59.2 MiB | 17.6 MiB |
| windows/amd64 | 62.6 MiB | 19.1 MiB |
| windows/arm64 | 58.0 MiB | 16.9 MiB |
Archives are .tar.gz, .zip on Windows. The release check
(hack/check-doc-sizes.sh, after the snapshot) fails when a size here or
in the README differs from the build by more than 2%, so these are re-measured
before a release ships a different size. On pull requests CI runs that
check only when they touch release inputs, so a code change that grows the
binary first fails a dispatched CI run or the release's own
release-check (scheduled runs skip it): run make release-check
(no Docker engine: GORELEASER_SKIP=publish,sign,sbom,docker) before
tagging, and update both pages when it fails.
The image adds the distroless base, whose layers are 0.7 MB compressed
(gcr.io/distroless/static-debian12:nonroot, as pinned in
Dockerfile.release), and about 0.3 MB of license notices, to the binary.
The size of the published v0.2.0 image will be measured from the registry
once it exists.