Documentation
¶
Overview ¶
Keeps this repo's pin of the upstream lookout watcher image current.
The gke-troubleshoot-agent recipe deploys ghcr.io/go-steer/lookout alongside the daemon, and the tag is written down in eleven places: a base Deployment, two kustomize overlays, the e2e harness, a Go test constant, and five documents. Nothing detected when that pin went stale. It sat at v0.11.0 for ten upstream releases, straight through a breaking rename, and what finally caught it was a person reading a manifest. This tool is the thing that should have caught it (#787).
Run weekly by .github/workflows/lookout-pin-check.yml, which opens a pull request carrying the rewrite plus upstream's release notes.
Usage:
# Ask "is the pin stale?" without writing anything: go run ./dev/lookout-pin-check --check # Rewrite every non-frozen site to the current upstream release: go run ./dev/lookout-pin-check # Both of the above against a captured release list, no network: go run ./dev/lookout-pin-check --check --releases=/tmp/releases.json # Rewrite, and leave a pull-request body on disk: go run ./dev/lookout-pin-check --pr-body=/tmp/body.md # Ask once, act on that same answer (what the workflow does): go run ./dev/lookout-pin-check --check --resolved=/tmp/upstream.json go run ./dev/lookout-pin-check --releases=/tmp/upstream.json
--check reports on stdout, not through the exit code ¶
--check prints exactly one line on stdout, `drift=true` or `drift=false`, and exits 0 either way. Everything a human reads goes to stderr. A non-zero exit ALWAYS means the tool itself failed — unreachable API, unreadable tree, a declaration that no longer matches anything.
The exit code cannot carry the verdict because the caller runs this through `go run`, and `go run` collapses every non-zero child status to 1. An exit-code convention would make "GitHub timed out" indistinguishable from "upstream shipped v0.22.0", and the weekly job would open a pull request every time the network hiccuped. Same reasoning, same shape, as dev/regen-builtin-pricing.
Two questions, two gates ¶
There is a second check reading these same declaration sites: examples/internal/recipecheck (#680) asks "can this daemon run this recipe's config?". They are not merged and must not be. That one is offline, in-tree, and runs in test-unit on every pull request; this one has to call another repo, so it runs weekly and out of band. The shared half — where is this image declared, and what tag does the declaration carry — lives in internal/imagepin, parameterised by image family, so there is exactly one pin walker in the repo.
Scope: the watcher image only ¶
This tool tracks ghcr.io/go-steer/lookout and nothing else. The core-agent daemon images are deliberately out of scope: they are OURS, their tags follow this repo's own release cadence rather than an upstream feed, and recipecheck already holds them to the released set. Mixing a mechanical third-party bump into that would make one pull request answer two unrelated questions. The walker is parameterised by imagepin.Family precisely so that decision stays a decision — adding a second tracked family is a declaration next to imagepin.Lookout plus a resolver, not a rewrite of any walking code.