Skip to content

Commit 6fe9694

Browse files
Auto-install pinned Zig toolchain in setup + devcontainer (#41)
## What & why The Zig FFI bridge is half of the ABI-FFI standard, but nothing installed Zig — `.tool-versions` only lists it (commented), `setup.sh` stopped at `just`, and the devcontainer's `postCreateCommand: just deps` referenced a `deps` recipe that didn't exist. And Zig is **not** distributed via GitHub releases, so it must come from `ziglang.org`, which isn't on the agent egress allowlist by default. ## Change - **`scripts/install-zig.sh`** — idempotent, fail-soft installer for the pinned **Zig 0.14.0** (arch/OS-aware, uses the proxy-populated system CA store, never `--insecure`). If `ziglang.org` is blocked it 403s and exits 0 with an actionable message, so it never blocks setup. - **`setup.sh`** — adds a Zig install step (where the template exposes one). - **`Justfile`** — new `deps` recipe (install Zig + `cargo fetch`) backing the devcontainer `postCreateCommand: just deps`. Once `ziglang.org` is allowlisted, future setups/dev-containers install Zig automatically. Part of a family-wide sweep; mirrors the merged iseriser reference (#70). ## CI note The `rust-ci` and `Hypatia` checks are **pre-existing estate-infra reds** (the reusable rust-ci workflow's empty `toolchain` input, and the Hypatia analyzer failing to compile its own Elixir source) — neither is caused by this shell/Justfile change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019xMKB3T4Vo5FYC7Czx3JSH --- _Generated by [Claude Code](https://claude.ai/code/session_019xMKB3T4Vo5FYC7Czx3JSH)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent b3caa84 commit 6fe9694

2 files changed

Lines changed: 65 additions & 0 deletions

File tree

Justfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,9 @@ crg-badge:
193193
D) color="orange" ;; E) color="red" ;; F) color="critical" ;; \
194194
*) color="lightgrey" ;; esac; \
195195
echo "[![CRG $$grade](https://img.shields.io/badge/CRG-$$grade-$$color?style=flat-square)](https://github.com/hyperpolymath/standards/tree/main/component-readiness-grades)"
196+
197+
# Install dev dependencies (invoked by the devcontainer postCreateCommand).
198+
# Installs the pinned Zig FFI toolchain, then warms the Cargo cache.
199+
deps:
200+
./scripts/install-zig.sh
201+
cargo fetch

scripts/install-zig.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/sh
2+
# SPDX-License-Identifier: MPL-2.0
3+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
4+
#
5+
# install-zig.sh — install the pinned Zig toolchain (the Zig FFI bridge half of
6+
# the ABI-FFI standard). Idempotent and fail-soft: it never aborts the caller.
7+
#
8+
# Egress note: Zig is NOT distributed via GitHub releases, so it is fetched from
9+
# ziglang.org. Inside a Claude Code session, outbound HTTPS goes through the
10+
# policy-enforcing agent proxy; github.com is allowlisted by default but
11+
# ziglang.org must be added explicitly, or this download returns 403. We use the
12+
# system CA store the proxy already populated — never pass --insecure.
13+
set -eu
14+
15+
ZIG_VERSION="${ZIG_VERSION:-0.14.0}"
16+
PREFIX="${ZIG_PREFIX:-/usr/local}"
17+
18+
# Already at the pinned version? Done.
19+
if command -v zig >/dev/null 2>&1 && [ "$(zig version 2>/dev/null)" = "$ZIG_VERSION" ]; then
20+
echo "install-zig: zig $ZIG_VERSION already installed"
21+
exit 0
22+
fi
23+
24+
# Map host arch/OS to Zig's release naming.
25+
case "$(uname -m)" in
26+
x86_64|amd64) zarch="x86_64" ;;
27+
aarch64|arm64) zarch="aarch64" ;;
28+
*) echo "install-zig: unsupported arch $(uname -m); install Zig $ZIG_VERSION manually" >&2; exit 0 ;;
29+
esac
30+
case "$(uname -s)" in
31+
Linux) zos="linux" ;;
32+
Darwin) zos="macos" ;;
33+
*) echo "install-zig: unsupported OS $(uname -s); install Zig $ZIG_VERSION manually" >&2; exit 0 ;;
34+
esac
35+
36+
tarball="zig-${zos}-${zarch}-${ZIG_VERSION}.tar.xz"
37+
url="https://ziglang.org/download/${ZIG_VERSION}/${tarball}"
38+
dest="${PREFIX}/lib/zig-${ZIG_VERSION}"
39+
40+
tmp="$(mktemp -d)"
41+
trap 'rm -rf "$tmp"' EXIT
42+
43+
echo "install-zig: fetching $url"
44+
if ! curl -fsSL --retry 2 -o "$tmp/$tarball" "$url"; then
45+
echo "install-zig: download failed (HTTP error or blocked host)." >&2
46+
echo "install-zig: if this is a Claude Code session, add 'ziglang.org' to the" >&2
47+
echo " egress allowlist — github.com is allowed but ziglang.org is not." >&2
48+
exit 0 # fail-soft: a missing Zig must not block setup or session start
49+
fi
50+
51+
mkdir -p "$dest" "${PREFIX}/bin"
52+
tar -xJf "$tmp/$tarball" -C "$dest" --strip-components=1
53+
ln -sf "$dest/zig" "${PREFIX}/bin/zig"
54+
55+
if command -v zig >/dev/null 2>&1 && [ "$(zig version 2>/dev/null)" = "$ZIG_VERSION" ]; then
56+
echo "install-zig: installed zig $(zig version)"
57+
else
58+
echo "install-zig: installed to ${PREFIX}/bin/zig — ensure ${PREFIX}/bin is on PATH" >&2
59+
fi

0 commit comments

Comments
 (0)