← all scripts

.github/scripts/dev_alias_live.sh

92 of 92 statements covered (100.00%).

coveredmissednever traced by Bash (not counted)A line ending in … continues the statement above it and shares its fate.

118#!/usr/bin/env bash
2#
3# dev_alias_live.sh — LIVE proof that scripts/setup-dev-alias.sh generates a
4# working `gco` shell function against a real container runtime, using the real
5# gco-dev image.
6#
7# tests/BATS/test_setup_dev_alias.bats mocks the runtimes and only inspects the
8# emitted text. This script closes that gap end to end: it runs
9# scripts/setup-dev-alias.sh to build the real gco-dev image and install the
10# generated function into a throwaway rc, sources it in a fresh shell, and
11# proves through that function:
12# * `gco --version` — the real CLI runs (and the arg reaches it)
13# * `gco dag validate <rel>/ci-dag.yaml` — an offline command that reads files
14# from the mounted workspace via a
15# *relative* path, proving arg-forwarding,
16# the $PWD -> /workspace bind mount, and
17# cwd=/workspace all at once.
18#
19# Dockerfile.dev installs the CLI editable (`pip install -e .`) at /workspace,
20# so the generated function must be run from the project directory: it mounts
21# $PWD at /workspace, and gco resolves its source there. We therefore run from
22# the repo root and drop the DAG fixture into a throwaway subdirectory of it.
23#
24# Modes:
25# dev_alias_live.sh <docker|finch|podman> [--skip-build] [--image NAME]
26# dev_alias_live.sh --no-runtime
27#
28# Privilege note: on Linux, finch talks to a root-owned daemon, so the finch CI
29# job invokes this via sudo. docker (docker group) and podman (rootless) run it
30# as the normal user. This script never calls sudo itself.
3122set -euo pipefail
32
33# The checkout to prove: normally the one this script lives in. The BATS suite
34# points GCO_DEV_ALIAS_LIVE_REPO_ROOT at a disposable fixture (carrying the
35# setup script and answering runtimes on PATH) so the tracked script runs in
36# place without writing its DAG fixture into a real checkout.
3771REPO_ROOT="$(cd "${GCO_DEV_ALIAS_LIVE_REPO_ROOT:-$(dirname "${BASH_SOURCE[0]}")/../..}" && pwd)"
3822SETUP="$REPO_ROOT/scripts/setup-dev-alias.sh"
39
4022RUNTIME=""
4122MODE="runtime"
4222IMAGE="gco-dev"
4322SKIP_BUILD=0
44
4532die() { printf 'FAIL: %s\n' "$*" >&2; exit 1; }
4647note() { printf '\n=== %s ===\n' "$*"; }
47
4848while [ "$#" -gt 0 ]; do
4931 case "$1" in
506 --no-runtime) MODE="none"; shift ;;
5110 --skip-build) SKIP_BUILD=1; shift ;;
528 --image) [ "$#" -ge 2 ] || die "--image needs a value"; IMAGE="$2"; shift 2 ;;
532 --image=*) IMAGE="${1#*=}"; shift ;;
5430 docker|finch|podman) RUNTIME="$1"; shift ;;
553 -h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
561 *) die "usage: dev_alias_live.sh <docker|finch|podman> [--skip-build] [--image NAME] | --no-runtime (got: $1)" ;;
57 esac
58done
59
6020[ -x "$SETUP" ] || die "setup script not found or not executable: $SETUP"
61
6236WORK="$(mktemp -d)"
6318FIXTURE_DIR="" # a throwaway subdir of the repo; set + cleaned up below
64cleanup() {
6518 rm -rf "$WORK" 2>/dev/null || true
6626 [ -n "$FIXTURE_DIR" ] && rm -rf "$FIXTURE_DIR" 2>/dev/null
6718 return 0
68}
6918trap cleanup EXIT
70
71# ---------------------------------------------------------------------------
72# Mode: no-runtime — prove graceful refusal.
73# ---------------------------------------------------------------------------
7418if [ "$MODE" = "none" ]; then
753 note "no-runtime refusal"
76 # Mask any real runtimes with stubs that fail `<rt> info`, so detection sees
77 # "installed but not answering" for all three — the same code path as "not
78 # installed at all". The rest of PATH still resolves awk/mktemp/etc.
793 stub="$WORK/stub-bin"
803 mkdir -p "$stub"
819 for rt in docker finch podman; do
829 printf '#!/bin/sh\nexit 1\n' >"$stub/$rt"
839 chmod +x "$stub/$rt"
84 done
853 rc="$WORK/rc-none"
863 set +e
8715 out="$(PATH="$stub:$PATH" GCO_CONTAINER_RUNTIME='' CDK_DOCKER='' "$SETUP" --rc "$rc" 2>&1)"
883 code=$?
893 set -e
906 printf '%s\n' "$out" | sed 's/^/ | /'
913 [ "$code" -ne 0 ] || die "expected a non-zero exit when no runtime answers (got 0)"
926 printf '%s\n' "$out" | grep -qi 'no container runtime' \
931 || die "expected 'no container runtime' guidance in the output"
943 if [ -f "$rc" ] && grep -q '>>> gco >>>' "$rc"; then
951 die "rc must not contain a gco function block when no runtime is available"
96 fi
971 printf 'PASS: script refused with guidance and wrote no gco function.\n'
981 exit 0
99fi
100
101# ---------------------------------------------------------------------------
102# Mode: runtime — preflight.
103# ---------------------------------------------------------------------------
10416[ -n "$RUNTIME" ] || die "a runtime (docker|finch|podman) or --no-runtime is required"
105
10614note "preflight: $RUNTIME"
10715command -v "$RUNTIME" >/dev/null 2>&1 || die "$RUNTIME is not on PATH"
10814"$RUNTIME" info >/dev/null 2>&1 || die "$RUNTIME is installed but '$RUNTIME info' does not answer"
10912"$RUNTIME" --version || true
110
111# ---------------------------------------------------------------------------
112# Setup GCO: setup-dev-alias.sh builds the dev image and installs the function.
113# ---------------------------------------------------------------------------
114# Building the image is the setup script's own job, so the normal path lets it
115# do exactly that: this is the end-to-end proof that `setup-dev-alias.sh` builds
116# gco-dev *and* wires up the alias in a single run. --skip-build instead reuses
117# an already-built image and tells the script to skip its build.
11812rc="$WORK/rc"
11912if [ "$SKIP_BUILD" -eq 1 ]; then
1205 note "using existing image: $IMAGE (--skip-build); setup-dev-alias.sh --no-build"
1215 "$RUNTIME" image inspect "$IMAGE" >/dev/null 2>&1 \
1221 || die "--skip-build set but image '$IMAGE' was not found in $RUNTIME"
1234 "$SETUP" --runtime "$RUNTIME" --image "$IMAGE" --no-build --rc "$rc" >/dev/null \
1241 || die "setup-dev-alias.sh failed to install the gco function for $RUNTIME"
125else
1267 note "setup GCO: setup-dev-alias.sh builds $IMAGE from Dockerfile.dev with $RUNTIME and installs the function"
127 # The build pulls the base image from Docker Hub, whose registry endpoints
128 # intermittently time out on GitHub runners. Retry the whole setup run
129 # (build + rc write, both idempotent; completed layers stay cached) so a
130 # transient registry blip does not fail the job — or, in the podman job,
131 # masquerade as an OCI-runtime configuration failure and burn one of its
132 # crun/runc attempts.
1337 build_ok=0
1347 retry_delay=15
13510 for attempt in 1 2 3; do
13610 if "$SETUP" --runtime "$RUNTIME" --image "$IMAGE" --rc "$rc"; then
1376 build_ok=1
1386 break
139 fi
1404 if [ "$attempt" -lt 3 ]; then
1413 printf 'setup-dev-alias.sh failed (attempt %s/3); retrying in %ss (usually a transient registry/network error)\n' \
142 "$attempt" "$retry_delay" >&2
1433 sleep "$retry_delay"
1443 retry_delay=$((retry_delay * 2))
145 fi
146 done
1477 [ "$build_ok" -eq 1 ] \
1481 || die "setup-dev-alias.sh failed to build $IMAGE / install the gco function for $RUNTIME (after 3 attempts)"
149fi
15010grep -q '>>> gco >>>' "$rc" || die "setup script did not write a gco function block"
151
152# ---------------------------------------------------------------------------
153# Workspace fixture. The dev image's editable install needs the repo at
154# /workspace, so we run from the repo root (the function mounts $PWD) and drop
155# the DAG fixture into a throwaway subdir of it. The DAG references its manifest
156# by a path relative to cwd; DagDefinition.validate() checks both the DAG and
157# the manifest exist, so a successful validate proves the bind mount surfaced
158# the files and that cwd is /workspace.
159# ---------------------------------------------------------------------------
1608FIXTURE_REL=".gco_dev_alias_live.$$"
1618FIXTURE_DIR="$REPO_ROOT/$FIXTURE_REL"
1628mkdir -p "$FIXTURE_DIR"
1638printf '# placeholder job manifest for the dev-alias live proof\n' >"$FIXTURE_DIR/probe-job.yaml"
1648cat >"$FIXTURE_DIR/ci-dag.yaml" <<YAML
165name: dev-alias-live-probe
166steps:
167 - name: probe
168 manifest: $FIXTURE_REL/probe-job.yaml
169YAML
170
171# Run under the real $HOME so that rootless podman's image store
172# (~/.local/share/containers) is the same one the build above wrote to.
173# Overriding HOME here would point podman at an empty store and it would try
174# to *pull* the locally-built image (docker is daemon-wide and finch is
175# rootful, so neither is HOME-sensitive — but podman is).
1768mkdir -p "$HOME/.aws" # the generated function bind-mounts ~/.aws read-only
177
178# ---------------------------------------------------------------------------
179# Proof 1: the real CLI runs through the generated function (run from the repo
180# root so the editable install resolves cli/ + gco/ at /workspace).
181# ---------------------------------------------------------------------------
1828note "prove the real gco CLI runs through the generated function"
18324if ! ver="$(cd "$REPO_ROOT" && bash --noprofile --norc -c ". '$rc'; gco --version" 2>&1)"; then
1842 printf '%s\n' "$ver" | sed 's/^/ | /'
1851 die "'gco --version' failed through the generated function"
186fi
1877printf ' gco --version -> %s\n' "$ver"
1888[ -n "$ver" ] || die "'gco --version' produced no output"
189
190# ---------------------------------------------------------------------------
191# Proof 2: arg-forwarding + workspace bind mount + cwd, via an offline command.
192# The relative path resolves only if $PWD was mounted at /workspace and cwd is
193# /workspace; gco dag validate then reads both the DAG and its manifest.
194# ---------------------------------------------------------------------------
1956note "prove arg-forwarding + workspace bind mount + cwd via 'gco dag validate'"
19618if ! out="$(cd "$REPO_ROOT" && bash --noprofile --norc -c ". '$rc'; gco dag validate '$FIXTURE_REL/ci-dag.yaml'" 2>&1)"; then
1972 printf '%s\n' "$out" | sed 's/^/ | /'
1981 die "'gco dag validate $FIXTURE_REL/ci-dag.yaml' failed through the generated function"
199fi
20010printf '%s\n' "$out" | sed 's/^/ | /'
20110printf '%s\n' "$out" | grep -qi 'is valid' \
2021 || die "expected 'is valid' (workspace bind mount or cwd not wired correctly)"
203
2044note "ALL CHECKS PASSED for $RUNTIME"