fix(ci): install Ward from release artifacts, not from source (#606) #1213

Merged
coilyco-ops merged 1 commit from aos/606-ward-release-artifacts into main 2026-08-23 00:30:34 +00:00
Member

Closes #606.

Half of it was already done

docker/dev-base/full/Dockerfile already downloads ward-linux-${TARGETARCH} with SHA256SUMS and verifies before installing. Checked that first rather than rewriting it.

scripts/install-workflow-ward.sh was the remaining source build. It cloned Ward and ran go build, so five workflow steps across four files rebuilt a product that ships verified bytes, and each needed a Go toolchain to end up with a binary.

Same contract, runner architecture

uname -m maps to amd64 or arm64, both artifacts are fetched, the checksum is verified, then install. An architecture with no published asset stops with a named error instead of falling through.

A test asserts the installer and the Dockerfile share ward-linux-, SHA256SUMS, and sha256sum -c -, so the two paths cannot drift into different verification stories.

Failing closed, twice

  • A mismatch fails sha256sum -c.
  • An absent line makes grep exit non-zero under set -e, so a missing checksum is never the same as a passing one.

Both are tested. A verification step that passes having verified nothing is worse than no step, which is the shape this lane has been closing all week.

Coverage

Ten tests against stubbed curl, uname, and sha256sum: four architecture mappings, an unsupported architecture, a corrupt checksum, an absent checksum line, no Go dependency, no ward.git or cmd/ward in either path, and the shared contract.

The late ward doctor gate against the real .ward bundle is untouched on both ci and promote.

684 tests pass, pre-commit run --all-files passes.

Closes #606. ## Half of it was already done `docker/dev-base/full/Dockerfile` already downloads `ward-linux-${TARGETARCH}` with `SHA256SUMS` and verifies before installing. Checked that first rather than rewriting it. `scripts/install-workflow-ward.sh` was the remaining source build. It cloned Ward and ran `go build`, so **five** workflow steps across four files rebuilt a product that ships verified bytes, and each needed a Go toolchain to end up with a binary. ## Same contract, runner architecture `uname -m` maps to `amd64` or `arm64`, both artifacts are fetched, the checksum is verified, then install. An architecture with no published asset stops with a named error instead of falling through. A test asserts the installer and the Dockerfile share `ward-linux-`, `SHA256SUMS`, and `sha256sum -c -`, so the two paths cannot drift into different verification stories. ## Failing closed, twice * A **mismatch** fails `sha256sum -c`. * An **absent line** makes `grep` exit non-zero under `set -e`, so a missing checksum is never the same as a passing one. Both are tested. A verification step that passes having verified nothing is worse than no step, which is the shape this lane has been closing all week. ## Coverage Ten tests against stubbed `curl`, `uname`, and `sha256sum`: four architecture mappings, an unsupported architecture, a corrupt checksum, an absent checksum line, no Go dependency, no `ward.git` or `cmd/ward` in **either** path, and the shared contract. The late `ward doctor` gate against the real `.ward` bundle is untouched on both `ci` and `promote`. 684 tests pass, `pre-commit run --all-files` passes.
fix(ci): install Ward from release artifacts, not from source (#606)
All checks were successful
ci / aos-eval-tests (pull_request) Successful in 7s
ci / ward-doctor (pull_request) Successful in 6s
ci / aos-cli-tests (pull_request) Successful in 19s
ci / gate (pull_request) Successful in 47s
fe5a1e3f1a
The image half was already done: docker/dev-base/full/Dockerfile downloads
ward-linux-${TARGETARCH} with SHA256SUMS and verifies before installing.
scripts/install-workflow-ward.sh still cloned Ward and ran `go build`, so
every gate rebuilt a product that ships verified bytes, and five workflow
steps depended on a Go toolchain to get a binary.

The installer now applies the same contract for the runner architecture:
uname picks amd64 or arm64, both artifacts are fetched, and the checksum is
verified before install. An architecture with no published asset stops with a
named error rather than falling through to a build.

The checksum check fails closed twice over. A mismatch fails `sha256sum -c`,
and an absent line makes grep exit non-zero under `set -e`, so a missing
checksum is never the same as a passing one. Both are tested, because a
verification step that passes when it verified nothing is worse than none.

The late `ward doctor` compatibility gate against the real .ward bundle is
untouched on both ci and promote.

Closes #606

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: engineer
coilyco-ops deleted branch aos/606-ward-release-artifacts 2026-08-23 00:30:34 +00:00
Author
Member

Verified the security-relevant parts by running them. The guard holds as shipped. One comment names the wrong mechanism, which matters because this idiom will be copied.

What I checked

  • The pin resolves: python3 -m agentic_os.prod_install_ref ward returns v0.887.0, so the ref is pinned rather than floating.
  • curl -fsSL with retries, over HTTPS, from the same host that publishes the release.
  • install -m 0755 then "${out}" --version as a smoke test, so a corrupt-but-verified binary still gets caught by refusing to run.
  • Dockerfile parity is real rather than asserted. docker/dev-base/full/Dockerfile:26-35 uses the same ward-linux-${arch}, the same SHA256SUMS, and the same grep ... | sha256sum -c - shape. Binding the two with a test so they cannot drift into different verification stories is the right instinct, and it is the same lesson as the typos entry in #1186.

Checking that half of #606 was already done before rewriting it is the fourth time today that reading first saved the work.

The comment attributes the guard to the wrong option

set -euo pipefail
...
# Fails closed: an absent line makes grep exit non-zero under `set -e`, so a
# missing checksum is never the same as a passing one.
(cd "${tmpdir}" && grep "[[:space:]]${asset}\$" SHA256SUMS | sha256sum -c -)

grep is not the last command in that pipeline, so set -e alone does not see its exit status. pipefail is what carries the guarantee, and the comment credits set -e.

Measured, on this machine:

set -euo pipefail   asset absent from SHA256SUMS  ->  pipeline fails, install never reached
set -e only         asset absent from SHA256SUMS  ->  "REACHED INSTALL" printed

A caveat I should state rather than hide: this host has Darwin's sha256sum (1.0), which exits 0 on empty stdin. GNU coreutils exits 1 there with "no properly formatted checksum lines found", so on a Linux runner the set -e-only variant would probably still fail, by luck rather than by the stated mechanism. I could not test that here, and CI is Linux, so the shipped script is correct on both counts and nothing is at risk today.

The reason it is still worth a word: this repo ships scripts and hooks to five others, set -e without pipefail is a very common way to write bash, and the comment reads as a general licence for the idiom. Someone copies the pattern, drops pipefail, and inherits a verification step whose correctness now depends on which sha256sum is on the box.

One-word fix: say pipefail where it says set -e. Or make it structural and lose the dependency:

grep -q "[[:space:]]${asset}\$" SHA256SUMS || { echo "no checksum for ${asset}" >&2; exit 1; }
(cd "${tmpdir}" && grep "[[:space:]]${asset}\$" SHA256SUMS | sha256sum -c -)

Not blocking. The behaviour is right, only its explanation is off, and the explanation is the part that travels.

**Verified the security-relevant parts by running them. The guard holds as shipped. One comment names the wrong mechanism, which matters because this idiom will be copied.** ## What I checked * The pin resolves: `python3 -m agentic_os.prod_install_ref ward` returns `v0.887.0`, so the ref is pinned rather than floating. * `curl -fsSL` with retries, over HTTPS, from the same host that publishes the release. * `install -m 0755` then `"${out}" --version` as a smoke test, so a corrupt-but-verified binary still gets caught by refusing to run. * Dockerfile parity is real rather than asserted. `docker/dev-base/full/Dockerfile:26-35` uses the same `ward-linux-${arch}`, the same `SHA256SUMS`, and the same `grep ... | sha256sum -c -` shape. Binding the two with a test so they cannot drift into different verification stories is the right instinct, and it is the same lesson as the `typos` entry in #1186. Checking that half of #606 was already done before rewriting it is the fourth time today that reading first saved the work. ## The comment attributes the guard to the wrong option ```sh set -euo pipefail ... # Fails closed: an absent line makes grep exit non-zero under `set -e`, so a # missing checksum is never the same as a passing one. (cd "${tmpdir}" && grep "[[:space:]]${asset}\$" SHA256SUMS | sha256sum -c -) ``` `grep` is not the last command in that pipeline, so `set -e` alone does not see its exit status. **`pipefail` is what carries the guarantee**, and the comment credits `set -e`. Measured, on this machine: ``` set -euo pipefail asset absent from SHA256SUMS -> pipeline fails, install never reached set -e only asset absent from SHA256SUMS -> "REACHED INSTALL" printed ``` **A caveat I should state rather than hide:** this host has Darwin's `sha256sum` (1.0), which exits 0 on empty stdin. GNU coreutils exits 1 there with "no properly formatted checksum lines found", so on a Linux runner the `set -e`-only variant would probably still fail, by luck rather than by the stated mechanism. I could not test that here, and CI is Linux, so **the shipped script is correct on both counts and nothing is at risk today**. The reason it is still worth a word: this repo ships scripts and hooks to five others, `set -e` without `pipefail` is a very common way to write bash, and the comment reads as a general licence for the idiom. Someone copies the pattern, drops `pipefail`, and inherits a verification step whose correctness now depends on which `sha256sum` is on the box. One-word fix: say `pipefail` where it says `set -e`. Or make it structural and lose the dependency: ```sh grep -q "[[:space:]]${asset}\$" SHA256SUMS || { echo "no checksum for ${asset}" >&2; exit 1; } (cd "${tmpdir}" && grep "[[:space:]]${asset}\$" SHA256SUMS | sha256sum -c -) ``` Not blocking. The behaviour is right, only its explanation is off, and the explanation is the part that travels.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1213
No description provided.