openclaw/scripts/stage-mac-node-worker.sh
Peter Steinberger 299ea7c393
fix(scripts): run macOS tooling under /bin/bash and make the framework-merge fixture self-contained (#141884)
* fix(scripts): use system Bash for macOS tooling and owned Mach-O fixtures

Pin native entrypoints and package commands to /bin/bash, guard portable heredoc callers on Darwin, and preserve Bash 3.2 boolean parsing. Streamed installers explain how to use system Bash when their input cannot be replayed.

Generate deterministic x86_64, arm64, and arm64e framework fixtures instead of borrowing /bin/ls. Preserve the existing framework pipeline repair from #141056 and verify merged slice bytes.

* fix(scripts): keep guarded portable scripts bash 3.2 compatible

* fix(scripts): keep macOS Bash CI coverage green

Distinguish sourced installer returns from stdin exits without ShellCheck unreachable-code warnings. Retain the shebang regression suite in changed-target routing, and repartition hosted tooling tails toward 50-second groups within the existing 150-second budget and 80-job cap.

Validation: 635 interpreter and routing tests plus 53 planner tests passed; ShellCheck, targeted lint, formatting, and fresh Codex review passed. The broader local changed-file check hit an unrelated existing dependency graph crossing through extensions/reef/node_modules/@noble/hashes; exact-head hosted CI remains required.

* docs(install): use system Bash in install and recovery commands

Align macOS-facing copy-and-paste commands and emitted installer guidance with the supported streamed interpreter. This addresses the remaining installer-command review finding without changing the PR body.

Validation: streamed help for both installers, install.sh dry-run, 16 selected fresh-install and upgrade lifecycle tests, formatting, diff check, and fresh Codex review passed. Landing remains blocked by unrelated provider-transport integration CI failure caused by an unchanged incomplete plugin-registry mock.

* fix(scripts): preserve streamed installs and CI packing

Keep public installer commands portable while replaying Darwin Bash 5.3+
stdin under system Bash through an immediately unlinked private temp file.
Retain actionable sourced-install rejection and the SC2317-safe check.

Restore the original CI packing policy and move the Bash policy scan into
its existing macOS tooling owner without adding a routed test file.

Validation: real Homebrew Bash streamed help and cleanup; 642 scan/routing
tests; 23 selected installer tests under both PATH orders; planner cap and
coverage tests; 139 Bash syntax checks; ShellCheck; 1,135 changed-gate tests;
focused lint/changed-check repair; fresh Codex review with no P0/P1 findings.
2026-09-08 01:21:30 -07:00

75 lines
3.5 KiB
Bash
Executable file

#!/bin/bash
set -euo pipefail
# Called after the canonical source build, before the app is signed. The
# complete npm artifact owns dependency selection; this is not a dist closure.
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
DESTINATION="$1"
shift
[[ "$#" -gt 0 ]] || { echo "ERROR: No worker architectures requested" >&2; exit 1; }
case "${OPENCLAW_MAC_SIGNING_VARIANT:-standard}" in
standard|elevation-host) ;;
*) echo "ERROR: Unknown Mac signing variant" >&2; exit 1 ;;
esac
# Scratch follows the caller's temp volume; only installed payloads need to
# share the destination volume so publishing remains a rename, not a copy.
SCRATCH="$(mktemp -d "${TMPDIR:-/tmp}/openclaw-mac-worker.XXXXXX")"
trap 'rm -rf "$SCRATCH"' EXIT
mkdir -p "$(dirname "$DESTINATION")"
STAGE="$(cd "$(dirname "$DESTINATION")" && mktemp -d "$PWD/.openclaw-mac-worker.XXXXXX")"
trap 'rm -rf "$STAGE" "$SCRATCH"' EXIT
mkdir -p "$SCRATCH/home" "$SCRATCH/package"
# Lifecycle hooks must never see operator config, credentials, or state;
# installer main discovers launchd by UID even with a new HOME.
# Use the build's pinned pnpm packer, not the host npm's expanding file globs.
TARBALL="$(env -i HOME="$SCRATCH/home" PATH="$PATH" TMPDIR="$SCRATCH" \
node "$ROOT_DIR/scripts/package-openclaw-for-docker.mjs" \
--skip-build --pnpm-pack --allow-unreleased-changelog --output-dir "$SCRATCH/package" \
--output-name openclaw.tgz)"
[[ -f "$TARBALL" ]] || { echo "ERROR: Canonical worker package missing" >&2; exit 1; }
for arch in "$@"; do
case "$arch" in
arm64) node_arch=arm64 ;;
x86_64) node_arch=x64 ;;
*) echo "ERROR: Unsupported Mac worker architecture: $arch" >&2; exit 1 ;;
esac
mkdir -p "$SCRATCH/$arch/home" "$SCRATCH/$arch/tmp"
env -i HOME="$SCRATCH/$arch/home" PATH="/usr/bin:/bin:/usr/sbin:/sbin" \
TMPDIR="$SCRATCH/$arch/tmp" OPENCLAW_INSTALL_CLI_SH_NO_RUN=1 \
/bin/bash -c '
set -euo pipefail
source "$1/scripts/install-cli.sh"
PREFIX="$2/prefix"
OPENCLAW_VERSION="$3"
install_node darwin "$4"
export PATH="$(node_dir)/bin:$PATH"
"$(node_bin)" -e '\''if (process.arch !== process.argv[1]) process.exit(1)'\'' "$4" || {
echo "ERROR: Cannot execute requested Node architecture $4; x64 on ARM requires Rosetta" >&2
exit 1
}
install_openclaw
mv "$(node_dir)" "$2/installed"
' bash "$ROOT_DIR" "$STAGE/$arch" "$TARBALL" "$node_arch"
# Unused Intel prebuilds can trigger macOS compatibility warnings even when
# the app and its selected worker are native Apple silicon.
env -i HOME="$SCRATCH/$arch/home" PATH="/usr/bin:/bin:/usr/sbin:/sbin" \
TMPDIR="$SCRATCH/$arch/tmp" /usr/bin/python3 -B "$ROOT_DIR/scripts/materialize-mac-node-worker.py" \
"$STAGE/$arch/installed" "$STAGE/$arch/runtime" "$STAGE/$arch" "$arch"
# Validate after moving out of its install prefix: absolute wrappers/symlinks
# cannot accidentally make a non-relocatable payload pass the proof.
env -i HOME="$SCRATCH/$arch/home" PATH="/usr/bin:/bin:/usr/sbin:/sbin" \
TMPDIR="$SCRATCH/$arch/tmp" \
"$STAGE/$arch/runtime/bin/node" "$ROOT_DIR/scripts/verify-mac-node-worker.mjs" \
"$STAGE/$arch/runtime" "$ROOT_DIR/dist/build-info.json"
done
mkdir -p "$DESTINATION"
# The packager owns this private parent; reject every occupant before any move.
for arch in "$@"; do
[[ ! -e "$DESTINATION/$arch" && ! -L "$DESTINATION/$arch" ]] || { echo "ERROR: Worker destination exists: $DESTINATION/$arch" >&2; exit 1; }
done
for arch in "$@"; do
mv "$STAGE/$arch/runtime" "$DESTINATION/$arch"
done