diff --git a/README.md b/README.md index 923195a..cc775fe 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,10 @@ oab-instance-mcp --token-file ~/.config/oab-instance-mcp/token \ - On `401`/`403` it retries every ~5 minutes rather than stopping. - **Secret rotation:** the secret file is re-read on every dial, so rotating the secret means updating the file; the next retry picks it up. +- **Installed with the package:** put the URL in `~/.config/oab-instance-mcp/switchboard.url`, the + secret in `switchboard.secret` (mode 600) and, optionally, the profile in `switchboard.profile`. + Then re-run the installer: the flags live in the LaunchAgent plist, which the installer writes + whenever both files exist, so a restart alone does not pick them up and upgrades keep them. - **Exiting:** the HTTP endpoint keeps serving after the switchboard attach stops. Restart the process (or the LaunchAgent) to dial again after a `4002` or `4003`. diff --git a/Sources/oab-instance-mcp/main.swift b/Sources/oab-instance-mcp/main.swift index 010a035..b083fe0 100644 --- a/Sources/oab-instance-mcp/main.swift +++ b/Sources/oab-instance-mcp/main.swift @@ -4,7 +4,7 @@ import CoreGraphics import Foundation import InstanceMCPCore -let version = "0.7.0" +let version = "0.8.0" struct Options { var host = "127.0.0.1" diff --git a/docs/releasing.md b/docs/releasing.md index 68b16dd..0efafa5 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -77,8 +77,8 @@ deleted in an `always()` cleanup step. 3. Tag the exact main commit and push: ```sh - git tag v0.7.0 - git push origin v0.7.0 + git tag v0.8.0 + git push origin v0.8.0 ``` 4. The `Release macOS installer` workflow builds/tests, signs, notarizes and publishes the macOS @@ -89,15 +89,15 @@ deleted in an `always()` cleanup step. `main` is rejected before any job starts ("Branch main is not allowed to deploy to release"): ```sh - gh workflow run release.yml --ref v0.7.0 -f tag=v0.7.0 + gh workflow run release.yml --ref v0.8.0 -f tag=v0.8.0 ``` 5. Download both artifacts and verify before installing: ```sh scripts/verify-release.sh \ - oab-instance-mcp-0.7.0-universal.app.zip \ - oab-instance-mcp-0.7.0-universal.pkg + oab-instance-mcp-0.8.0-universal.app.zip \ + oab-instance-mcp-0.8.0-universal.pkg shasum -a 256 -c SHA256SUMS ``` @@ -129,8 +129,8 @@ lipo -create /tmp/imcp-arm64/release/oab-instance-mcp \ /tmp/imcp-x86_64/release/oab-instance-mcp \ -output /tmp/oab-instance-mcp chmod +x /tmp/oab-instance-mcp -scripts/assemble-app.sh /tmp/oab-instance-mcp /tmp/oab-instance-mcp.app 0.7.0 -ALLOW_UNSIGNED=1 scripts/package-pkg.sh /tmp/oab-instance-mcp.app /tmp/oab-instance-mcp.pkg 0.7.0 +scripts/assemble-app.sh /tmp/oab-instance-mcp /tmp/oab-instance-mcp.app 0.8.0 +ALLOW_UNSIGNED=1 scripts/package-pkg.sh /tmp/oab-instance-mcp.app /tmp/oab-instance-mcp.pkg 0.8.0 ``` Unsigned artifacts are testing inputs only; do not install or publish them. diff --git a/scripts/install-prebuilt.sh b/scripts/install-prebuilt.sh index 1c2ebf6..a24cee7 100755 --- a/scripts/install-prebuilt.sh +++ b/scripts/install-prebuilt.sh @@ -185,6 +185,17 @@ if [ "${SKIP_LAUNCH:-0}" != "1" ] && /bin/launchctl print "gui/$UID_/dev.openab. elif [ "${TEST_WITH_UPSTREAM:-0}" = "1" ]; then ARGS+=(--upstream browser=http://127.0.0.1:8794/mcp) fi +# Switchboard mode is configured by files, so an update keeps it: the URL in +# switchboard.url plus the secret in switchboard.secret turn it on, and +# switchboard.profile (observe|desktop|owner) optionally picks the profile. +SB_DIR="$HOME_DIR/.config/oab-instance-mcp" +if [ -s "$SB_DIR/switchboard.url" ] && [ -s "$SB_DIR/switchboard.secret" ]; then + SB_URL=$(/usr/bin/head -n 1 "$SB_DIR/switchboard.url" | /usr/bin/tr -d '[:space:]') + ARGS+=(--switchboard "$SB_URL" --switchboard-secret-file "$SB_DIR/switchboard.secret") + if [ -s "$SB_DIR/switchboard.profile" ]; then + ARGS+=(--switchboard-profile "$(/usr/bin/head -n 1 "$SB_DIR/switchboard.profile" | /usr/bin/tr -d '[:space:]')") + fi +fi for i in "${!ARGS[@]}"; do "$PB" -c "Add :ProgramArguments:$i string ${ARGS[$i]}" "$PLIST"; done "$PB" -c 'Add :RunAtLoad bool true' "$PLIST" "$PB" -c 'Add :KeepAlive bool true' "$PLIST" diff --git a/scripts/test-packaging.sh b/scripts/test-packaging.sh index 28c7fa6..b77293f 100755 --- a/scripts/test-packaging.sh +++ b/scripts/test-packaging.sh @@ -48,6 +48,24 @@ ALLOW_UNSIGNED=1 INSTALL_HOME="$HOME1" SKIP_LAUNCH=1 SKIP_TAILSCALE=1 \ "$ROOT/scripts/install-prebuilt.sh" "$APP" --allow-login test@example.invalid >/dev/null [ "$(cat "$TOKEN")" = "$TOKEN_BEFORE" ] +# Switchboard mode comes from config files and survives an update. +SBC="$HOME1/.config/oab-instance-mcp" +if /usr/libexec/PlistBuddy -c 'Print :ProgramArguments' "$PLIST" | grep -q -- '--switchboard'; then + echo "switchboard args present without config" >&2; exit 1 +fi +echo 'wss://sb.example.invalid/vm/attach' >"$SBC/switchboard.url" +echo 'not-a-real-secret' >"$SBC/switchboard.secret" +echo 'desktop' >"$SBC/switchboard.profile" +ALLOW_UNSIGNED=1 INSTALL_HOME="$HOME1" SKIP_LAUNCH=1 SKIP_TAILSCALE=1 \ + "$ROOT/scripts/install-prebuilt.sh" "$APP" --allow-login test@example.invalid >/dev/null +SB_ARGS=$(/usr/libexec/PlistBuddy -c 'Print :ProgramArguments' "$PLIST") +echo "$SB_ARGS" | grep -qx ' *--switchboard' +echo "$SB_ARGS" | grep -qx ' *wss://sb.example.invalid/vm/attach' +echo "$SB_ARGS" | grep -qx " *$SBC/switchboard.secret" +echo "$SB_ARGS" | grep -qx ' *desktop' +if echo "$SB_ARGS" | grep -q 'not-a-real-secret'; then echo "secret leaked into the plist" >&2; exit 1; fi +rm -f "$SBC/switchboard.url" "$SBC/switchboard.secret" "$SBC/switchboard.profile" + # Exercise the real structured Tailscale identity path with an anonymized fixture. # The fake also records `serve`, so this does not touch the runner's tailnet. HOME2="$TMP/home-auto"