From 020b84233ce10175410822abebc2f8814b5dedb0 Mon Sep 17 00:00:00 2001 From: Tom Brow Date: Mon, 12 Oct 2026 11:44:26 -0700 Subject: [PATCH] fix: enforce stable Xcode in desktop dev recipes Signed-off-by: Tom Brow --- Justfile | 4 ++++ .../protectedFeatures/tauriCommand.test.mjs | 2 +- scripts/check-xcode.sh | 7 +++++-- scripts/test-xcode-version.sh | 21 ++++++++++++++++++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Justfile b/Justfile index 69edf3e155..2fb44361ce 100644 --- a/Justfile +++ b/Justfile @@ -771,6 +771,7 @@ relay-release: bootstrap _ensure-migrations dev *ARGS: bootstrap _ensure-sidecar-stubs _ensure-migrations #!/usr/bin/env bash set -euo pipefail + ./scripts/check-xcode.sh export PATH="{{justfile_directory()}}/bin:$PATH" set -o allexport source .env @@ -833,6 +834,7 @@ dev *ARGS: bootstrap _ensure-sidecar-stubs _ensure-migrations desktop-standalone *ARGS: _ensure-sidecar-stubs #!/usr/bin/env bash set -euo pipefail + ./scripts/check-xcode.sh export PATH="{{justfile_directory()}}/bin:$PATH" cargo build -p buzz-acp -p buzz-agent -p buzz-backend-kubernetes -p buzz-dev-mcp -p buzz-cli -p git-credential-nostr TARGET=$(rustc -vV | sed -n 's|host: ||p') @@ -865,6 +867,7 @@ desktop-standalone *ARGS: _ensure-sidecar-stubs staging *ARGS: bootstrap _ensure-sidecar-stubs #!/usr/bin/env bash set -euo pipefail + ./scripts/check-xcode.sh export PATH="{{justfile_directory()}}/bin:$PATH" pnpm install # unconditional: staging must always start with a clean dep tree cargo build --release -p buzz-acp -p buzz-agent -p buzz-backend-kubernetes -p buzz-dev-mcp -p buzz-cli -p git-credential-nostr @@ -900,6 +903,7 @@ staging *ARGS: bootstrap _ensure-sidecar-stubs production *ARGS: bootstrap _ensure-sidecar-stubs #!/usr/bin/env bash set -euo pipefail + ./scripts/check-xcode.sh export PATH="{{justfile_directory()}}/bin:$PATH" pnpm install # unconditional: production must always start with a clean dep tree cargo build --release -p buzz-acp -p buzz-agent -p buzz-backend-kubernetes -p buzz-dev-mcp -p buzz-cli -p git-credential-nostr diff --git a/desktop/src/protectedFeatures/tauriCommand.test.mjs b/desktop/src/protectedFeatures/tauriCommand.test.mjs index ed461852c5..c7ab8e0886 100644 --- a/desktop/src/protectedFeatures/tauriCommand.test.mjs +++ b/desktop/src/protectedFeatures/tauriCommand.test.mjs @@ -26,7 +26,7 @@ const pinnedXcode = readFileSync( writeFileSync( path.join(toolDir, "xcodebuild"), `#!/bin/sh -printf 'Xcode %s\\nBuild version fixture\\n' "\${TEST_XCODE_VERSION}" +printf 'Xcode %s\\nBuild version 27A266a\\n' "\${TEST_XCODE_VERSION}" `, { mode: 0o755 }, ); diff --git a/scripts/check-xcode.sh b/scripts/check-xcode.sh index 50f69d8d85..99692c5f91 100755 --- a/scripts/check-xcode.sh +++ b/scripts/check-xcode.sh @@ -12,11 +12,14 @@ if ! version="$(xcodebuild -version)"; then echo "Buzz requires Xcode $expected. Set DEVELOPER_DIR to its Xcode.app/Contents/Developer." >&2 exit 1 fi +# Stable Xcode 27.0; marketing versions alone also match prereleases. +expected_build=27A266a +actual_build="$(printf '%s\n' "$version" | sed -n 's/^Build version //p')" actual="$(printf '%s\n' "$version" | sed -n 's/^Xcode //p')" [[ "$actual" == *.* ]] || actual="$actual.0" [[ "$actual" == *.*.* ]] || actual="$actual.0" -if [[ "$actual" != "$expected" ]]; then - echo "Buzz requires Xcode $expected (.xcode-version); active toolchain reports: $version" >&2 +if [[ "$actual" != "$expected" || "$actual_build" != "$expected_build" ]]; then + echo "Buzz requires Xcode $expected (build $expected_build, .xcode-version); active toolchain reports: $version" >&2 echo "Set DEVELOPER_DIR to the matching Xcode.app/Contents/Developer and retry." >&2 exit 1 fi diff --git a/scripts/test-xcode-version.sh b/scripts/test-xcode-version.sh index 54e251f782..abc0be9d0c 100755 --- a/scripts/test-xcode-version.sh +++ b/scripts/test-xcode-version.sh @@ -14,7 +14,7 @@ STUB cat > "$fixture/bin/xcodebuild" <<'STUB' #!/usr/bin/env bash [[ "${TEST_XCODE:-}" != broken ]] || exit 1 -printf 'Xcode %s\nBuild version fixture\n' "$TEST_XCODE" +printf 'Xcode %s\nBuild version %s\n' "$TEST_XCODE" "${TEST_XCODE_BUILD:-27A266a}" STUB chmod +x "$fixture/bin/"* export PATH="$fixture/bin:$PATH" @@ -27,6 +27,25 @@ for TEST_XCODE in 26.6 27.1 '27.0 beta' broken ''; do export TEST_XCODE if check; then echo "Accepted wrong Xcode: $TEST_XCODE" >&2; exit 1; fi done +TEST_XCODE=27.0 +if TEST_XCODE_BUILD=27A123b check; then echo 'Accepted prerelease build' >&2; exit 1; fi +# Run the real standalone recipe body in an isolated fixture. It must reject +# the compiler before starting cargo or any desktop/device work. +{ + printf "desktop_dir := 'desktop'\nmesh := ''\nfresh := ''\n" + awk '/^desktop-standalone \*ARGS:/ { active=1; print "desktop-standalone *ARGS:"; next } active && /^$/ { exit } active { print }' "$root/Justfile" +} > "$fixture/Justfile" +cat > "$fixture/bin/cargo" <<'STUB' +#!/usr/bin/env bash +echo 'Native build started before Xcode validation' >&2 +exit 99 +STUB +chmod +x "$fixture/bin/cargo" +if TEST_XCODE=26.5 "$root/bin/just" --justfile "$fixture/Justfile" desktop-standalone >"$fixture/recipe.log" 2>&1; then + echo 'Standalone recipe accepted wrong Xcode' >&2; exit 1 +fi +grep -q 'Buzz requires Xcode' "$fixture/recipe.log" +if grep -q 'Native build started' "$fixture/recipe.log"; then cat "$fixture/recipe.log"; exit 1; fi printf 'latest\n' > "$fixture/.xcode-version" if check; then echo 'Accepted invalid pin' >&2; exit 1; fi TEST_OS=Linux check