#!/bin/sh # 1667 Shell Installer — channel stable, version 0.10.8 # Generated release asset. Do not edit. Attest before you trust a local copy. set -eu PRODUCT_VERSION='0.10.8' INSTALL_CHANNEL='stable' GITHUB_REPOSITORY='1667-ai/1667' ASSET_BASE='https://github.com/1667-ai/1667/releases/download/v0.10.8' MAX_ARCHIVE_BYTES=335544320 # Complete decompressed tar stream bound (headers, payloads, padding, terminators). MAX_TAR_BYTES=301989888 # Expanded 1667 executable bound (same shared limit as managed upgrade). MAX_EXECUTABLE_BYTES=268435456 # Cumulative bytes in all regular-file members. MAX_FILE_BYTES=285212672 # Maximum bytes in a canonical Transaction Record before parsing. MAX_TRANSACTION_BYTES=16384 # Portable curl deadlines: connect bound, then overall transfer bound. DOWNLOAD_CONNECT_TIMEOUT_SEC=30 DOWNLOAD_MAX_TIME_SEC=600 OWNERSHIP_FILE='.1667-install.json' LOCK_FILE='.1667-install.lock' TXN_FILE='.1667-install-txn.json' CANDIDATE_FILE='.1667-candidate' PREVIOUS_FILE='.1667-previous' PREVIOUS_NEXT_FILE='.1667-previous.next' PACKAGE_STAGING_FILE='.1667-package.tgz' ACTIVE_FILE='1667' # Exact reserved extract staging under the Install Root (never PID-scoped). EXTRACT_STAGE='.1667-extract' # Bounded candidate version probe (no GNU timeout; portable POSIX shell). PROBE_TIMEOUT_SEC=5 PROBE_MAX_OUTPUT_BLOCKS=8 PROBE_OUTPUT_FILE='.1667-probe-output' # 1 only after this process proves ownership of reserved staging (canonical # Transaction Record, or a verified clean fresh root that starts this install). CLEANUP_OWNS_STAGING=0 # 1 only while this process owns a pre-activation Shell Installer Transaction # Record it wrote into a Managed Installation. The in-binary updater accepts a # Shell Installer record only in the 'activated' phase, so an interrupted # managed bootstrap must not leave one behind. A managed Transaction Record is # never cleared here: recovery needs it to finish or abort a half-applied swap. CLEANUP_CLEAR_TXN=0 MANAGED_FORCE=0 main() { prefix= prefix_set=0 dry_run=0 # --force waives path ownership and other-writer refusals. It never waives a # checksum, an attestation, a release identity, or the version probe: those # decide whether the bytes are the release, which no local layout can answer. force=0 while [ "$#" -gt 0 ]; do case "$1" in --prefix) [ "$#" -ge 2 ] || die "--prefix requires an absolute path" prefix=$2 prefix_set=1 shift 2 ;; --prefix=*) prefix=${1#--prefix=} prefix_set=1 shift ;; --dry-run) dry_run=1 shift ;; --force) force=1 shift ;; -h|--help) usage return 0 ;; *) die "Unknown option: $1" ;; esac done MANAGED_FORCE=$force target=$(detect_target) || exit 1 case "$target" in darwin-arm64) archive='1667_0.10.8_darwin-arm64.tar.gz' ;; darwin-x64) archive='1667_0.10.8_darwin-x64.tar.gz' ;; linux-arm64) archive='1667_0.10.8_linux-arm64.tar.gz' ;; linux-x64) archive='1667_0.10.8_linux-x64.tar.gz' ;; *) die "Unsupported target: $target" ;; esac case "$target" in darwin-arm64) digest='db44c91dc4e6c78aa853acea2ee04d4ee4c51cb24eabd32f7c21da11a8df44d0' ;; darwin-x64) digest='cae980cbfa6e05e67fc7e05330dfa5944d816777979950d63aa249faa19a5271' ;; linux-arm64) digest='85f831c349b3b45dca89a5cdc5472a913dfc8397e5b995debb6dfd3e4d5fc2a0' ;; linux-x64) digest='ba0c528b25de5394989af617b85b9866f0ad36677d88ec0d25abfad5980eceb1' ;; *) die "Unsupported target: $target" ;; esac # No --prefix selects the default. Explicit empty --prefix / --prefix= is usage error. if [ "$prefix_set" -eq 0 ]; then prefix="$HOME/.local/bin" elif [ -z "$prefix" ]; then die "--prefix requires an absolute path" fi case "$prefix" in /*) ;; *) die "--prefix must be an absolute path" ;; esac # Ownership Record installRoot cannot be filesystem root (needs a path component). # Reject before dry-run or mutation so every accepted prefix can produce a record. if [ "$prefix" = "/" ]; then die "--prefix must not be the filesystem root" fi validate_install_root "$prefix" "$force" || exit 1 if [ "$dry_run" -eq 1 ]; then printf 'dry-run: would install 1667 %s (%s) for %s into %s\n' \ "$PRODUCT_VERSION" "$INSTALL_CHANNEL" "$target" "$prefix" printf 'dry-run: archive %s/%s\n' "$ASSET_BASE" "$archive" return 0 fi umask 077 ensure_install_root "$prefix" prefix=$(CDPATH= cd "$prefix" && pwd -P) assert_json_safe_path "$prefix" "Install Root" executable="$prefix/$ACTIVE_FILE" # CLEANUP_OWNS_STAGING stays 0 until recovery validates a txn or the fresh path # verifies a clean root and begins this install. CLEANUP_OWNS_STAGING=0 CLEANUP_CLEAR_TXN=0 acquire_lock "$prefix" # EXIT cleans once. INT/TERM clear traps, clean once, then exit 128+signal. trap 'cleanup_install "$prefix" "$archive"' EXIT trap 'on_install_signal INT "$prefix" "$archive"' INT trap 'on_install_signal TERM "$prefix" "$archive"' TERM # Run recovery in this shell so PROBE_PID is visible to INT/TERM traps. RECOVER_STATUS= recover_install "$prefix" "$executable" "$target" "$digest" "$archive" || exit 1 case "$RECOVER_STATUS" in completed) trap - EXIT INT TERM release_lock "$prefix" ( exec 9>&- trap '' PIPE printf 'Recovered 1667 %s (%s) for %s at %s\n' \ "$PRODUCT_VERSION" "$INSTALL_CHANNEL" "$target" "$executable" ) || : return 0 ;; none|reset|managed-reset|managed-completed) # These statuses intentionally continue into the normal bootstrap path. ;; *) die "Unsupported recovery status: $RECOVER_STATUS" ;; esac managed_install=0 active_version= if [ -e "$executable" ] || [ -L "$executable" ]; then if [ -L "$executable" ] || [ ! -f "$executable" ]; then die "Refusing to replace an unmanaged 1667 at $executable" fi validate_managed_ownership "$prefix" "$executable" "$target" managed_install=1 # A valid Ownership Record proves this root is a managed installation. With # no Transaction Record, remove only the exact residue paths shared with # managed recovery. Validate each path before granting removal authority. if [ "$RECOVER_STATUS" = none ]; then managed_residue= for managed_residue in "$prefix/$CANDIDATE_FILE" "$prefix/$PACKAGE_STAGING_FILE" "$prefix/$PREVIOUS_NEXT_FILE" "$prefix/$PROBE_OUTPUT_FILE"; do if [ -e "$managed_residue" ] || [ -L "$managed_residue" ]; then validate_managed_file_safety "$managed_residue" "managed staging" rm -f "$managed_residue" 9>&- fi done else refuse_prior_managed_path "$prefix/$PREVIOUS_NEXT_FILE" "staged previous executable" refuse_prior_managed_path "$prefix/$CANDIDATE_FILE" "candidate executable" refuse_prior_managed_path "$prefix/$PROBE_OUTPUT_FILE" "probe output" rm -f "$prefix/$PACKAGE_STAGING_FILE" 9>&- fi refuse_prior_managed_path "$prefix/$EXTRACT_STAGE" "extract staging" refuse_prior_managed_path "$prefix/$archive" "Release Archive staging" if [ -e "$prefix/$PREVIOUS_FILE" ] || [ -L "$prefix/$PREVIOUS_FILE" ]; then validate_managed_file_safety "$prefix/$PREVIOUS_FILE" "rollback executable" fi CLEANUP_OWNS_STAGING=1 probe_managed_owned "$executable" "managed active executable" "$target" active_version=$MANAGED_PROBE_VERSION else # Fail closed on prior managed or reserved staging paths. Do not delete them. # The persistent Install Root lock file is allowed to remain. refuse_prior_managed_path "$prefix/$OWNERSHIP_FILE" "Ownership Record" refuse_prior_managed_path "$prefix/$PREVIOUS_FILE" "previous executable" refuse_prior_managed_path "$prefix/$PREVIOUS_NEXT_FILE" "staged previous executable" refuse_prior_managed_path "$prefix/$CANDIDATE_FILE" "candidate executable" refuse_prior_managed_path "$prefix/$EXTRACT_STAGE" "extract staging" refuse_prior_managed_path "$prefix/$PROBE_OUTPUT_FILE" "probe output" refuse_prior_managed_path "$prefix/$PACKAGE_STAGING_FILE" "package staging" refuse_prior_managed_path "$prefix/$archive" "Release Archive staging" # Clean root proven; this install now owns reserved staging for EXIT cleanup. CLEANUP_OWNS_STAGING=1 fi if [ "$managed_install" -eq 1 ]; then semver_order=$(exec 9>&-; semver_compare "$active_version" "$PRODUCT_VERSION") if [ "$semver_order" -gt 0 ]; then die "Installer will not downgrade 1667 from $active_version to $PRODUCT_VERSION. For an intentional downgrade, run '1667 upgrade --version $PRODUCT_VERSION'." fi fi # A same-version bootstrap is a no-op for executable bytes. It still records # the channel selected by this Installer and retains any rollback executable. if [ "$managed_install" -eq 1 ] && [ "$active_version" = "$PRODUCT_VERSION" ]; then write_ownership "$prefix" "$OWNERSHIP_ID" "$executable" "$target" "$INSTALL_CHANNEL" trap - EXIT INT TERM release_lock "$prefix" ( exec 9>&- trap '' PIPE printf '1667 %s (%s) is already installed at %s\n' "$PRODUCT_VERSION" "$INSTALL_CHANNEL" "$executable" ) || : return 0 fi url="$ASSET_BASE/$archive" # A managed bootstrap writes these pre-activation records into a root that # already holds a valid Ownership Record and a working active executable. # Own them so an interrupted bootstrap cannot strand '1667 upgrade'. if [ "$managed_install" -eq 1 ]; then CLEANUP_CLEAR_TXN=1 fi write_txn "$prefix" "downloading" "$target" "$digest" archive_path="$prefix/$archive" rm -f "$archive_path" 9>&- say "Downloading 1667 $PRODUCT_VERSION for $target" download_archive "$url" "$archive_path" say "Checking the download" verify_sha256 "$archive_path" "$digest" write_txn "$prefix" "extracted" "$target" "$digest" say "Unpacking" extract_candidate "$prefix" "$archive_path" "$archive" rm -f "$archive_path" 9>&- say "Starting 1667 once to confirm it runs" probe_candidate "$prefix/$CANDIDATE_FILE" "$target" # Candidate bytes must be durable before candidate-ready is published. # Power loss after a durable txn must not leave a missing or corrupt candidate. fsync_path "$prefix/$CANDIDATE_FILE" if [ "$managed_install" -eq 1 ]; then # Stage the old active before publishing the managed transaction. The old # active remains in place until the candidate rename commits. if [ -e "$prefix/$PREVIOUS_FILE" ] || [ -L "$prefix/$PREVIOUS_FILE" ]; then validate_managed_file_safety "$prefix/$PREVIOUS_FILE" "rollback executable" fi rm -f "$prefix/$PREVIOUS_NEXT_FILE" 9>&- cp "$executable" "$prefix/$PREVIOUS_NEXT_FILE" 9>&- || die "Could not stage the previous executable" chmod 0755 "$prefix/$PREVIOUS_NEXT_FILE" 9>&- if [ -L "$prefix/$PREVIOUS_NEXT_FILE" ] || [ ! -f "$prefix/$PREVIOUS_NEXT_FILE" ]; then die "Staged previous executable is invalid" fi fsync_path "$prefix/$PREVIOUS_NEXT_FILE" write_managed_txn "$prefix" "candidate-ready" "upgrade" "$INSTALL_CHANNEL" true "$active_version" "$PRODUCT_VERSION" "$OWNERSHIP_ID" "$target" # Release the pre-activation claim only after the managed record is on # disk. write_managed_txn can die before it publishes, and the stale # pre-activation record must still be cleared in that case. A die after it # publishes leaves the claim set, which is safe: the candidate has not # replaced the active executable yet, so clearing is self-healing. CLEANUP_CLEAR_TXN=0 mv "$prefix/$CANDIDATE_FILE" "$executable" 9>&- chmod 0755 "$executable" 9>&- fsync_path "$executable" write_managed_txn "$prefix" "ownership-pending" "upgrade" "$INSTALL_CHANNEL" true "$active_version" "$PRODUCT_VERSION" "$OWNERSHIP_ID" "$target" mv "$prefix/$PREVIOUS_NEXT_FILE" "$prefix/$PREVIOUS_FILE" 9>&- fsync_path "$prefix/$PREVIOUS_FILE" fsync_dir "$prefix" write_ownership "$prefix" "$OWNERSHIP_ID" "$executable" "$target" "$INSTALL_CHANNEL" else write_txn "$prefix" "candidate-ready" "$target" "$digest" mv "$prefix/$CANDIDATE_FILE" "$executable" 9>&- chmod 0755 "$executable" 9>&- fsync_path "$executable" # Close the gap: durable activated mark before ownership write. write_txn "$prefix" "activated" "$target" "$digest" # random_hex_32 subshell inherits FD 9; close it so a hung id helper cannot pin. installation_id=$( exec 9>&- random_hex_32 ) write_ownership "$prefix" "$installation_id" "$executable" "$target" fi # Ownership is already fsynced inside write_ownership; clear txn only after that. clear_txn "$prefix" trap - EXIT INT TERM release_lock "$prefix" # The installation is complete and the lock is released. Reporting it must not # turn a finished install into a signal death, so the result goes through the # same guard the progress uses. 'head' on the output is enough to trigger it. ( exec 9>&- trap '' PIPE printf 'Installed 1667 %s (%s) for %s to %s\n' \ "$PRODUCT_VERSION" "$INSTALL_CHANNEL" "$target" "$executable" case ":$PATH:" in *":$prefix:"*) ;; *) printf 'Add this directory to PATH:\n export PATH="%s:$PATH"\n' "$prefix" ;; esac ) || : } usage() { printf 'Usage: install-%s.sh [--prefix /absolute/path] [--dry-run] [--force]\n' "$INSTALL_CHANNEL" printf 'Installs 1667 %s from the pinned GitHub release archive.\n' "$PRODUCT_VERSION" printf 'Use this installer for a fresh Install Root or a valid Shell Managed Installation.\n' printf 'Use 1667 upgrade for later updates when the installed executable runs.\n' printf -- '--force accepts path ownership and write-permission risks.\n' printf -- 'This Installer runs the 1667 in the Install Root to read its version.\n' printf -- '--force also accepts that executable when it fails the safety checks.\n' printf 'It waives no checksum, attestation, or version check.\n' } cleanup_install() { root=$1 archive=$2 # Delete reserved staging only when this process owns it (canonical txn or # a verified clean fresh install that already began). Always release the lock. if [ "${CLEANUP_OWNS_STAGING:-0}" -eq 1 ]; then # Remove staging while this process still holds the lock, then release. # Releasing first lets a successor publish staging that this cleanup would delete. rm -f "$root/$CANDIDATE_FILE" "$root/$PROBE_OUTPUT_FILE" "$root/$archive" "$root/$PACKAGE_STAGING_FILE" 9>&- 2>/dev/null || true remove_extract_stage "$root" fi # Drop a pre-activation Shell Installer record this process wrote into a # Managed Installation. Do it under the lock, before the lock is released. if [ "${CLEANUP_CLEAR_TXN:-0}" -eq 1 ]; then clear_txn "$root" CLEANUP_CLEAR_TXN=0 fi release_lock "$root" } # Kill a background download so wait returns and this trap can exit promptly. stop_download() { if [ -n "${DOWNLOAD_PID:-}" ]; then kill "$DOWNLOAD_PID" 2>/dev/null || true set +e wait "$DOWNLOAD_PID" 2>/dev/null set -e DOWNLOAD_PID= fi } # Kill a bounded version probe (and its watchdog) so traps can exit promptly. # Escalate to SIGKILL so a TERM-resistant candidate cannot hold the lock. stop_probe() { if [ -n "${PROBE_WATCHDOG_PID:-}" ]; then kill "$PROBE_WATCHDOG_PID" 2>/dev/null || true set +e wait "$PROBE_WATCHDOG_PID" 2>/dev/null set -e PROBE_WATCHDOG_PID= fi if [ -n "${PROBE_PID:-}" ]; then kill "$PROBE_PID" 2>/dev/null || true sleep 1 9>&- kill -9 "$PROBE_PID" 2>/dev/null || true set +e wait "$PROBE_PID" 2>/dev/null set -e PROBE_PID= fi } # Conventional status: 128 + signal number (INT=2 → 130, TERM=15 → 143). # Clears traps first so EXIT does not run cleanup a second time. on_install_signal() { sig=$1 root=$2 archive=$3 trap - EXIT INT TERM stop_download stop_probe cleanup_install "$root" "$archive" case "$sig" in INT) exit 130 ;; TERM) exit 143 ;; *) exit 1 ;; esac } die() { printf '1667 install: %s\n' "$*" >&2 exit 1 } # Progress goes to stderr so that stdout carries only the install result. # Without it the installer is silent for the whole transfer, and a slow network # is indistinguishable from a stall. # # The prefix is deliberately not the one die() uses. A successful install must # not print the string that marks a refusal, because that string is a usable # failure signal for anything wrapping this script. # # The write is best-effort. These calls happen between the transaction record # and the activation, so a closed, full, or unreadable stderr must not end the # installation under 'set -e'. Progress is cosmetic; the install is not. say() { # The write happens in a subshell that ignores SIGPIPE, so a reader that stops # early (for example '2>&1 | head') cannot signal the installer. The subshell # takes the EPIPE instead, and '|| :' keeps its status away from 'set -e'. # The subshell closes FD 9, like every other subshell here, so a stalled write # can never hold the Install Root lock. ( exec 9>&- trap '' PIPE printf 'info: %s\n' "$*" >&2 ) || : } # Refuse any prior managed path (regular file, directory, or symbolic link). # Fresh install does not remove managed state left by a prior install or upgrade. refuse_prior_managed_path() { managed=$1 label=$2 if [ -e "$managed" ] || [ -L "$managed" ]; then die "Refusing to install over prior managed state ($label) at $managed. Remove it only after you confirm it is safe, or run '1667 upgrade' on a managed install." fi } # Prefer python3 os.fsync when present; else require successful sync(1). # Close Install Root lock FD 9 on durable-sync helpers so they cannot pin the lock. fsync_path() { path=$1 if command -v python3 >/dev/null 2>&1; then python3 -c ' import os, sys path = sys.argv[1] fd = os.open(path, os.O_RDONLY) try: os.fsync(fd) finally: os.close(fd) directory = os.path.dirname(path) or "." dfd = os.open(directory, os.O_RDONLY) try: os.fsync(dfd) finally: os.close(dfd) ' "$path" 9>&- || die "Could not durable-sync $path" return 0 fi sync 9>&- || die "Could not durable-sync $path (sync failed; python3 not available)" } fsync_dir() { directory=$1 if command -v python3 >/dev/null 2>&1; then python3 -c ' import os, sys directory = sys.argv[1] dfd = os.open(directory, os.O_RDONLY) try: os.fsync(dfd) finally: os.close(dfd) ' "$directory" 9>&- || die "Could not durable-sync directory $directory" return 0 fi sync 9>&- || die "Could not durable-sync directory $directory (sync failed; python3 not available)" } # Advisory lock on a persistent regular file at $LOCK_FILE. # Open on fixed FD 9; keep open through mutation; release by closing FD. # Never unlink the lock file. Kernel releases on process exit/crash. # close_install_lock_fd only closes FD 9 — do not redirect stderr with exec # (that would silence later die messages for the rest of the process). INSTALL_LOCK_FD=9 close_install_lock_fd() { exec 9>&- || true } acquire_lock() { root=$1 lock="$root/$LOCK_FILE" if [ -L "$lock" ]; then die "Install lock path is a symbolic link" fi if [ -e "$lock" ] && [ ! -f "$lock" ]; then die "Install lock path is not a regular file" fi # Append/create preserves an existing inode; do not truncate or replace. # shellcheck disable=SC2094,SC3023 exec 9>>"$lock" || die "Could not open the Install Root lock" if [ -L "$lock" ] || [ ! -f "$lock" ]; then close_install_lock_fd die "Install lock path is not a regular file" fi # uname runs in a command-substitution subshell that inherits FD 9. # Close it there so a hung uname cannot pin the Install Root lock. case "$( exec 9>&- uname -s )" in Darwin) if ! command -v lockf >/dev/null 2>&1; then close_install_lock_fd die "lockf is required to acquire the Install Root lock" fi if ! lockf -s -t 0 9; then close_install_lock_fd die "Another install holds the Install Root lock" fi ;; Linux) if ! command -v flock >/dev/null 2>&1; then close_install_lock_fd die "flock is required to acquire the Install Root lock" fi if ! flock -n 9; then close_install_lock_fd die "Another install holds the Install Root lock" fi ;; *) close_install_lock_fd die "Install Root lock is supported only on Darwin and Linux" ;; esac } release_lock() { # Idempotent. Close FD 9; optional Linux unlock before close. # uname subshell inherits FD 9 while the lock is still held; close it there. case "$( exec 9>&- uname -s )" in Linux) if command -v flock >/dev/null 2>&1; then flock -u 9 2>/dev/null || true fi ;; esac close_install_lock_fd } detect_target() { os=$(uname -s) arch=$(uname -m) case "$os" in Darwin) case "$arch" in arm64) printf 'darwin-arm64\n' ;; x86_64) printf 'darwin-x64\n' ;; *) die "Unsupported macOS architecture: $arch" ;; esac ;; Linux) if [ -e /lib/ld-musl-x86_64.so.1 ] || [ -e /lib/ld-musl-aarch64.so.1 ] \ || [ -e /lib/libc.musl-x86_64.so.1 ] || [ -e /lib/libc.musl-aarch64.so.1 ]; then die "Linux systems that use musl are not supported" fi case "$arch" in aarch64|arm64) printf 'linux-arm64\n' ;; x86_64|amd64) printf 'linux-x64\n' ;; *) die "Unsupported Linux architecture: $arch" ;; esac ;; *) die "Unsupported operating system: $os" ;; esac } # Paths are written into JSON without escaping. Reject quote, backslash, and # control characters before any Install Root mutation. assert_json_safe_path() { value=$1 label=$2 case $value in *\"*) die "$label must not contain a quote or backslash" ;; esac case $value in *\\*) die "$label must not contain a quote or backslash" ;; esac # Keep only printable ASCII (space through tilde). Any control or non-ASCII fails. cleaned=$(printf '%s' "$value" | tr -cd '\40-\176') if [ "$cleaned" != "$value" ]; then die "$label must not contain a control character" fi } # Members of a group other than this user and root. Sets GROUP_NAME and # GROUP_OTHERS. Returns 1 when the platform cannot answer, which is not the same # as a group with nobody else in it. # # /etc/group cannot answer on macOS: it lists 'admin:*:80:root' while Directory # Services holds the account that is really a member, so a reader of that file # says a shared group is private. Each platform is asked through the interface # that knows. group_other_members() { gid=$1 me=$2 GROUP_NAME= GROUP_OTHERS= members= if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then getent_bin=/usr/bin/getent [ -x "$getent_bin" ] || getent_bin=/bin/getent line=$(exec 9>&-; "$getent_bin" group "$gid" 2>/dev/null) || return 1 [ -n "$line" ] || return 1 GROUP_NAME=${line%%:*} members=${line##*:} elif [ -x /usr/bin/dscl ]; then GROUP_NAME=$(exec 9>&-; /usr/bin/dscl . -search /Groups PrimaryGroupID "$gid" 2>/dev/null \ | awk 'NR==1{print $1}') || return 1 [ -n "$GROUP_NAME" ] || return 1 # A group with nobody in it has no GroupMembership key, and dscl exits # nonzero. That is an empty membership, not a failed lookup. members=$(exec 9>&-; /usr/bin/dscl . -read "/Groups/$GROUP_NAME" GroupMembership 2>/dev/null \ | sed -n 's/^GroupMembership: //p') || members= else return 1 fi GROUP_OTHERS=$(exec 9>&-; printf '%s' "$members" | tr ', ' '\n\n' \ | grep -v -e '^$' -e "^root\$" -e "^$me\$" | tr '\n' ' ' || true) GROUP_OTHERS=${GROUP_OTHERS% } return 0 } # The Install Root must be a name this Installer can write into the Ownership # Record, a directory this user owns, and a directory no other account can # write. 1667 stages a candidate here, checks its digest, runs it once, and then # renames it into place; an account that can write here can replace the # candidate inside that window. # # Writable to everybody always fails. Writable to a group fails only when the # group holds somebody else, because Ubuntu gives each user a private group and # Homebrew's admin group holds root and the owner. Reading the bit alone refused # those layouts and named no exposure. # Refuse, or warn and continue when the caller passed --force. A waived refusal # still prints, so the reader who forced it can read what they accepted. refuse_root() { forced=$1 message=$2 if [ "$forced" -eq 1 ]; then printf 'warning: %s\n' "$message" >&2 printf 'warning: --force accepted this Install Root anyway.\n' >&2 return 0 fi die "$message" } validate_install_root() { root=$1 forced=${2:-0} assert_json_safe_path "$root" "Install Root" if [ -e "$root" ]; then if [ ! -d "$root" ]; then die "Install Root is not a directory: $root" fi owner=$(owner_uid "$root") || return 1 me=$(id -u) if [ "$owner" != "$me" ]; then refuse_root "$forced" "Install Root $root belongs to user $owner, and you are $(id -un). 1667 replaces files there during an upgrade, which it cannot do as another user. Run: sudo chown $(id -un) $root, choose another Install Root, or pass --force to install here anyway." fi mode=$(file_mode "$root") || return 1 if [ $(( $(printf '%d' "0$mode") & 2 )) -ne 0 ]; then refuse_root "$forced" "Install Root $root is writable by every account on this machine (mode $mode). Any of them could replace what 1667 installs there. Run: chmod o-w $root - or pass --force to install here anyway." fi if [ $(( $(printf '%d' "0$mode") & 16 )) -ne 0 ]; then gid=$(file_gid "$root") || return 1 if group_other_members "$gid" "$(id -un)"; then if [ -n "$GROUP_OTHERS" ]; then refuse_root "$forced" "Install Root $root is writable by group ${GROUP_NAME:-$gid} (mode $mode), which also holds $GROUP_OTHERS. That account could replace what 1667 installs there. Run: chmod g-w $root, choose another Install Root, or pass --force to install here anyway." fi else refuse_root "$forced" "Install Root $root is writable by group $gid (mode $mode), and this Installer could not read that group's members to see whether anybody else is in it. Run: chmod g-w $root - or pass --force to install here anyway." fi fi fi } ensure_install_root() { root=$1 if [ -d "$root" ]; then return 0 fi missing= path=$root while [ ! -e "$path" ] && [ "$path" != "/" ]; do missing="$path $missing" path=$(dirname "$path") done printf '%s\n' "$missing" | while IFS= read -r component; do [ -n "$component" ] || continue mkdir -m 0700 "$component" done } owner_uid() { # Close Install Root lock FD 9 on the stat helper so it cannot pin the lock. if stat -f %u "$1" >/dev/null 2>&1; then stat -f %u "$1" 9>&- else stat -c %u "$1" 9>&- fi } file_gid() { if stat -f %g "$1" >/dev/null 2>&1; then stat -f %g "$1" 9>&- else stat -c %g "$1" 9>&- fi } # Permission bits as octal digits, such as 775. file_mode() { if stat -f %Lp "$1" >/dev/null 2>&1; then stat -f %Lp "$1" 9>&- else stat -c %a "$1" 9>&- fi } # One canonical transaction renderer for writes and acceptance. canonical_txn_bytes() { phase=$1 target=$2 digest=$3 root=$4 printf '%s\n' "{\"kind\":\"shell-installer\",\"schemaVersion\":1,\"phase\":\"$phase\",\"version\":\"$PRODUCT_VERSION\",\"channel\":\"$INSTALL_CHANNEL\",\"artifactTarget\":\"$target\",\"archiveSha256\":\"$digest\",\"installRoot\":\"$root\",\"executable\":\"$root/$ACTIVE_FILE\"}" } write_txn() { root=$1 phase=$2 target=$3 digest=$4 tmp="$root/.1667-install-txn.$$.tmp" rm -f "$tmp" 9>&- umask 077 # Noclobber writer is a parenthesized subshell that inherits FD 9; close it. if ! ( exec 9>&- set -C canonical_txn_bytes "$phase" "$target" "$digest" "$root" > "$tmp" ); then die "Could not create a Transaction Record" fi mv "$tmp" "$root/$TXN_FILE" 9>&- fsync_path "$root/$TXN_FILE" } # Accept an existing transaction only when its complete bytes equal one allowed # canonical phase record. Compare with cmp -s so trailing newlines are not stripped # (command substitution would drop trailing newlines and accept one extra byte). validate_txn() { file=$1 expected_target=$2 expected_digest=$3 root=$4 # Private comparison temp may be rewritten each phase; do not use noclobber here. tmp="$file.validate.$$" for phase in downloading extracted candidate-ready activated; do if ! canonical_txn_bytes "$phase" "$expected_target" "$expected_digest" "$root" > "$tmp"; then rm -f "$tmp" 9>&- die "Could not build a comparison Transaction Record" fi if cmp -s "$file" "$tmp" 9>&-; then rm -f "$tmp" 9>&- printf '%s\n' "$phase" return 0 fi done rm -f "$tmp" 9>&- die "Install transaction is not a canonical phase record" } # Remove the exact reserved extract staging path under Install Root. # Never glob. A symbolic link is unlinked without following. remove_extract_stage() { root=$1 stage="$root/$EXTRACT_STAGE" if [ -L "$stage" ]; then rm -f "$stage" 9>&- return 0 fi if [ -d "$stage" ]; then rm -rf "$stage" 9>&- return 0 fi if [ -e "$stage" ]; then rm -f "$stage" 9>&- fi } # Recovery runs in the lock-owning shell so PROBE_PID stays visible to traps. # Sets RECOVER_STATUS (none|reset|completed|managed-reset|managed-completed). # The caller must handle every value explicitly. Do not wrap in command # substitution: recovery runs in the lock-owning shell so probe traps work. recover_install() { root=$1 executable=$2 target=$3 digest=$4 # Exact pinned Release Archive file name for this host/version (never a glob). archive=$5 RECOVER_STATUS= txn="$root/$TXN_FILE" if [ -L "$txn" ]; then die "Install transaction must not be a symbolic link" fi if [ ! -e "$txn" ]; then # No Transaction Record: do not delete reserved staging. Ownership is unproven. RECOVER_STATUS=none return 0 fi if [ ! -f "$txn" ]; then die "Install transaction must be a regular file" fi validate_managed_file_safety "$txn" "Install Transaction Record" txn_mode=$(exec 9>&-; file_mode "$txn") || die "Could not inspect Install Transaction Record permissions" [ "$txn_mode" = 600 ] || die "Install Transaction Record must have mode 600" txn_size=$(exec 9>&-; wc -c < "$txn" | tr -d ' ') [ -n "$txn_size" ] && [ "$txn_size" -le "$MAX_TRANSACTION_BYTES" ] || die "Install Transaction Record is too large" txn_text=$(exec 9>&-; cat "$txn") || die "Could not read Install Transaction Record" txn_kind=$(exec 9>&-; json_string_field "$txn_text" kind) if [ "$txn_kind" = managed ]; then validate_managed_txn "$txn" "$target" "$root" # Managed Transaction Records do not own Shell Installer-only staging. # Refuse it before recovery grants cleanup authority. refuse_prior_managed_path "$root/$EXTRACT_STAGE" "extract staging" refuse_prior_managed_path "$root/$archive" "Release Archive staging" recover_managed_install "$root" "$executable" "$target" "$txn" return 0 fi [ "$txn_kind" = shell-installer ] || die "Install transaction is not a canonical phase record" # validate_txn subshell inherits FD 9; close it so a hung validator cannot pin. phase=$( exec 9>&- validate_txn "$txn" "$target" "$digest" "$root" ) || exit 1 # Canonical match proves this installer owns reserved staging for cleanup. CLEANUP_OWNS_STAGING=1 case "$phase" in downloading|extracted) rm -f "$root/$CANDIDATE_FILE" "$root/$PREVIOUS_NEXT_FILE" "$root/$PROBE_OUTPUT_FILE" "$root/$archive" 9>&- remove_extract_stage "$root" clear_txn "$root" RECOVER_STATUS=reset return 0 ;; candidate-ready) if [ -f "$executable" ] && [ ! -L "$executable" ]; then if probe_candidate_soft "$executable" "$target"; then # Rename may have completed before fsync; durable-sync active first. fsync_path "$executable" installation_id=$( exec 9>&- random_hex_32 ) write_ownership "$root" "$installation_id" "$executable" "$target" rm -f "$root/$CANDIDATE_FILE" 9>&- remove_extract_stage "$root" clear_txn "$root" RECOVER_STATUS=completed return 0 fi die "Install left an active executable that does not match the pinned release" fi rm -f "$root/$CANDIDATE_FILE" 9>&- remove_extract_stage "$root" clear_txn "$root" RECOVER_STATUS=reset return 0 ;; activated) if [ ! -f "$executable" ] || [ -L "$executable" ]; then die "Install transaction is activated but the executable is missing" fi probe_candidate "$executable" "$target" fsync_path "$executable" ownership="$root/$OWNERSHIP_FILE" if [ -e "$ownership" ] || [ -L "$ownership" ]; then validate_managed_ownership "$root" "$executable" "$target" [ "$OWNERSHIP_CHANNEL" = "$INSTALL_CHANNEL" ] || die "Ownership Record channel does not match the Install Transaction Record" fsync_path "$ownership" else installation_id=$( exec 9>&- random_hex_32 ) write_ownership "$root" "$installation_id" "$executable" "$target" fi rm -f "$root/$CANDIDATE_FILE" 9>&- remove_extract_stage "$root" clear_txn "$root" RECOVER_STATUS=completed return 0 ;; *) die "Install transaction phase is unsupported: $phase" ;; esac } # Background curl + wait so INT/TERM traps run during download (foreground # curl would block trapped signals until the transfer finished). # Close Install Root lock FD 9 in the child so a parent crash cannot leave the # advisory lock held by a still-running downloader. # --connect-timeout and --max-time are portable curl flags; both URL branches # share the same connect and overall transfer deadlines. DOWNLOAD_PID= download_archive() { url=$1 out=$2 command -v curl >/dev/null 2>&1 || die "curl is required" # A person watching a terminal gets the transfer bar. A log or a pipe gets # silence, so captured output stays free of carriage returns. if [ -t 2 ]; then progress='--progress-bar' else progress='--silent' fi case "$url" in https://*) curl -fSL "$progress" --proto '=https' --proto-redir '=https' \ --connect-timeout "$DOWNLOAD_CONNECT_TIMEOUT_SEC" \ --max-time "$DOWNLOAD_MAX_TIME_SEC" \ --max-filesize "$MAX_ARCHIVE_BYTES" "$url" -o "$out" 9>&- & ;; http://127.0.0.1:*|http://localhost:*) curl -fSL "$progress" \ --connect-timeout "$DOWNLOAD_CONNECT_TIMEOUT_SEC" \ --max-time "$DOWNLOAD_MAX_TIME_SEC" \ --max-filesize "$MAX_ARCHIVE_BYTES" "$url" -o "$out" 9>&- & ;; *) die "Release Archive URL must use HTTPS" ;; esac DOWNLOAD_PID=$! set +e wait "$DOWNLOAD_PID" status=$? set -e DOWNLOAD_PID= if [ "$status" -ne 0 ]; then rm -f "$out" 9>&- die "Download failed" fi # size= subshell inherits FD 9; close it so a hung wc cannot pin the lock. size=$( exec 9>&- wc -c < "$out" | tr -d ' ' ) if [ "$size" -le 0 ] || [ "$size" -gt "$MAX_ARCHIVE_BYTES" ]; then rm -f "$out" 9>&- die "Release Archive size is outside the bound" fi } verify_sha256() { file=$1 expected=$2 # Command-substitution subshells inherit FD 9. Close it in the subshell itself # (not only pipeline children) so a hanging digest helper cannot pin the lock # after the installer parent dies. actual=$( exec 9>&- file_sha256 "$file" ) if [ "$actual" != "$expected" ]; then die "Release Archive SHA-256 digest did not match the pinned value" fi } file_sha256() { # Digest helpers must not inherit Install Root lock FD 9. if command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" 9>&- | awk '{print $1}' 9>&- elif command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" 9>&- | awk '{print $1}' 9>&- else die "shasum or sha256sum is required" fi } random_hex_32() { if [ -r /dev/urandom ]; then od -An -N16 -tx1 /dev/urandom 9>&- | tr -d ' \n' 9>&- return 0 fi die "Cannot create an installation id" } # Canonical Ownership Record bytes for writes and post-replace verification. canonical_ownership_bytes() { id=$1 exe=$2 target=$3 root=$4 channel=$5 cat 9>&- <&- umask 077 # Noclobber writers inherit FD 9; close it in each parenthesized subshell. if ! ( exec 9>&- set -C canonical_ownership_bytes "$id" "$exe" "$target" "$root" "$channel" > "$tmp" ); then die "Could not create an Ownership Record" fi fsync_path "$tmp" # Keep expected bytes for post-replace verification (mv consumes $tmp). if ! ( exec 9>&- set -C canonical_ownership_bytes "$id" "$exe" "$target" "$root" "$channel" > "$verify" ); then rm -f "$tmp" 9>&- die "Could not create an Ownership Record verification copy" fi mv "$tmp" "$dest" 9>&- chmod 0600 "$dest" 9>&- # Ownership must be durable before any later Transaction Record removal. fsync_path "$dest" fsync_dir "$root" # Verify final path type and exact bytes after atomic replacement. if [ -L "$dest" ] || [ ! -f "$dest" ]; then rm -f "$verify" 9>&- die "Ownership Record path is not a regular file after write" fi if ! cmp -s "$dest" "$verify" 9>&-; then rm -f "$verify" 9>&- die "Ownership Record verification failed after write" fi rm -f "$verify" 9>&- } clear_txn() { root=$1 rm -f "$root/$TXN_FILE" 9>&- fsync_dir "$root" } canonical_ownership_compact_bytes() { id=$1 exe=$2 target=$3 root=$4 channel=$5 printf '%s\n' "{\"schemaVersion\":1,\"product\":\"1667\",\"installationId\":\"$id\",\"method\":\"shell\",\"channel\":\"$channel\",\"installRoot\":\"$root\",\"executable\":\"$exe\",\"artifactTarget\":\"$target\"}" } # Extract a bounded JSON string without splitting on commas. Paths may contain # commas, and the complete canonical-byte comparison below remains authoritative. managed_json_string_field() { text=$1 key=$2 printf '%s\n' "$text" | sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -n 1 } validate_managed_file_safety() { file=$1 label=$2 if [ -L "$file" ] || [ ! -f "$file" ]; then die "$label must be a regular non-symbolic-link file" fi forced=${MANAGED_FORCE:-0} owner=$(exec 9>&-; owner_uid "$file") || die "Could not inspect $label ownership" me=$(exec 9>&-; id -u) if [ "$owner" != "$me" ]; then refuse_root "$forced" "$label belongs to user $owner, and you are $(exec 9>&-; id -un). 1667 replaces files there during an upgrade, which it cannot do as another user." if [ "$forced" -eq 1 ]; then return 0; fi fi mode=$(exec 9>&-; file_mode "$file") || die "Could not inspect $label permissions" if [ $(( $(exec 9>&-; printf '%d' "0$mode") & 2 )) -ne 0 ]; then refuse_root "$forced" "$label is writable by every account on this machine (mode $mode). Any of them could replace what 1667 installs there." if [ "$forced" -eq 1 ]; then return 0; fi fi if [ $(( $(exec 9>&-; printf '%d' "0$mode") & 16 )) -ne 0 ]; then gid=$(exec 9>&-; file_gid "$file") || die "Could not inspect $label group" if group_other_members "$gid" "$(exec 9>&-; id -un)"; then if [ -n "$GROUP_OTHERS" ]; then refuse_root "$forced" "$label is writable by group ${GROUP_NAME:-$gid} (mode $mode), which also holds $GROUP_OTHERS." if [ "$forced" -eq 1 ]; then return 0; fi fi else refuse_root "$forced" "$label is writable by group $gid (mode $mode), and this Installer could not read that group's members." if [ "$forced" -eq 1 ]; then return 0; fi fi fi } probe_managed_owned() { file=$1 label=$2 target=$3 validate_managed_file_safety "$file" "$label" probe_managed_active "$file" "$target" } # POSIX awk implementation of the shared SemVer grammar. Numeric identifiers # cannot have leading zeroes. Prerelease and build identifiers use only the # characters allowed by shared/semver.ts. semver_valid() { value=$1 printf '%s\n' "$value" | awk ' function numeric(s) { return s ~ /^(0|[1-9][0-9]*)$/ } function identifier(s) { return s ~ /^[0-9A-Za-z-]+$/ && s != "" } { if (index($0, " ") || $0 == "") exit 1 plus = index($0, "+") if (plus && index(substr($0, plus + 1), "+")) exit 1 core = plus ? substr($0, 1, plus - 1) : $0 build = plus ? substr($0, plus + 1) : "" if (build != "") { n = split(build, b, ".") for (i = 1; i <= n; i++) if (!identifier(b[i])) exit 1 } else if (plus) exit 1 dash = index(core, "-") pre = dash ? substr(core, dash + 1) : "" base = dash ? substr(core, 1, dash - 1) : core if (dash && pre == "") exit 1 if (split(base, v, ".") != 3) exit 1 for (i = 1; i <= 3; i++) if (!numeric(v[i])) exit 1 if (pre != "") { n = split(pre, p, ".") for (i = 1; i <= n; i++) { if (!identifier(p[i])) exit 1 if (p[i] ~ /^[0-9]+$/ && !numeric(p[i])) exit 1 } } exit 0 } { exit 1 } ' 9>&- } # Compare two already validated SemVer values. Print -1, 0, or 1. Keep numeric # comparison textual so large core identifiers do not lose precision in awk. semver_compare() { LC_ALL=C awk -v left="$1" -v right="$2" ' function parse(value, which, plus, dash, core, pre, parts, count, i) { plus = index(value, "+") if (plus) value = substr(value, 1, plus - 1) dash = index(value, "-") if (dash) { core = substr(value, 1, dash - 1) pre = substr(value, dash + 1) } else { core = value pre = "" } count = split(core, parts, "[.]") if (which == "left") { lmajor = parts[1] lminor = parts[2] lpatch = parts[3] } else { rmajor = parts[1] rminor = parts[2] rpatch = parts[3] } if (pre == "") { if (which == "left") lpre_count = 0 else rpre_count = 0 return } count = split(pre, parts, "[.]") if (which == "left") { lpre_count = count for (i = 1; i <= count; i++) lpre[i] = parts[i] } else { rpre_count = count for (i = 1; i <= count; i++) rpre[i] = parts[i] } } function compare_numeric(left_value, right_value) { if (length(left_value) != length(right_value)) { return length(left_value) < length(right_value) ? -1 : 1 } if (("x" left_value) == ("x" right_value)) return 0 return ("x" left_value) < ("x" right_value) ? -1 : 1 } function compare_identifier(left_value, right_value, left_numeric, right_numeric) { left_numeric = left_value ~ /^[0-9]+$/ right_numeric = right_value ~ /^[0-9]+$/ if (left_numeric && right_numeric) return compare_numeric(left_value, right_value) if (left_numeric != right_numeric) return left_numeric ? -1 : 1 if (left_value == right_value) return 0 return ("x" left_value) < ("x" right_value) ? -1 : 1 } function compare_prerelease(left_count, right_count, count, i, comparison) { if (left_count == 0) return right_count == 0 ? 0 : 1 if (right_count == 0) return -1 count = left_count > right_count ? left_count : right_count for (i = 1; i <= count; i++) { if (i > left_count) return -1 if (i > right_count) return 1 comparison = compare_identifier(lpre[i], rpre[i]) if (comparison != 0) return comparison } return 0 } function compare_versions(comparison) { comparison = compare_numeric(lmajor, rmajor) if (comparison != 0) return comparison comparison = compare_numeric(lminor, rminor) if (comparison != 0) return comparison comparison = compare_numeric(lpatch, rpatch) if (comparison != 0) return comparison return compare_prerelease(lpre_count, rpre_count) } BEGIN { parse(left, "left") parse(right, "right") print compare_versions() } ' 9>&- } validate_managed_ownership() { root=$1 executable=$2 target=$3 file="$root/$OWNERSHIP_FILE" if [ -L "$file" ]; then die "Ownership Record must not be a symbolic link" fi if [ ! -f "$file" ]; then die "Refusing to replace an existing 1667: Ownership Record is missing (unmanaged installation)" fi validate_managed_file_safety "$file" "Ownership Record" mode=$(exec 9>&-; file_mode "$file") || return 1 [ "$mode" = 600 ] || die "Ownership Record must have mode 600" size=$(exec 9>&-; wc -c < "$file" | tr -d ' ') [ -n "$size" ] && [ "$size" -le 16384 ] || die "Ownership Record is too large" text=$(exec 9>&-; cat "$file") || die "Could not read Ownership Record" id=$(exec 9>&-; managed_json_string_field "$text" installationId) method=$(exec 9>&-; managed_json_string_field "$text" method) channel=$(exec 9>&-; managed_json_string_field "$text" channel) id_length=$(exec 9>&-; printf '%s' "$id" | wc -c | tr -d ' ') [ "$id_length" -eq 32 ] || die "Ownership Record installation id is invalid" case "$id" in *[!0-9a-f]*) die "Ownership Record installation id is invalid" ;; esac case "$channel" in stable|beta) ;; *) die "Ownership Record channel is invalid" ;; esac [ "$method" = shell ] || die "Ownership Record method is invalid" expected="$root/.1667-ownership-validate.$$" rm -f "$expected" 9>&- if canonical_ownership_bytes "$id" "$executable" "$target" "$root" "$channel" > "$expected" && cmp -s "$file" "$expected" 9>&-; then rm -f "$expected" 9>&- OWNERSHIP_ID=$id OWNERSHIP_CHANNEL=$channel return 0 fi if canonical_ownership_compact_bytes "$id" "$executable" "$target" "$root" "$channel" > "$expected" && cmp -s "$file" "$expected" 9>&-; then rm -f "$expected" 9>&- OWNERSHIP_ID=$id OWNERSHIP_CHANNEL=$channel return 0 fi rm -f "$expected" 9>&- die "Ownership Record is not a canonical managed record" } json_bool_field() { text=$1 key=$2 printf '%s\n' "$text" | tr ',' '\n' | sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*//p" | head -n 1 | tr -d ' }' } canonical_managed_txn_bytes() { phase=$1 operation=$2 channel=$3 update_channel=$4 active_version=$5 candidate_version=$6 installation_id=$7 root=$8 target=$9 # Declared serializer contract: serializeInstallTransactionRecord in # tui/src/install-transaction-record.ts. It writes phase as the final key. printf '%s\n' "{\"kind\":\"managed\",\"schemaVersion\":1,\"operation\":\"$operation\",\"channel\":\"$channel\",\"updateChannel\":$update_channel,\"activeVersion\":\"$active_version\",\"candidateVersion\":\"$candidate_version\",\"installationId\":\"$installation_id\",\"installRoot\":\"$root\",\"executable\":\"$root/$ACTIVE_FILE\",\"artifactTarget\":\"$target\",\"phase\":\"$phase\"}" } write_managed_txn() { root=$1 phase=$2 operation=$3 channel=$4 update_channel=$5 active_version=$6 candidate_version=$7 installation_id=$8 target=$9 tmp="$root/.1667-managed-txn.$$.tmp" rm -f "$tmp" 9>&- umask 077 if ! ( exec 9>&- set -C canonical_managed_txn_bytes "$phase" "$operation" "$channel" "$update_channel" "$active_version" "$candidate_version" "$installation_id" "$root" "$target" > "$tmp" ); then die "Could not create a managed Transaction Record" fi fsync_path "$tmp" mv "$tmp" "$root/$TXN_FILE" 9>&- fsync_path "$root/$TXN_FILE" fsync_dir "$root" } validate_managed_txn() { file=$1 target=$2 root=$3 text=$(exec 9>&-; cat "$file") || die "Could not read managed Transaction Record" kind=$(exec 9>&-; managed_json_string_field "$text" kind) phase=$(exec 9>&-; managed_json_string_field "$text" phase) operation=$(exec 9>&-; managed_json_string_field "$text" operation) channel=$(exec 9>&-; managed_json_string_field "$text" channel) update_channel=$(exec 9>&-; json_bool_field "$text" updateChannel) active_version=$(exec 9>&-; managed_json_string_field "$text" activeVersion) candidate_version=$(exec 9>&-; managed_json_string_field "$text" candidateVersion) installation_id=$(exec 9>&-; managed_json_string_field "$text" installationId) [ "$kind" = managed ] || die "Install transaction kind is unsupported" case "$phase" in candidate-ready|ownership-pending) ;; *) die "Managed transaction phase is invalid" ;; esac case "$operation" in upgrade|rollback) ;; *) die "Managed transaction operation is invalid" ;; esac case "$channel" in stable|beta) ;; *) die "Managed transaction channel is invalid" ;; esac case "$update_channel" in true|false) ;; *) die "Managed transaction updateChannel is invalid" ;; esac if ! semver_valid "$active_version" || ! semver_valid "$candidate_version"; then die "Managed transaction versions are invalid" fi id_length=$(exec 9>&-; printf '%s' "$installation_id" | wc -c | tr -d ' ') [ "$id_length" -eq 32 ] || die "Managed transaction installation id is invalid" case "$installation_id" in *[!0-9a-f]*) die "Managed transaction installation id is invalid" ;; esac expected="$file.validate.$$" rm -f "$expected" 9>&- if canonical_managed_txn_bytes "$phase" "$operation" "$channel" "$update_channel" "$active_version" "$candidate_version" "$installation_id" "$root" "$target" > "$expected" && cmp -s "$file" "$expected" 9>&-; then rm -f "$expected" 9>&- MANAGED_PHASE=$phase MANAGED_OPERATION=$operation MANAGED_CHANNEL=$channel MANAGED_UPDATE_CHANNEL=$update_channel MANAGED_ACTIVE_VERSION=$active_version MANAGED_CANDIDATE_VERSION=$candidate_version MANAGED_INSTALLATION_ID=$installation_id return 0 fi rm -f "$expected" 9>&- die "Install transaction is not a canonical managed record" } finish_managed_recovery() { root=$1 executable=$2 target=$3 if [ -e "$root/$PREVIOUS_NEXT_FILE" ] || [ -L "$root/$PREVIOUS_NEXT_FILE" ]; then if [ -L "$root/$PREVIOUS_NEXT_FILE" ] || [ ! -f "$root/$PREVIOUS_NEXT_FILE" ]; then die "Managed transaction rollback staging is invalid" fi probe_managed_owned "$root/$PREVIOUS_NEXT_FILE" "rollback staging" "$target" previous_version=$MANAGED_PROBE_VERSION [ "$previous_version" = "$MANAGED_ACTIVE_VERSION" ] || die "Managed transaction rollback staging does not match the active version" if [ -e "$root/$PREVIOUS_FILE" ] || [ -L "$root/$PREVIOUS_FILE" ]; then validate_managed_file_safety "$root/$PREVIOUS_FILE" "rollback executable" fi mv "$root/$PREVIOUS_NEXT_FILE" "$root/$PREVIOUS_FILE" 9>&- fsync_path "$root/$PREVIOUS_FILE" fsync_dir "$root" elif [ -e "$root/$PREVIOUS_FILE" ]; then if [ -L "$root/$PREVIOUS_FILE" ] || [ ! -f "$root/$PREVIOUS_FILE" ]; then die "Managed transaction rollback executable is invalid" fi probe_managed_owned "$root/$PREVIOUS_FILE" "rollback executable" "$target" previous_version=$MANAGED_PROBE_VERSION [ "$previous_version" = "$MANAGED_ACTIVE_VERSION" ] || die "Managed transaction rollback executable does not match the active version" else die "Managed transaction has no verified rollback executable" fi if [ "$MANAGED_UPDATE_CHANNEL" = true ]; then recovery_channel=$MANAGED_CHANNEL else recovery_channel=$OWNERSHIP_CHANNEL fi write_ownership "$root" "$MANAGED_INSTALLATION_ID" "$executable" "$target" "$recovery_channel" rm -f "$root/$CANDIDATE_FILE" "$root/$PACKAGE_STAGING_FILE" 9>&- clear_txn "$root" RECOVER_STATUS=managed-completed } recover_managed_install() { root=$1 executable=$2 target=$3 validate_managed_ownership "$root" "$executable" "$target" [ "$OWNERSHIP_ID" = "$MANAGED_INSTALLATION_ID" ] || die "Managed transaction installation id does not match Ownership Record" if [ -e "$root/$PROBE_OUTPUT_FILE" ] || [ -L "$root/$PROBE_OUTPUT_FILE" ]; then validate_managed_file_safety "$root/$PROBE_OUTPUT_FILE" "probe output" rm -f "$root/$PROBE_OUTPUT_FILE" 9>&- fi CLEANUP_OWNS_STAGING=1 case "$MANAGED_PHASE" in candidate-ready) if [ -f "$executable" ] && [ ! -L "$executable" ]; then probe_managed_owned "$executable" "managed active executable" "$target" active_version=$MANAGED_PROBE_VERSION if [ "$active_version" = "$MANAGED_ACTIVE_VERSION" ]; then rm -f "$root/$CANDIDATE_FILE" "$root/$PREVIOUS_NEXT_FILE" "$root/$PACKAGE_STAGING_FILE" 9>&- clear_txn "$root" RECOVER_STATUS=managed-reset return 0 fi if [ "$active_version" = "$MANAGED_CANDIDATE_VERSION" ]; then finish_managed_recovery "$root" "$executable" "$target" return 0 fi fi die "Managed transaction active executable does not match its record" ;; ownership-pending) if [ ! -f "$executable" ] || [ -L "$executable" ]; then die "Managed transaction active executable is missing" fi probe_managed_owned "$executable" "managed active executable" "$target" active_version=$MANAGED_PROBE_VERSION [ "$active_version" = "$MANAGED_CANDIDATE_VERSION" ] || die "Managed transaction active executable does not match its record" finish_managed_recovery "$root" "$executable" "$target" ;; esac } # Tools required for bounded decompress and physical ustar validation. require_extract_tools() { command -v gzip >/dev/null 2>&1 || die "gzip is required" command -v dd >/dev/null 2>&1 || die "dd is required" command -v od >/dev/null 2>&1 || die "od is required" command -v cmp >/dev/null 2>&1 || die "cmp is required" } # Decompress gzip into a private tar path. Every decompressed byte counts # against MAX_TAR_BYTES. Reads at most one 512-byte block past the bound so # overflow is visible without unbounded write. Close FD 9 on gzip so a hung # decompress cannot pin the Install Root lock. decompress_archive_bounded() { archive_path=$1 tar_path=$2 # MAX_TAR_BYTES is a multiple of 512 (shared release bound). max_blocks=$((MAX_TAR_BYTES / 512)) # Private status file next to the private tar (same extract stage). gzip_status_path="${tar_path}.gzip-status" rm -f "$tar_path" "$gzip_status_path" 9>&- # Capture gzip exit in the status file (POSIX sh has no pipefail). dd # iflag=fullblock makes count mean complete 512-byte blocks on GNU dd and # macOS BSD dd. Close FD 9 in the subshell and on gzip. ( exec 9>&- { gs=0 gzip -dc "$archive_path" 9>&- || gs=$? echo "$gs" > "$gzip_status_path" } | dd bs=512 count=$((max_blocks + 1)) iflag=fullblock of="$tar_path" 2>/dev/null ) || true size=$( exec 9>&- wc -c < "$tar_path" | tr -d ' ' ) if [ -z "$size" ] || [ "$size" -le 0 ]; then die "Archive decompression failed" fi if [ "$size" -gt "$MAX_TAR_BYTES" ]; then # Prefer expanded-size when past the bound, even if gzip got SIGPIPE. die "Release archive expanded size is outside the bound" fi # Command substitution strips the trailing newline from the status file. gzip_status=$( exec 9>&- if [ -f "$gzip_status_path" ]; then cat "$gzip_status_path" fi ) rm -f "$gzip_status_path" 9>&- # At or below the bound require gzip status 0 so a bad CRC cannot pass. if [ -z "$gzip_status" ] || [ "$gzip_status" -ne 0 ]; then die "Archive decompression failed" fi } # Read one 512-byte block at index i into hdr_path (private tar, block seek). ustar_read_block() { tar_path=$1 hdr_path=$2 i=$3 ( exec 9>&- dd if="$tar_path" of="$hdr_path" bs=512 skip="$i" count=1 2>/dev/null ) || die "Archive structure is truncated or not block-aligned" } # Parse one physical 512-byte ustar header. # Output is one fixed record: zero, bad, layout, D:0, or F::. parse_ustar_header() { hdr_path=$1 od -An -v -tu1 -N512 "$hdr_path" 9>&- | awk -v m0="$m0" -v m1="$m1" -v m2="$m2" -v m3="$m3" -v m4="$m4" -v m5="$m5" ' { for (i = 1; i <= NF; i++) { b[n_bytes++] = $i + 0 } } END { if (n_bytes != 512) { print "bad" exit 1 } z = 1 for (i = 0; i < 512; i++) { if (b[i] != 0) { z = 0 break } } if (z) { print "zero" exit 0 } sum = 0 for (i = 0; i < 512; i++) { if (i >= 148 && i < 156) sum += 32 else sum += b[i] } ck = parse_octal(148, 8) if (ck < 0 || ck != sum) { print "bad" exit 1 } if (b[257] != 117 || b[258] != 115 || b[259] != 116 || b[260] != 97 || b[261] != 114 || b[262] != 0) { print "bad" exit 1 } if (b[263] != 48 || b[264] != 48) { print "bad" exit 1 } type = b[156] mode = parse_octal(100, 8) size = parse_octal(124, 12) if (mode < 0 || size < 0) { print "bad" exit 1 } for (i = 157; i < 257; i++) { if (b[i] != 0) { print "bad" exit 1 } } name = field_text(0, 100) if (name == "__BAD_FIELD__") { print "bad" exit 1 } prefix = field_text(345, 155) if (prefix == "__BAD_FIELD__") { print "bad" exit 1 } if (name == "" && prefix == "") { print "bad" exit 1 } if (prefix == "") path = name else path = prefix "/" name if (type == 0 || type == 48) { if (path == m1) { print "F:1:" size; exit 0 } if (path == m2) { print "F:2:" size; exit 0 } if (path == m3) { print "F:3:" size; exit 0 } if (path == m4) { print "F:4:" size; exit 0 } if (path == m5) { print "F:5:" size; exit 0 } print "layout" exit 0 } if (type == 53) { if (size != 0) { print "bad" exit 1 } if (substr(path, length(path), 1) == "/") { path = substr(path, 1, length(path) - 1) } if (path == "") { print "bad" exit 1 } if (path == m0) { print "D:0" exit 0 } print "layout" exit 0 } print "bad" exit 1 } function parse_octal(start, len, i, end, c, started, v) { if (b[start] >= 128) return -1 end = start + len started = 0 v = 0 for (i = start; i < end; i++) { c = b[i] if (c == 0) { for (i = i + 1; i < end; i++) { if (b[i] != 0 && b[i] != 32) return -1 } break } if (c == 32) { if (!started) continue for (i = i + 1; i < end; i++) { if (b[i] != 0 && b[i] != 32) return -1 } break } if (c < 48 || c > 55) return -1 started = 1 if (v > 2147483647 / 8) return -1 v = v * 8 + (c - 48) } if (!started) return -1 return v } function field_text(start, len, i, end, out, c) { end = start + len out = "" for (i = start; i < end; i++) { c = b[i] if (c == 0) { for (i = i + 1; i < end; i++) { if (b[i] != 0) return "__BAD_FIELD__" } return out } if (c < 32 || c > 126) return "__BAD_FIELD__" out = out sprintf("%c", c) } return out } ' } # Body + padding phase for one regular-file member. Seeks by block; does not # stream executable payload bytes through awk. Final partial block must be zero # past the declared size (same rule as UstarStreamParser padding). ustar_skip_member_body() { tar_path=$1 hdr_path=$2 i=$3 fsize=$4 blocks=$5 body_blocks=$(((fsize + 511) / 512)) end=$((i + 1 + body_blocks)) if [ "$end" -gt "$blocks" ]; then die "Archive structure is truncated or not block-aligned" fi if [ "$fsize" -gt 0 ]; then rem=$((fsize % 512)) if [ "$rem" -ne 0 ]; then last=$((i + body_blocks)) ustar_read_block "$tar_path" "$hdr_path" "$last" pad_ok=$( exec 9>&- od -An -v -tu1 -N512 "$hdr_path" 9>&- | awk -v rem="$rem" ' { for (i = 1; i <= NF; i++) b[n++] = $i + 0 } END { if (n != 512) { print "bad"; exit 1 } for (i = rem; i < 512; i++) { if (b[i] != 0) { print "bad"; exit 1 } } print "ok" } ' ) || die "Archive structure is truncated or not block-aligned" [ "$pad_ok" = ok ] || die "Archive structure is truncated or not block-aligned" fi fi # Caller advances the block cursor to end. USTAR_NEXT_I=$end } # Trailing phase: require the second zero block, then only zero blocks to EOF. ustar_consume_trailing() { tar_path=$1 hdr_path=$2 zero=$3 i=$4 blocks=$5 # i points at the block after the first zero of the end marker. while [ "$i" -lt "$blocks" ]; do ustar_read_block "$tar_path" "$hdr_path" "$i" cmp -s "$hdr_path" "$zero" 9>&- || die "Archive has excess trailing nonzero data" i=$((i + 1)) done USTAR_NEXT_I=$i } # Walk every 512-byte block of the private tar (already size-bounded). Require # the exact pinned member set via a numeric bitmask (no path inventory file). validate_ustar_physical() { tar_path=$1 stem=$2 stage=$3 size=$( exec 9>&- wc -c < "$tar_path" | tr -d ' ' ) if [ -z "$size" ] || [ "$size" -le 0 ] || [ "$size" -gt "$MAX_TAR_BYTES" ]; then die "Release archive expanded size is outside the bound" fi if [ "$((size % 512))" -ne 0 ]; then die "Archive structure is truncated or not block-aligned" fi blocks=$((size / 512)) if [ "$blocks" -lt 2 ]; then die "Archive structure is truncated or not block-aligned" fi hdr="$stage/.ustar-hdr" zero="$stage/.ustar-zero" rm -f "$hdr" "$zero" 9>&- ( exec 9>&- dd if=/dev/zero of="$zero" bs=512 count=1 2>/dev/null ) || die "Could not prepare ustar validation scratch" # Canonical full member paths for this archive stem (generated layout). m0="$stem" m1="$stem/1667" m2="$stem/build-manifest.json" m3="$stem/sbom.spdx.json" m4="$stem/LICENSE" m5="$stem/NOTICE" i=0 zero_run=0 saw_end=0 seen=0 file_bytes=0 exesize= expected_mask=63 exec_id=1 while [ "$i" -lt "$blocks" ]; do ustar_read_block "$tar_path" "$hdr" "$i" if cmp -s "$hdr" "$zero" 9>&-; then zero_run=$((zero_run + 1)) if [ "$zero_run" -eq 2 ]; then saw_end=1 i=$((i + 1)) ustar_consume_trailing "$tar_path" "$hdr" "$zero" "$i" "$blocks" i=$USTAR_NEXT_I break fi i=$((i + 1)) continue fi if [ "$zero_run" -ne 0 ]; then die "Archive structure is truncated or not block-aligned" fi parsed=$( exec 9>&- parse_ustar_header "$hdr" ) || die "Archive contains a symbolic link, hard link, special entry, or non-ustar header" # Trusted compact records only. Never word-split free-form paths. case "$parsed" in zero) die "Archive structure is truncated or not block-aligned" ;; bad|"") die "Archive contains a symbolic link, hard link, special entry, or non-ustar header" ;; layout) die "Archive layout is not the exact pinned Release Archive layout" ;; D:0) bit=1 if [ "$((seen & bit))" -ne 0 ]; then die "Archive layout is not the exact pinned Release Archive layout" fi seen=$((seen | bit)) i=$((i + 1)) ;; F:*) rest="${parsed#F:}" mid="${rest%%:*}" fsize="${rest#*:}" case "$mid" in "" | *[!0-9]*) die "Archive layout is not the exact pinned Release Archive layout" ;; esac case "$fsize" in "" | *[!0-9]*) die "Archive layout is not the exact pinned Release Archive layout" ;; esac if [ "$mid" -le 0 ] || [ "$mid" -ge 6 ]; then die "Archive layout is not the exact pinned Release Archive layout" fi # Reject F:id:size forms with extra colon payload (path leak / confuse). case "$fsize" in *:*) die "Archive layout is not the exact pinned Release Archive layout" ;; esac if [ "$fsize" -gt "$((MAX_FILE_BYTES - file_bytes))" ]; then die "Release archive file bytes are outside the bound" fi file_bytes=$((file_bytes + fsize)) bit=$((1 << mid)) if [ "$((seen & bit))" -ne 0 ]; then die "Archive layout is not the exact pinned Release Archive layout" fi seen=$((seen | bit)) if [ "$mid" -eq "$exec_id" ]; then if [ "$fsize" -le 0 ] || [ "$fsize" -gt "$MAX_EXECUTABLE_BYTES" ]; then die "Release executable size is outside the bound" fi exesize=$fsize fi ustar_skip_member_body "$tar_path" "$hdr" "$i" "$fsize" "$blocks" i=$USTAR_NEXT_I ;; *) die "Archive contains a symbolic link, hard link, special entry, or non-ustar header" ;; esac done if [ "$saw_end" -ne 1 ]; then die "Archive structure is truncated or not block-aligned" fi if [ -z "$exesize" ] || [ "$seen" -ne "$expected_mask" ]; then die "Archive layout is not the exact pinned Release Archive layout" fi rm -f "$hdr" "$zero" 9>&- } # Extract only the pinned 1667 executable into private reserved staging. # Does not trust archive ownership or modes. Enforces the expanded size bound # on the complete decompressed stream before extraction. Enforces the # executable size bound on header claim and on extracted bytes. extract_candidate() { root=$1 archive_path=$2 archive=$3 stem=${archive%.tar.gz} require_extract_tools # One exact reserved staging path, protected by the Install Root lock. stage="$root/$EXTRACT_STAGE" remove_extract_stage "$root" mkdir -m 0700 "$stage" 9>&- tar_path="$stage/archive.tar" decompress_archive_bounded "$archive_path" "$tar_path" validate_ustar_physical "$tar_path" "$stem" "$stage" member="$stem/1667" # Extract only the expected regular executable member from the private # validated tar. Never preserve archive member UID/GID. As root, tar defaults # to same-owner (GNU tar and macOS bsdtar), which would install files as the # release runner. Close FD 9 so a surviving extract child cannot hold the lock. tar --no-same-owner -xf "$tar_path" -C "$stage" "$member" 9>&- candidate="$stage/$member" [ -f "$candidate" ] || die "Archive is missing the 1667 executable" [ ! -L "$candidate" ] || die "Archive executable must not be a symbolic link" # Expanded output bound before activation (header claim already checked). size=$( exec 9>&- wc -c < "$candidate" | tr -d ' ' ) if [ "$size" -le 0 ] || [ "$size" -gt "$MAX_EXECUTABLE_BYTES" ]; then die "Release executable size is outside the bound" fi rm -f "$root/$CANDIDATE_FILE" 9>&- mv "$candidate" "$root/$CANDIDATE_FILE" 9>&- # Installer-chosen mode; do not preserve archive modes. chmod 0755 "$root/$CANDIDATE_FILE" 9>&- remove_extract_stage "$root" } # Extract one JSON string field by fixed key name. Key is caller-controlled and # never user-supplied. Compare extracted values with shell string equality so # PRODUCT_VERSION / target dots and plus signs are literal (not ERE metachars). json_string_field() { text=$1 key=$2 printf '%s\n' "$text" | tr ',' '\n' | sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -n 1 } # Portable bounded version probe for generated install.sh (macOS + POSIX sh). # - Candidate does not inherit Install Root lock FD 9. # - Runtime is bounded without GNU timeout (watchdog + sleep). # - Output is bounded with the POSIX file-size resource limit. # - Child and watchdog are terminated and reaped on timeout and by stop_probe. PROBE_PID= PROBE_WATCHDOG_PID= MANAGED_PROBE_VERSION= run_bounded_probe() { candidate=$1 out=$2 rm -f "$out" 9>&- # Noclobber makes an output-path race fail closed. # The subshell exec makes PROBE_PID the candidate PID, not a wrapper PID. ( exec 9>&- umask 077 ulimit -f "$PROBE_MAX_OUTPUT_BLOCKS" set -C exec "$candidate" --version --json > "$out" 2>/dev/null ) & PROBE_PID=$! probe_pid=$PROBE_PID # Watchdog must not hold the lock either. ( exec 9>&- watchdog_timer= trap ' trap - INT TERM if [ -n "${watchdog_timer:-}" ]; then kill "$watchdog_timer" 2>/dev/null || true wait "$watchdog_timer" 2>/dev/null || true fi exit 0 ' INT TERM sleep "$PROBE_TIMEOUT_SEC" & watchdog_timer=$! wait "$watchdog_timer" watchdog_timer= trap - INT TERM if kill -0 "$probe_pid" 2>/dev/null; then kill "$probe_pid" 2>/dev/null || true sleep 1 kill -9 "$probe_pid" 2>/dev/null || true fi ) & PROBE_WATCHDOG_PID=$! set +e wait "$PROBE_PID" status=$? set -e PROBE_PID= if [ -n "${PROBE_WATCHDOG_PID:-}" ]; then kill "$PROBE_WATCHDOG_PID" 2>/dev/null || true set +e wait "$PROBE_WATCHDOG_PID" 2>/dev/null set -e PROBE_WATCHDOG_PID= fi return "$status" } probe_candidate() { candidate=$1 target=$2 out="${candidate%/*}/$PROBE_OUTPUT_FILE" if ! run_bounded_probe "$candidate" "$out"; then rm -f "$out" 9>&- die "Candidate version probe failed" fi # Preserve trailing newlines for identity JSON (command substitution would drop them). # Each capture subshell inherits FD 9; close it so a hung reader cannot pin the lock. if ! out_text=$( exec 9>&- cat "$out" ); then rm -f "$out" 9>&- die "Candidate version probe failed" fi rm -f "$out" 9>&- product=$( exec 9>&- json_string_field "$out_text" product ) version=$( exec 9>&- json_string_field "$out_text" productVersion ) art=$( exec 9>&- json_string_field "$out_text" artifactTarget ) kind=$( exec 9>&- json_string_field "$out_text" buildKind ) [ "$product" = "1667" ] || die "Candidate product is not 1667" [ "$version" = "$PRODUCT_VERSION" ] || die "Candidate version did not match the pinned release" [ "$art" = "$target" ] || die "Candidate target did not match this host" [ "$kind" = "release" ] || die "Candidate is not a release build" } probe_candidate_soft() { candidate=$1 target=$2 out="${candidate%/*}/$PROBE_OUTPUT_FILE" if ! run_bounded_probe "$candidate" "$out"; then rm -f "$out" 9>&- return 1 fi if ! out_text=$( exec 9>&- cat "$out" ); then rm -f "$out" 9>&- return 1 fi rm -f "$out" 9>&- product=$( exec 9>&- json_string_field "$out_text" product ) version=$( exec 9>&- json_string_field "$out_text" productVersion ) art=$( exec 9>&- json_string_field "$out_text" artifactTarget ) kind=$( exec 9>&- json_string_field "$out_text" buildKind ) [ "$product" = "1667" ] || return 1 [ "$version" = "$PRODUCT_VERSION" ] || return 1 [ "$art" = "$target" ] || return 1 [ "$kind" = "release" ] || return 1 return 0 } # Probe an existing managed active executable. Unlike the release candidate # probe, this accepts any release version so an older installer can bootstrap # across a changed package/NOTICE file. The caller invokes this directly so # signal traps can see PROBE_PID; the version is returned in MANAGED_PROBE_VERSION. probe_managed_active() { candidate=$1 target=$2 out="${candidate%/*}/$PROBE_OUTPUT_FILE" if ! run_bounded_probe "$candidate" "$out"; then rm -f "$out" 9>&- die "Managed active executable version probe failed" fi if ! out_text=$( exec 9>&- cat "$out" ); then rm -f "$out" 9>&- die "Managed active executable version probe failed" fi rm -f "$out" 9>&- product=$(exec 9>&-; json_string_field "$out_text" product) version=$(exec 9>&-; json_string_field "$out_text" productVersion) art=$(exec 9>&-; json_string_field "$out_text" artifactTarget) kind=$(exec 9>&-; json_string_field "$out_text" buildKind) [ "$product" = "1667" ] || die "Managed active executable is not 1667" [ "$art" = "$target" ] || die "Managed active executable target did not match this host" [ "$kind" = "release" ] || die "Managed active executable is not a release build" version_length=$(exec 9>&-; printf '%s' "$version" | wc -c | tr -d ' ') [ -n "$version" ] && [ "$version_length" -le 128 ] || die "Managed active executable version is invalid" semver_valid "$version" || die "Managed active executable version is invalid" MANAGED_PROBE_VERSION=$version } main "$@"