diff --git a/.tangled/workflows/admission.yml b/.tangled/workflows/admission.yml index 5785ea1..37c6ce2 100644 --- a/.tangled/workflows/admission.yml +++ b/.tangled/workflows/admission.yml @@ -57,17 +57,39 @@ steps: command: | set -euo pipefail source /tmp/env.sh - printf '%s' "$ATCR_APP_PASSWORD" | docker login atcr.io -u zat.dev --password-stdin + printf '%s' "$ATCR_APP_PASSWORD" | docker login atcr.io -u zat.dev --password-stdin || true ./scripts/admit run - ./scripts/admit publish - - name: push receipt back + - name: publish image (best effort) + command: | + set -uo pipefail + # The registry can refuse a push for reasons unrelated to admission + # (an over-quota account denies every write scope). That must not + # discard a passing gate: the receipt already binds the local image id, + # and `admit publish` can pin the registry digest later. + source /tmp/env.sh + ./scripts/admit publish || echo "WARN: publish failed; receipt keeps its local image id" + + - name: emit receipt command: | set -euo pipefail + # The receipt is the artifact of this workflow. Print it unconditionally + # so a run is useful with no repo-write credential at all; the push-back + # below is a convenience, never a gate. + sha=$(git rev-parse --short HEAD) + echo "===== receipt $sha =====" + cat receipts/"$sha".json + echo "===== end receipt =====" + + - name: push receipt back (optional) + command: | + set -uo pipefail + # Needs a repo-write credential (ADMIT_BOT_APP_PASSWORD). Without one + # this step warns and the run still passes — the receipt is in the log. sha=$(git rev-parse --short HEAD) - git add receipts/"$sha".json - git -c user.name=admit-bot -c user.email=bot@zat.dev commit -m "receipt: $sha admitted via spindle" - git push -o skip-ci origin HEAD:main # needs ADMIT_BOT_APP_PASSWORD wired into the remote or a token remote + git add receipts/"$sha".json || true + git -c user.name=admit-bot -c user.email=bot@zat.dev commit -m "receipt: $sha admitted via spindle" || true + git push -o skip-ci origin HEAD:main || echo "WARN: receipt not pushed back; copy it from the log above" # REMAINING UNKNOWNS (answered by the first run, not by theory): # 1. microVM resource caps / workflow timeout on the hosted spindle (suite diff --git a/.tangled/workflows/publish-image.yml b/.tangled/workflows/publish-image.yml index 1dd6a63..5d04515 100644 --- a/.tangled/workflows/publish-image.yml +++ b/.tangled/workflows/publish-image.yml @@ -41,6 +41,4 @@ steps: --dockerfile=$(pwd)/Dockerfile \ --destination="atcr.io/zat.dev/stream:$TANGLED_COMMIT_SHA" \ --push-retry=3 \ - --skip-push-permission-check \ - --cache=true \ - --cache-repo=atcr.io/zat.dev/stream/cache + --skip-push-permission-check diff --git a/tests/powerloss_oracle.py b/tests/powerloss_oracle.py index 395f68e..73090b5 100644 --- a/tests/powerloss_oracle.py +++ b/tests/powerloss_oracle.py @@ -275,9 +275,14 @@ def stop_device(*, graceful=False): if graceful: dexec_sh("sync", check=False) dexec_sh("pkill -9 -x nbdkit 2>/dev/null || true", check=False) - dexec_sh("timeout 5 umount -l /mnt/strict 2>/dev/null || true", check=False) - dexec_sh(f"timeout 5 nbd-client -d {DEVICE} >/dev/null 2>&1 || true", check=False) - dexec_sh("pkill -9 -x nbd-client 2>/dev/null || true", check=False) + # Disconnect the device BEFORE unmounting. Killing nbdkit leaves the + # kernel device serverless, so any I/O to it — umount included — parks in + # uninterruptible sleep, where the inner `timeout` cannot reach it and the + # `docker exec` itself hangs until the harness times out (2026-08-09, a + # full gate run). Disconnecting first makes that I/O fail with EIO. + dexec_sh(f"timeout 5 nbd-client -d {DEVICE} >/dev/null 2>&1 || true", check=False, timeout=20) + dexec_sh("timeout 5 umount -l /mnt/strict 2>/dev/null || true", check=False, timeout=20) + dexec_sh("pkill -9 -x nbd-client 2>/dev/null || true", check=False, timeout=20) def calibrate(state):