fix(ci): install Ward from release artifacts, not from source (#606) #1213
No reviewers
Labels
No labels
burndown-2026-06
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/agentic-os!1213
Loading…
Reference in a new issue
No description provided.
Delete branch "aos/606-ward-release-artifacts"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #606.
Half of it was already done
docker/dev-base/full/Dockerfilealready downloadsward-linux-${TARGETARCH}withSHA256SUMSand verifies before installing. Checked that first rather than rewriting it.scripts/install-workflow-ward.shwas the remaining source build. It cloned Ward and rango 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 -mmaps toamd64orarm64, 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, andsha256sum -c -, so the two paths cannot drift into different verification stories.Failing closed, twice
sha256sum -c.grepexit non-zero underset -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, andsha256sum: four architecture mappings, an unsupported architecture, a corrupt checksum, an absent checksum line, no Go dependency, noward.gitorcmd/wardin either path, and the shared contract.The late
ward doctorgate against the real.wardbundle is untouched on bothciandpromote.684 tests pass,
pre-commit run --all-filespasses.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: engineerVerified 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
python3 -m agentic_os.prod_install_ref wardreturnsv0.887.0, so the ref is pinned rather than floating.curl -fsSLwith retries, over HTTPS, from the same host that publishes the release.install -m 0755then"${out}" --versionas a smoke test, so a corrupt-but-verified binary still gets caught by refusing to run.docker/dev-base/full/Dockerfile:26-35uses the sameward-linux-${arch}, the sameSHA256SUMS, and the samegrep ... | 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 thetyposentry 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
grepis not the last command in that pipeline, soset -ealone does not see its exit status.pipefailis what carries the guarantee, and the comment creditsset -e.Measured, on this machine:
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 theset -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 -ewithoutpipefailis a very common way to write bash, and the comment reads as a general licence for the idiom. Someone copies the pattern, dropspipefail, and inherits a verification step whose correctness now depends on whichsha256sumis on the box.One-word fix: say
pipefailwhere it saysset -e. Or make it structural and lose the dependency:Not blocking. The behaviour is right, only its explanation is off, and the explanation is the part that travels.