feat(desktop): add opt-in bundled Goose runtime

Signed-off-by: Salman Mohammed <smohammed@squareup.com>
This commit is contained in:
Salman Mohammed
2026-09-23 20:21:25 -04:00
parent 48884848f5
commit 4f77fd2dcd
30 changed files with 661 additions and 84 deletions

59
scripts/build-bundled-goose.sh Executable file
View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Build the internal macOS Goose sidecar from the reviewed source pin.
set -euo pipefail
ROOT=$(cd "$(dirname "$0")/.." && pwd)
cd "$ROOT"
source ./bin/activate-hermit
[[ $(uname -s) == Darwin ]] || { echo 'Bundled Goose currently supports macOS only' >&2; exit 1; }
TARGET=${1:-$(rustc -vV | sed -n 's/^host: //p')}
case "$TARGET" in aarch64-apple-darwin|x86_64-apple-darwin) ;; *) echo "Unsupported target: $TARGET" >&2; exit 1 ;; esac
PIN="$ROOT/scripts/goose-build.json"
REPOSITORY=$(node -p 'require(process.argv[1]).repository' "$PIN")
REVISION=$(node -p 'require(process.argv[1]).revision' "$PIN")
PROFILE=$(node -p 'require(process.argv[1]).profile' "$PIN")
FEATURES=$(node -p 'require(process.argv[1]).features' "$PIN")
[[ "$REVISION" =~ ^[0-9a-f]{40}$ && "$PROFILE" == lean ]] || { echo 'Invalid Goose source pin' >&2; exit 1; }
CACHE="$ROOT/.cache/bundled-goose/$REVISION"
SOURCE="$CACHE/source"
mkdir -p "$CACHE"
# Never share a mutable checkout or target directory with the developer's Goose.
if [[ ! -d "$SOURCE/.git" ]]; then
git init -q "$SOURCE"
fi
if ! git -C "$SOURCE" cat-file -e "$REVISION^{commit}" 2>/dev/null; then
git -C "$SOURCE" -c http.lowSpeedLimit=1024 -c http.lowSpeedTime=60 fetch --depth=1 "$REPOSITORY" "$REVISION"
fi
[[ -z $(git -C "$SOURCE" status --porcelain) ]] || { echo "Dirty Goose build checkout: $SOURCE" >&2; exit 1; }
git -C "$SOURCE" checkout --detach "$REVISION"
[[ $(git -C "$SOURCE" rev-parse HEAD) == "$REVISION" ]]
(
cd "$SOURCE"
source ./bin/activate-hermit
TOOLCHAIN=$(rustc -vV | shasum -a 256 | cut -d ' ' -f 1)
export CARGO_TARGET_DIR="$CACHE/target/$TOOLCHAIN/$FEATURES"
# Avoid a runtime dependency on a build machine's Homebrew libssl/libcrypto.
export OPENSSL_STATIC=1
cargo build --locked -p goose --bin goose-acp --profile "$PROFILE" \
--no-default-features --features "$FEATURES" --target "$TARGET"
BINARY="$CARGO_TARGET_DIR/$TARGET/$PROFILE/goose-acp"
"$ROOT/scripts/verify-bundled-goose.sh" "$BINARY"
DEST="$ROOT/desktop/src-tauri/binaries/goose-acp-$TARGET"
mkdir -p "$(dirname "$DEST")"
# Atomic replacement keeps an already-running signed executable valid.
STAGED=$(mktemp "$DEST.XXXXXX")
trap 'rm -f "$STAGED"' EXIT
cp "$BINARY" "$STAGED"
chmod 755 "$STAGED"
mv -f "$STAGED" "$DEST"
node - "$PIN" "$DEST" "$TARGET" "$(rustc --version)" <<'JS'
const fs = require('node:fs');
const crypto = require('node:crypto');
const [pin, binary, target, rustc] = process.argv.slice(2);
const manifest = {
...JSON.parse(fs.readFileSync(pin, 'utf8')), target, rustc,
unsigned_sha256: crypto.createHash('sha256').update(fs.readFileSync(binary)).digest('hex'),
};
fs.writeFileSync(`${binary}.json`, `${JSON.stringify(manifest, null, 2)}\n`);
JS
echo "Staged $DEST"
)

6
scripts/goose-build.json Normal file
View File

@@ -0,0 +1,6 @@
{
"repository": "https://github.com/aaif-goose/goose.git",
"revision": "6a2c3dadf6a8866aeb434f4d3c41ea58b278d6c0",
"profile": "lean",
"features": "native-tls,system-keyring"
}

15
scripts/verify-bundled-goose.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Run against both the staged binary and the signed .app executable.
set -euo pipefail
BINARY=${1:?usage: verify-bundled-goose.sh /path/to/goose-acp}
[[ -x "$BINARY" ]] || { echo "Missing executable: $BINARY" >&2; exit 1; }
# Only system dylibs are permitted: no unshipped Homebrew or @rpath libraries.
DEPENDENCIES=$(otool -L "$BINARY" | tail -n +2 | sed -E 's/^[[:space:]]*//; s/ \(compatibility version.*$//')
while IFS= read -r dependency; do
case "$dependency" in
/usr/lib/*|/System/Library/*) ;;
*) echo "Unbundled Goose dependency: $dependency" >&2; exit 1 ;;
esac
done <<< "$DEPENDENCIES"
"$BINARY" --version
"$BINARY" --help | grep -Fq 'Usage: goose-acp'