Repository navigation
Publish release images to GHCR and a CLI that defaults to them - #71
Merged
Merged
Conversation
Tomer Glottmann (tomergee)
marked this pull request as draft
October 1, 2026 16:52
Collaborator
Author
|
After #77 (Substrate bump to |
Tomer Glottmann (tomergee)
force-pushed
the
release-images
branch
from
October 13, 2026 05:32
9cbb235 to
0d86335
Compare
Tomer Glottmann (tomergee)
marked this pull request as ready for review
October 13, 2026 05:32
Tomer Glottmann (tomergee)
force-pushed
the
release-images
branch
from
October 13, 2026 17:15
0d86335 to
74fb002
Compare
Nothing published images for this repo: the Makefile pushed to a personal registry, releases carried no assets, and the manifest command's error message pointed at "images published by the latest release" that did not exist. Every user, including the quickstart, had to build and push ate-env-api and ate-env-guest first. A release workflow now runs on every v* tag (and by hand for an existing tag): ko builds both images for linux/amd64 and linux/arm64, pushes them to ghcr.io/<org>/<repo>/ate-env-api and ate-env-guest tagged with the release and latest, signs them with cosign keyless signing bound to the workflow's identity, then builds the ate-env CLI for linux and darwin on amd64 and arm64 with the two digests and the version baked in, uploads the binaries, an images_<tag>.txt and checksums as release assets, and writes an Images section with the digests and the verify command into the release notes. The CLI gains build-time defaults: a release binary's `manifest --api-image` and `manifest template --guest-image` default to the images published with it, `ate-env --version` prints the tag, and a source build keeps the flags required with messages that say why. The worker image stays a required flag, since ateom-gvisor comes from the Substrate repo and must match the Substrate version on the cluster; the message says so. `make build-cli` reproduces a release-style binary locally. A ci workflow runs the Go build, vet and tests, the license-header check, and the Python client tests on pull requests and main; the repo had no checks before. The guest's bash base image is pinned by digest in .ko.yaml so a published guest is reproducible. docs/release.md describes the artifacts, pinning, verification, cutting and republishing a release, and the one-time organization setup for GitHub Container Registry; the README quickstart no longer needs image flags with a release binary.
…t of shell What the organization's workflow security scan (zizmor) requires, and what a release pipeline should do anyway: - every action pinned by commit SHA, with the version in a trailing comment (each SHA checked against its tag) - checkout with persist-credentials off - top-level permissions empty; the release job asks for contents, packages and id-token itself - no expression interpolated into a run block: inputs and step outputs reach the shell through env - Go module cache off for the release build, so a release cannot consume a cache another run seeded - concurrency: a new push supersedes running CI; one publish per tag at a time docs/release.md explains the pinning convention and how to bump a pin. zizmor reports no findings on both workflows.
The quickstart no longer pins this repo's images, release binaries carry the defaults, so the regex rewrite had nothing to match and printed a misleading "updated README" line. Build, push, print.
Tomer Glottmann (tomergee)
force-pushed
the
release-images
branch
from
October 13, 2026 17:42
74fb002 to
3525f79
Compare
runSidecar used exec.CommandContext, whose cancel kills only the direct child. A sidecar that forks (a wrapper script, which RUNTIMES.md recommends for quoted arguments) died alone while its child kept the output pipes open, and cmd.Wait blocked until that child exited. The guest's shutdown hung for as long as the orphan lived. TestRunSidecarRestartsAndStopsWithContext caught this on Linux and not on macOS: `sh -c "sleep 60"` is dash on Linux, which forks sleep, and bash on macOS, which execs it. First seen in the ci run on #71 (https://github.com/agent-substrate/env/actions/runs/38440900526), the first Linux run of this code. Each sidecar now runs in its own process group. On cancel the group gets SIGTERM, cmd.WaitDelay (sidecarStopGrace, 5 s) bounds the wait for the pipes, and the group gets SIGKILL for anything still alive. Verified in a golang:1.27 container, the test 3/3 and the guest packages green, and on macOS. (cherry picked from commit 93c5fb2)
ubuntu-latest migrates to Ubuntu 26.04 from 2026-10-19 (actions/runner-images#14748). A release pipeline must not change its toolchain image underneath a tag; pin the image and bump it on purpose.
… platform Review follow-ups on the process-group fix: - main waits for the supervisors after Serve returns (bounded by sidecarStopGrace plus a second), so the SIGTERM, grace and SIGKILL sequence runs before the process exits. Inside an actor the guest is PID 1 and the container ends with it anyway; outside one, this is what stops the sidecars. - The old process group is SIGKILLed before a restart as well, so a restarted sidecar does not compete with its own orphans for ports. - A stop is logged. - The test forks explicitly (`sleep 60 & wait`): a bare `sh -c "sleep 60"` execs on macOS and did not exercise the group kill there. The bound is derived from sidecarStopGrace and explained: the forked sleep holds the pipe, so returning within it proves the child died. (cherry picked from commit 922a95b)
…ign identity, strip CR before editing notes - The --worker-image message, the README quickstart and docs/release.md name `go run ./cmd/ate-setup publish worker-images` (which pushes the ateom images and prints their digest-pinned refs) instead of "build it with ko", and warn that a registry's :latest is whatever was built last and a stale worker image registers workers with no capacity. - The cosign identity regexp in the release notes and the docs is anchored to this repository's release workflow at a refs/tags/ ref, not to any identity under the repository. - The republish path strips carriage returns from the release body before looking for the previous "## Images" block; with CRLF from the API the block was appended twice instead of replaced.
…p logs Review follow-up on #79. stopGroup is now the only way a sidecar's group is taken down: SIGTERM, up to sidecarStopGrace for the group to disappear, then SIGKILL for what is left. Both paths use it: after a cancel, where it finishes what cmd.Cancel started, and before a restart, where it clears what a crashed sidecar left behind so the new one does not compete with its own orphans for ports, pipes or lock files. Each step is logged: SIGTERM sent, group exited, still alive after the grace and SIGKILL sent, or already gone (ESRCH counts as success). main's shutdown wait covers both grace periods. The test asserts the logged sequence. (cherry picked from commit 8eb8274)
Vicente Ferrara (vicentefb)
approved these changes
Oct 13, 2026
Vicente Ferrara (vicentefb)
left a comment
Collaborator
There was a problem hiding this comment.
/lgtm
Collaborator
|
/lgtm |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Make the images of this repo something a customer downloads rather than builds.
.github/workflows/release.yaml: on everyv*tag, or by hand for an existing tag, buildsate-env-apiandate-env-guestwith ko for linux/amd64 and linux/arm64, pushes them toghcr.io/agent-substrate/env/<image>tagged with the release andlatest, signs them with cosign keyless signing (bound to this repo's Actions identity), builds theate-envCLI for linux and darwin on amd64 and arm64 with the two digests baked in, and uploads binaries,images_<tag>.txtand checksums as release assets. The release notes get an## Imagessection with the digests and the verify command; a republish replaces it instead of duplicating it.CLI defaults: a release binary's
ate-env manifest --api-imageandate-env manifest template --guest-imagedefault to the release's images, so the quickstart needs no image flags for this repo.ate-env --versionprints the tag. A source build keeps the flags required, with messages that explain the two cases.make build-clireproduces a release-style binary locally.--worker-imagestays required.ateom-gvisoris a Substrate image and must match the Substrate version on the cluster; Substrate publishes nothing yet, so the message points at building it there. That is the remaining piece for a zero-build customer experience and belongs to the Substrate repo..github/workflows/ci.yaml: Go build, vet, tests, gofmt (make verify-gofmtover tracked Go files), license headers, and the Python client tests on PRs andmain. The repo had no checks before. ate-env-api: create the default atespace at startup #78 landed with two space-indented files because nothing checked formatting; this PR formats them and adds the check..ko.yaml: the guest'sbashbase pinned by digest, so a published guest image is reproducible.docs/release.md: artifacts, pinning by digest, signature verification, cutting and republishing a release, the one-time organization setup for GHCR. README: Installation and a new Images section; quickstart commands updated.Workflow hardening (what the organization's zizmor scan requires): every action pinned by commit SHA with the version in a trailing comment, checkout with
persist-credentials: false, top-levelpermissions: {}with the release job asking forcontents,packagesandid-tokenitself, no expression interpolated into arun:block (inputs and step outputs reach the shell throughenv), Go module cache off for the release build, and concurrency groups (a new push supersedes running CI; one publish per tag at a time).docs/release.mdexplains how to bump a pin.make imagesbuilds, pushes and prints the digests. It no longer rewrites the README, which no longer pins this repo's images.Why this shape
latestmoves.ate-env manifest" work without reading release notes, and keeps the CLI and the images of one release consistent by construction.First-time setup (maintainers, once)
git tag -a v0.0.11 -m v0.0.11 && git push origin v0.0.11), watch thereleaseworkflow.Testing
go test ./...passes (12 packages); the new test covers the source-build and release-build flag defaults and the worker-image message.hack/verify/boilerplate.shpasses.make build-cli ATE_ENV_API_IMAGE=... ATE_ENV_GUEST_IMAGE=... VERSION=v9.9.9produces a binary whose--versionand flag defaults carry the values, which is exactly what the workflow does. A source build keeps the flags required with the explaining message.actions/checkoutv5.1.0,actions/setup-gov5.6.0,actions/setup-pythonv5.6.0,ko-build/setup-kov0.9,sigstore/cosign-installerv3.10.1.run:block passesbash -n. The Python CI steps were run locally as written.make verify-gofmtpasses on the branch and fails on a planted unformatted file.mainand a tag is pushed; the first tag is the real test, andworkflow_dispatchexists to rerun it without a new tag.Relation to other PRs
mainafter Bump Substrate to f03327bd: follow the current API and stop sending ate-target-actor twice #77 (Substratef03327bd) and ate-env-api: create the default atespace at startup #78 (default atespace). The README keeps Bump Substrate to f03327bd: follow the current API and stop sending ate-target-actor twice #77's compatibility note; the quickstart's image lines now rely on the release defaults instead of project-pinned digests.mainafter Run unmodified rootfs images: guest injected as an OCI image volume, plus second-runtime layers #70 (rootfs images) merged: the quickstart keeps Run unmodified rootfs images: guest injected as an OCI image volume, plus second-runtime layers #70's rootfs-image and layer sections and this PR's release-default image lines; both test blocks incmd/ate-env/manifest_test.goare kept. Once a release is cut, the rootfs-image docs can name the published guest image instead of a placeholder.