feat: add Atlas native app UX overhaul

This commit is contained in:
zhukang
2026-03-10 17:09:35 +08:00
parent 0fabc6feec
commit 994e63f0b3
199 changed files with 38705 additions and 0 deletions

24
scripts/atlas/build-native.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
PROJECT_PATH="$ROOT_DIR/Atlas.xcodeproj"
SCHEME="AtlasApp"
CONFIGURATION="${CONFIGURATION:-Release}"
DERIVED_DATA_PATH="${DERIVED_DATA_PATH:-$ROOT_DIR/.build/atlas-native/DerivedData}"
if [[ -f "$ROOT_DIR/project.yml" ]]; then
if command -v xcodegen >/dev/null 2>&1; then
(cd "$ROOT_DIR" && xcodegen generate)
elif [[ ! -d "$PROJECT_PATH" || "$ROOT_DIR/project.yml" -nt "$PROJECT_PATH/project.pbxproj" ]]; then
echo "Atlas.xcodeproj is missing or stale, but xcodegen is not installed." >&2
exit 1
fi
fi
xcodebuild \
-project "$PROJECT_PATH" \
-scheme "$SCHEME" \
-configuration "$CONFIGURATION" \
-derivedDataPath "$DERIVED_DATA_PATH" \
build

View File

@@ -0,0 +1,89 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
source "$ROOT_DIR/scripts/atlas/signing-common.sh"
KEYCHAIN_PATH="$(atlas_local_signing_keychain_path)"
KEYCHAIN_PASSWORD="$(atlas_local_signing_keychain_password)"
IDENTITY_NAME="$(atlas_local_signing_identity_name)"
VALID_DAYS="${ATLAS_LOCAL_SIGNING_VALID_DAYS:-3650}"
P12_PASSWORD="${ATLAS_LOCAL_SIGNING_P12_PASSWORD:-atlas-local-signing-p12}"
if atlas_local_identity_usable; then
atlas_unlock_local_signing_keychain
printf 'Atlas local signing identity ready\n'
printf 'Identity: %s\n' "$IDENTITY_NAME"
printf 'Keychain: %s\n' "$KEYCHAIN_PATH"
exit 0
fi
if [[ -f "$KEYCHAIN_PATH" ]]; then
rm -f "$KEYCHAIN_PATH"
fi
mkdir -p "$(dirname "$KEYCHAIN_PATH")"
tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/atlas-local-signing.XXXXXX")"
cleanup() {
rm -rf "$tmpdir"
}
trap cleanup EXIT
cat > "$tmpdir/openssl.cnf" <<EOF
[ req ]
distinguished_name = dn
x509_extensions = ext
prompt = no
[ dn ]
CN = $IDENTITY_NAME
[ ext ]
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
EOF
/usr/bin/openssl req \
-new \
-x509 \
-nodes \
-newkey rsa:2048 \
-days "$VALID_DAYS" \
-keyout "$tmpdir/identity.key" \
-out "$tmpdir/identity.crt" \
-config "$tmpdir/openssl.cnf" >/dev/null 2>&1
/usr/bin/openssl pkcs12 \
-export \
-inkey "$tmpdir/identity.key" \
-in "$tmpdir/identity.crt" \
-out "$tmpdir/identity.p12" \
-passout "pass:$P12_PASSWORD" >/dev/null 2>&1
if [[ ! -f "$KEYCHAIN_PATH" ]]; then
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" >/dev/null
fi
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security import "$tmpdir/identity.p12" \
-k "$KEYCHAIN_PATH" \
-P "$P12_PASSWORD" \
-f pkcs12 \
-A \
-T /usr/bin/codesign \
-T /usr/bin/security >/dev/null
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" >/dev/null
atlas_unlock_local_signing_keychain
if ! atlas_local_identity_usable; then
echo "Failed to provision local Atlas signing identity." >&2
exit 1
fi
printf 'Created Atlas local signing identity\n'
printf 'Identity: %s\n' "$IDENTITY_NAME"
printf 'Keychain: %s\n' "$KEYCHAIN_PATH"
printf 'Use: ./scripts/atlas/package-native.sh\n'

View File

@@ -0,0 +1,68 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
cd "$ROOT_DIR"
run_ui_acceptance() {
local atlas_log repro_log
atlas_log="$(mktemp -t atlas-ui-acceptance.XXXXXX.log)"
repro_log="$(mktemp -t atlas-ui-repro.XXXXXX.log)"
trap 'rm -f "$atlas_log" "$repro_log"' RETURN
if ./scripts/atlas/run-ui-automation.sh 2>&1 | tee "$atlas_log"; then
return 0
fi
echo "Atlas UI automation failed; checking standalone repro to classify the failure..."
if xcodebuild test \
-project Testing/XCUITestRepro/XCUITestRepro.xcodeproj \
-scheme XCUITestRepro \
-destination 'platform=macOS' 2>&1 | tee "$repro_log"; then
echo "Standalone repro passed while Atlas UI automation failed; treating this as an Atlas-specific blocker."
return 1
fi
if grep -q 'Timed out while enabling automation mode' "$atlas_log" && grep -q 'Timed out while enabling automation mode' "$repro_log"; then
echo "UI automation is blocked by the current macOS automation environment; continuing acceptance with a documented environment condition."
return 0
fi
echo "UI automation failed for a reason that was not classified as a shared environment blocker."
return 1
}
echo "[1/10] Shared package tests"
swift test --package-path Packages
echo "[2/10] App package tests"
swift test --package-path Apps
echo "[3/10] Worker and helper builds"
swift build --package-path XPC
swift test --package-path Helpers
swift build --package-path Testing
echo "[4/10] Native packaging"
./scripts/atlas/package-native.sh
echo "[5/10] Bundle structure verification"
./scripts/atlas/verify-bundle-contents.sh
echo "[6/10] DMG install verification"
KEEP_INSTALLED_APP=1 ./scripts/atlas/verify-dmg-install.sh
echo "[7/10] Installed app launch smoke"
./scripts/atlas/verify-app-launch.sh
echo "[8/10] Native UI automation"
run_ui_acceptance
echo "[9/10] Signing preflight"
./scripts/atlas/signing-preflight.sh || true
echo "[10/10] Acceptance summary"
echo "Artifacts available in dist/native"
ls -lah dist/native

139
scripts/atlas/package-native.sh Executable file
View File

@@ -0,0 +1,139 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
source "$ROOT_DIR/scripts/atlas/signing-common.sh"
DIST_DIR="${DIST_DIR:-$ROOT_DIR/dist/native}"
DERIVED_DATA_PATH="${DERIVED_DATA_PATH:-$ROOT_DIR/.build/atlas-native/DerivedData}"
APP_NAME="Atlas for Mac.app"
APP_PATH="$DERIVED_DATA_PATH/Build/Products/Release/$APP_NAME"
HELPER_BINARY="$ROOT_DIR/Helpers/.build/release/AtlasPrivilegedHelper"
ZIP_PATH="$DIST_DIR/Atlas-for-Mac.zip"
DMG_PATH="$DIST_DIR/Atlas-for-Mac.dmg"
PKG_PATH="$DIST_DIR/Atlas-for-Mac.pkg"
SHA_PATH="$DIST_DIR/Atlas-for-Mac.sha256"
PACKAGED_APP_PATH="$DIST_DIR/$APP_NAME"
DMG_STAGING_DIR="$DIST_DIR/dmg-root"
REQUESTED_APP_SIGN_IDENTITY="${ATLAS_CODESIGN_IDENTITY:-}"
APP_SIGN_IDENTITY="$(atlas_resolve_app_signing_identity)"
APP_SIGNING_KEYCHAIN="$(atlas_resolve_app_signing_keychain "$APP_SIGN_IDENTITY")"
APP_SIGNING_MODE="$(atlas_signing_mode_for_identity "$APP_SIGN_IDENTITY")"
INSTALLER_SIGN_IDENTITY="$(atlas_resolve_installer_signing_identity)"
NOTARY_PROFILE="${ATLAS_NOTARY_PROFILE:-}"
mkdir -p "$DIST_DIR"
sign_app_component() {
local path="$1"
local args=(--force --sign "$APP_SIGN_IDENTITY")
local entitlements_file=""
if [[ -n "$APP_SIGNING_KEYCHAIN" ]]; then
args+=(--keychain "$APP_SIGNING_KEYCHAIN")
fi
if [[ "$APP_SIGNING_MODE" == "developer-id" ]]; then
args+=(--options runtime --timestamp)
fi
entitlements_file="$(mktemp "${TMPDIR:-/tmp}/atlas-entitlements.XXXXXX")"
if /usr/bin/codesign -d --entitlements :- "$path" > "$entitlements_file" 2>/dev/null && /usr/bin/grep -q '<plist' "$entitlements_file"; then
args+=(--entitlements "$entitlements_file")
else
rm -f "$entitlements_file"
entitlements_file=""
fi
codesign "${args[@]}" "$path"
if [[ -n "$entitlements_file" ]]; then
rm -f "$entitlements_file"
fi
}
if [[ -n "$APP_SIGNING_KEYCHAIN" ]]; then
atlas_unlock_local_signing_keychain
fi
printf 'App signing identity: %s (%s)\n' "$APP_SIGN_IDENTITY" "$APP_SIGNING_MODE"
if [[ -n "$APP_SIGNING_KEYCHAIN" ]]; then
printf 'App signing keychain: %s\n' "$APP_SIGNING_KEYCHAIN"
fi
printf 'Installer signing identity: %s\n' "${INSTALLER_SIGN_IDENTITY:-UNSIGNED}"
swift build --package-path "$ROOT_DIR/Helpers" -c release
"$ROOT_DIR/scripts/atlas/build-native.sh"
if [[ ! -d "$APP_PATH" ]]; then
echo "Built app not found at $APP_PATH" >&2
exit 1
fi
python3 - "$PACKAGED_APP_PATH" "$DMG_STAGING_DIR" "$DMG_PATH" <<'PY'
from pathlib import Path
import shutil, sys
for raw in sys.argv[1:]:
path = Path(raw)
if path.exists():
if path.is_dir():
shutil.rmtree(path)
else:
path.unlink()
PY
cp -R "$APP_PATH" "$PACKAGED_APP_PATH"
mkdir -p "$PACKAGED_APP_PATH/Contents/Helpers"
cp "$HELPER_BINARY" "$PACKAGED_APP_PATH/Contents/Helpers/AtlasPrivilegedHelper"
chmod +x "$PACKAGED_APP_PATH/Contents/Helpers/AtlasPrivilegedHelper"
while IFS= read -r xpc; do
sign_app_component "$xpc"
done < <(find "$PACKAGED_APP_PATH/Contents/XPCServices" -maxdepth 1 -name '*.xpc' -type d 2>/dev/null | sort)
sign_app_component "$PACKAGED_APP_PATH/Contents/Helpers/AtlasPrivilegedHelper"
sign_app_component "$PACKAGED_APP_PATH"
codesign --verify --deep --strict --verbose=2 "$PACKAGED_APP_PATH"
/usr/bin/ditto -c -k --sequesterRsrc --keepParent "$PACKAGED_APP_PATH" "$ZIP_PATH"
mkdir -p "$DMG_STAGING_DIR"
cp -R "$PACKAGED_APP_PATH" "$DMG_STAGING_DIR/$APP_NAME"
ln -s /Applications "$DMG_STAGING_DIR/Applications"
hdiutil create -volname "Atlas for Mac" -srcfolder "$DMG_STAGING_DIR" -ov -format UDZO "$DMG_PATH" >/dev/null
productbuild_args=(--component "$PACKAGED_APP_PATH" /Applications "$PKG_PATH")
if [[ -n "$INSTALLER_SIGN_IDENTITY" ]]; then
productbuild_args=(--sign "$INSTALLER_SIGN_IDENTITY" --component "$PACKAGED_APP_PATH" /Applications "$PKG_PATH")
fi
/usr/bin/productbuild "${productbuild_args[@]}"
(
cd "$DIST_DIR"
/usr/bin/shasum -a 256 \
"$(basename "$ZIP_PATH")" \
"$(basename "$DMG_PATH")" \
"$(basename "$PKG_PATH")" > "$SHA_PATH"
)
echo "Packaged app: $PACKAGED_APP_PATH"
echo "Zip artifact: $ZIP_PATH"
echo "DMG artifact: $DMG_PATH"
echo "Installer package: $PKG_PATH"
echo "Checksums: $SHA_PATH"
if [[ -n "$NOTARY_PROFILE" && "$APP_SIGNING_MODE" == "developer-id" && -n "$INSTALLER_SIGN_IDENTITY" ]]; then
xcrun notarytool submit "$PKG_PATH" --keychain-profile "$NOTARY_PROFILE" --wait
xcrun stapler staple "$PKG_PATH"
xcrun notarytool submit "$DMG_PATH" --keychain-profile "$NOTARY_PROFILE" --wait
xcrun notarytool submit "$ZIP_PATH" --keychain-profile "$NOTARY_PROFILE" --wait
xcrun stapler staple "$PACKAGED_APP_PATH"
/usr/bin/ditto -c -k --sequesterRsrc --keepParent "$PACKAGED_APP_PATH" "$ZIP_PATH"
(
cd "$DIST_DIR"
/usr/bin/shasum -a 256 \
"$(basename "$ZIP_PATH")" \
"$(basename "$DMG_PATH")" \
"$(basename "$PKG_PATH")" > "$SHA_PATH"
)
echo "Notarization complete"
fi

View File

@@ -0,0 +1,42 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
cd "$ROOT_DIR"
if ! ./scripts/atlas/ui-automation-preflight.sh >/dev/null; then
echo "Skipping native UI automation: Accessibility / automation permissions are not ready."
exit 0
fi
run_once() {
pkill -f 'Atlas for Mac.app/Contents/MacOS/Atlas for Mac' >/dev/null 2>&1 || true
pkill -f 'AtlasAppUITests-Runner|XCTRunner|xcodebuild test -project Atlas.xcodeproj -scheme AtlasApp' >/dev/null 2>&1 || true
sleep 2
xcodegen generate >/dev/null
xcodebuild test \
-project Atlas.xcodeproj \
-scheme AtlasApp \
-destination 'platform=macOS' \
-only-testing:AtlasAppUITests
}
LOG_FILE="$(mktemp -t atlas-ui-automation.XXXXXX.log)"
trap 'rm -f "$LOG_FILE"' EXIT
for attempt in 1 2; do
echo "UI automation attempt $attempt/2"
if run_once 2>&1 | tee "$LOG_FILE"; then
exit 0
fi
if grep -q 'Timed out while enabling automation mode' "$LOG_FILE" && [[ "$attempt" -lt 2 ]]; then
echo "UI automation timed out while enabling automation mode; retrying after cleanup..."
sleep 3
continue
fi
exit 1
done

View File

@@ -0,0 +1,168 @@
#!/bin/bash
atlas_local_signing_keychain_path() {
printf '%s\n' "${ATLAS_LOCAL_SIGNING_KEYCHAIN_PATH:-$HOME/Library/Keychains/AtlasLocalSigning.keychain-db}"
}
atlas_local_signing_keychain_password() {
printf '%s\n' "${ATLAS_LOCAL_SIGNING_KEYCHAIN_PASSWORD:-atlas-local-signing}"
}
atlas_local_signing_identity_name() {
printf '%s\n' "${ATLAS_LOCAL_SIGNING_IDENTITY_NAME:-Atlas Local Development}"
}
atlas_detect_release_app_identity() {
security find-identity -v -p codesigning 2>/dev/null \
| sed -n 's/.*"\(Developer ID Application:.*\)"/\1/p' \
| head -1
}
atlas_detect_development_app_identity() {
local output
output="$(security find-identity -v -p codesigning 2>/dev/null || true)"
local identity
identity="$(printf '%s\n' "$output" | sed -n 's/.*"\(Apple Development:.*\)"/\1/p' | head -1)"
if [[ -n "$identity" ]]; then
printf '%s\n' "$identity"
return 0
fi
printf '%s\n' "$output" | sed -n 's/.*"\(Mac Developer:.*\)"/\1/p' | head -1
}
atlas_detect_installer_identity() {
security find-identity -v -p basic 2>/dev/null \
| sed -n 's/.*"\(Developer ID Installer:.*\)"/\1/p' \
| head -1
}
atlas_local_identity_exists() {
local keychain_path identity_name
keychain_path="$(atlas_local_signing_keychain_path)"
identity_name="$(atlas_local_signing_identity_name)"
[[ -f "$keychain_path" ]] || return 1
security find-certificate -a -c "$identity_name" "$keychain_path" >/dev/null 2>&1
}
atlas_unlock_local_signing_keychain() {
local keychain_path keychain_password
keychain_path="$(atlas_local_signing_keychain_path)"
keychain_password="$(atlas_local_signing_keychain_password)"
[[ -f "$keychain_path" ]] || return 0
security unlock-keychain -p "$keychain_password" "$keychain_path" >/dev/null 2>&1 || true
security set-keychain-settings -lut 21600 "$keychain_path" >/dev/null 2>&1 || true
atlas_add_local_signing_keychain_to_search_list
}
atlas_add_local_signing_keychain_to_search_list() {
local keychain_path
keychain_path="$(atlas_local_signing_keychain_path)"
[[ -f "$keychain_path" ]] || return 0
local current_keychains=()
while IFS= read -r line; do
line="${line#"${line%%[![:space:]]*}"}"
line="${line%\"}"
line="${line#\"}"
[[ -n "$line" ]] && current_keychains+=("$line")
done < <(security list-keychains -d user 2>/dev/null || true)
if printf '%s\n' "${current_keychains[@]}" | grep -Fx "$keychain_path" >/dev/null 2>&1; then
return 0
fi
security list-keychains -d user -s "$keychain_path" "${current_keychains[@]}" >/dev/null 2>&1 || true
}
atlas_local_identity_usable() {
atlas_local_identity_exists || return 1
local keychain_path identity_name sample_file
keychain_path="$(atlas_local_signing_keychain_path)"
identity_name="$(atlas_local_signing_identity_name)"
atlas_unlock_local_signing_keychain
sample_file="$(mktemp "${TMPDIR:-/tmp}/atlas-local-signing-check.XXXXXX")"
printf 'atlas local signing check\n' > "$sample_file"
if ! /usr/bin/codesign --force --sign "$identity_name" --keychain "$keychain_path" "$sample_file" >/dev/null 2>&1; then
rm -f "$sample_file"
return 1
fi
rm -f "$sample_file"
return 0
}
atlas_signing_mode_for_identity() {
local identity="${1:-}"
local local_identity_name
local_identity_name="$(atlas_local_signing_identity_name)"
if [[ -z "$identity" || "$identity" == "-" ]]; then
printf '%s\n' "adhoc"
elif [[ "$identity" == Developer\ ID\ Application:* ]]; then
printf '%s\n' "developer-id"
elif [[ "$identity" == "$local_identity_name" ]]; then
printf '%s\n' "local-stable"
else
printf '%s\n' "local-stable"
fi
}
atlas_resolve_app_signing_identity() {
if [[ -n "${ATLAS_CODESIGN_IDENTITY:-}" ]]; then
printf '%s\n' "$ATLAS_CODESIGN_IDENTITY"
return 0
fi
local identity
identity="$(atlas_detect_release_app_identity)"
if [[ -n "$identity" ]]; then
printf '%s\n' "$identity"
return 0
fi
identity="$(atlas_detect_development_app_identity)"
if [[ -n "$identity" ]]; then
printf '%s\n' "$identity"
return 0
fi
if atlas_local_identity_usable; then
printf '%s\n' "$(atlas_local_signing_identity_name)"
return 0
fi
printf '%s\n' "-"
}
atlas_resolve_app_signing_keychain() {
local identity="${1:-}"
if [[ -n "${ATLAS_CODESIGN_KEYCHAIN:-}" ]]; then
printf '%s\n' "$ATLAS_CODESIGN_KEYCHAIN"
return 0
fi
if [[ "$identity" == "$(atlas_local_signing_identity_name)" ]] && atlas_local_identity_exists; then
printf '%s\n' "$(atlas_local_signing_keychain_path)"
return 0
fi
printf '%s\n' ""
}
atlas_resolve_installer_signing_identity() {
if [[ -n "${ATLAS_INSTALLER_SIGN_IDENTITY:-}" ]]; then
printf '%s\n' "$ATLAS_INSTALLER_SIGN_IDENTITY"
return 0
fi
atlas_detect_installer_identity
}

View File

@@ -0,0 +1,76 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
source "$ROOT_DIR/scripts/atlas/signing-common.sh"
APP_IDENTITY_OVERRIDE="${ATLAS_CODESIGN_IDENTITY:-}"
INSTALLER_IDENTITY_OVERRIDE="${ATLAS_INSTALLER_SIGN_IDENTITY:-}"
NOTARY_PROFILE_OVERRIDE="${ATLAS_NOTARY_PROFILE:-}"
codesign_output="$(security find-identity -v -p codesigning 2>/dev/null || true)"
basic_output="$(security find-identity -v -p basic 2>/dev/null || true)"
app_identity_detected="$(printf '%s\n' "$codesign_output" | sed -n 's/.*"\(Developer ID Application:.*\)"/\1/p' | head -1)"
installer_identity_detected="$(printf '%s\n' "$basic_output" | sed -n 's/.*"\(Developer ID Installer:.*\)"/\1/p' | head -1)"
app_identity="${APP_IDENTITY_OVERRIDE:-$app_identity_detected}"
installer_identity="${INSTALLER_IDENTITY_OVERRIDE:-$installer_identity_detected}"
local_identity=""
if atlas_local_identity_exists; then
local_identity="$(atlas_local_signing_identity_name)"
fi
printf 'Atlas signing preflight\n'
printf '======================\n'
printf 'Developer ID Application: %s\n' "${app_identity:-MISSING}"
printf 'Developer ID Installer: %s\n' "${installer_identity:-MISSING}"
printf 'Notary profile: %s\n' "${NOTARY_PROFILE_OVERRIDE:-MISSING}"
if [[ -n "$local_identity" ]]; then
printf 'Stable local app identity: %s\n' "$local_identity"
else
printf 'Stable local app identity: MISSING\n'
fi
status=0
if [[ -z "$app_identity" ]]; then
echo '✗ Missing Developer ID Application identity'
status=1
fi
if [[ -z "$installer_identity" ]]; then
echo '✗ Missing Developer ID Installer identity'
status=1
fi
if [[ -z "$NOTARY_PROFILE_OVERRIDE" ]]; then
echo '✗ Missing notarytool keychain profile name in ATLAS_NOTARY_PROFILE'
status=1
fi
if [[ -n "$NOTARY_PROFILE_OVERRIDE" ]]; then
if xcrun notarytool history --keychain-profile "$NOTARY_PROFILE_OVERRIDE" >/dev/null 2>&1; then
echo '✓ notarytool profile is usable'
else
echo '✗ notarytool profile could not be validated'
status=1
fi
fi
if [[ $status -eq 0 ]]; then
echo '✓ Release signing prerequisites are present'
echo "export ATLAS_CODESIGN_IDENTITY='$app_identity'"
echo "export ATLAS_INSTALLER_SIGN_IDENTITY='$installer_identity'"
echo "export ATLAS_NOTARY_PROFILE='$NOTARY_PROFILE_OVERRIDE'"
else
echo
echo 'To unblock signed/notarized release packaging, provide or install:'
echo ' 1. Developer ID Application certificate'
echo ' 2. Developer ID Installer certificate'
echo ' 3. notarytool keychain profile name via ATLAS_NOTARY_PROFILE'
if [[ -z "$local_identity" ]]; then
echo
echo 'For stable local TCC-friendly builds without Apple release credentials, run:'
echo ' ./scripts/atlas/ensure-local-signing-identity.sh'
fi
fi
exit $status

View File

@@ -0,0 +1,69 @@
#!/bin/bash
set -euo pipefail
CACHE_ROOT="$HOME/Library/Caches/AtlasExecutionFixturesCache"
LOG_ROOT="$HOME/Library/Logs/AtlasExecutionFixturesLogs"
DERIVED_ROOT="$HOME/Library/Developer/Xcode/DerivedData/AtlasExecutionFixturesDerivedData"
PYCACHE_ROOT="$HOME/Library/Caches/AtlasExecutionFixturesPycache"
create_blob() {
local path="$1"
local size_mb="$2"
mkdir -p "$(dirname "$path")"
if command -v mkfile >/dev/null 2>&1; then
mkfile -n "${size_mb}m" "$path"
else
dd if=/dev/zero of="$path" bs=1m count="$size_mb" status=none
fi
}
print_status() {
local existing=false
for path in "$CACHE_ROOT" "$LOG_ROOT" "$DERIVED_ROOT" "$PYCACHE_ROOT"; do
if [[ -e "$path" ]]; then
existing=true
du -sh "$path"
find "$path" -maxdepth 3 -type f | sort
fi
done
if [[ "$existing" == false ]]; then
echo "No Smart Clean manual fixtures found."
fi
}
create_fixtures() {
cleanup_fixtures >/dev/null 2>&1 || true
create_blob "$CACHE_ROOT/cache-a.bin" 24
create_blob "$CACHE_ROOT/cache-b.bin" 12
create_blob "$LOG_ROOT/app.log" 8
create_blob "$DERIVED_ROOT/Build/Logs/build-products.bin" 16
mkdir -p "$PYCACHE_ROOT/project/__pycache__"
create_blob "$PYCACHE_ROOT/project/__pycache__/sample.cpython-312.pyc" 4
echo "Created Smart Clean manual fixtures:"
print_status
echo ""
echo "Note: bin/clean.sh --dry-run may aggregate these fixtures into higher-level roots such as ~/Library/Caches, ~/Library/Logs, or ~/Library/Developer/Xcode/DerivedData."
}
cleanup_fixtures() {
rm -rf "$CACHE_ROOT" "$LOG_ROOT" "$DERIVED_ROOT" "$PYCACHE_ROOT"
echo "Removed Smart Clean manual fixtures."
}
case "${1:-create}" in
create)
create_fixtures
;;
status)
print_status
;;
cleanup)
cleanup_fixtures
;;
*)
echo "Usage: $0 [create|status|cleanup]" >&2
exit 1
;;
esac

View File

@@ -0,0 +1,25 @@
#!/bin/bash
set -euo pipefail
trusted=$(swift -e 'import ApplicationServices; print(AXIsProcessTrusted())' 2>/dev/null || echo false)
echo "Atlas UI automation preflight"
echo "============================"
echo "Accessibility trusted for current process: $trusted"
if [[ "$trusted" != "true" ]]; then
cat <<'MSG'
✗ UI automation is currently blocked by macOS Accessibility / automation permissions.
To unblock local XCUITest on this machine:
1. Open System Settings
2. Privacy & Security -> Accessibility
3. Allow the terminal app you use to run `xcodebuild` (Terminal / iTerm / Warp / etc.)
4. Also allow Xcode if you run tests from Xcode directly
5. Re-run the minimal repro:
xcodebuild test -project Testing/XCUITestRepro/XCUITestRepro.xcodeproj -scheme XCUITestRepro -destination 'platform=macOS'
MSG
exit 1
fi
echo "✓ Current process is trusted for Accessibility APIs"

View File

@@ -0,0 +1,35 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
APP_PATH="${APP_PATH:-$HOME/Applications/Atlas for Mac.app}"
BIN_PATH="$APP_PATH/Contents/MacOS/Atlas for Mac"
STATE_DIR="${STATE_DIR:-$ROOT_DIR/.build/atlas-launch-state}"
if [[ ! -x "$BIN_PATH" ]]; then
echo "App binary not found: $BIN_PATH" >&2
exit 1
fi
mkdir -p "$STATE_DIR"
ATLAS_STATE_DIR="$STATE_DIR" "$BIN_PATH" >/tmp/atlas-launch.log 2>&1 &
pid=$!
cleanup() {
if kill -0 "$pid" >/dev/null 2>&1; then
kill "$pid" >/dev/null 2>&1 || true
wait "$pid" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
sleep 3
if ! kill -0 "$pid" >/dev/null 2>&1; then
echo "Atlas app exited immediately; see /tmp/atlas-launch.log" >&2
cat /tmp/atlas-launch.log >&2 || true
exit 1
fi
echo "App launch smoke test succeeded"
echo "PID: $pid"

View File

@@ -0,0 +1,56 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
APP_PATH="${APP_PATH:-$ROOT_DIR/dist/native/Atlas for Mac.app}"
HELPER_PATH="$APP_PATH/Contents/Helpers/AtlasPrivilegedHelper"
XPC_PATH="$APP_PATH/Contents/XPCServices/AtlasWorkerXPC.xpc"
PLIST_PATH="$APP_PATH/Contents/Info.plist"
XPC_PLIST_PATH="$XPC_PATH/Contents/Info.plist"
if [[ ! -d "$APP_PATH" ]]; then
echo "App bundle not found: $APP_PATH" >&2
exit 1
fi
if [[ ! -x "$HELPER_PATH" ]]; then
echo "Helper not found or not executable: $HELPER_PATH" >&2
exit 1
fi
if [[ ! -d "$XPC_PATH" ]]; then
echo "Embedded XPC service missing: $XPC_PATH" >&2
exit 1
fi
if [[ ! -f "$PLIST_PATH" ]]; then
echo "Missing Info.plist: $PLIST_PATH" >&2
exit 1
fi
if [[ ! -f "$XPC_PLIST_PATH" ]]; then
echo "Missing XPC Info.plist: $XPC_PLIST_PATH" >&2
exit 1
fi
if ! /usr/bin/codesign --verify --deep --strict "$APP_PATH" >/dev/null 2>&1; then
echo "App bundle failed codesign verification: $APP_PATH" >&2
exit 1
fi
bundle_id=$(/usr/bin/defaults read "$PLIST_PATH" CFBundleIdentifier 2>/dev/null || true)
display_name=$(/usr/bin/defaults read "$PLIST_PATH" CFBundleDisplayName 2>/dev/null || true)
xpc_bundle_id=$(/usr/bin/defaults read "$XPC_PLIST_PATH" CFBundleIdentifier 2>/dev/null || true)
if [[ "$bundle_id" != "com.atlasformac.app" ]]; then
echo "Unexpected bundle identifier: ${bundle_id:-<empty>}" >&2
exit 1
fi
if [[ "$display_name" != "Atlas for Mac" ]]; then
echo "Unexpected display name: ${display_name:-<empty>}" >&2
exit 1
fi
if [[ "$xpc_bundle_id" != "com.atlasformac.app.worker" ]]; then
echo "Unexpected XPC bundle identifier: ${xpc_bundle_id:-<empty>}" >&2
exit 1
fi
echo "Bundle verification succeeded"
echo "App: $APP_PATH"
echo "Helper: $HELPER_PATH"
echo "XPC: $XPC_PATH"

View File

@@ -0,0 +1,69 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
DMG_PATH="${DMG_PATH:-$ROOT_DIR/dist/native/Atlas-for-Mac.dmg}"
MOUNT_POINT="${MOUNT_POINT:-$ROOT_DIR/.build/atlas-dmg-verify/mount}"
INSTALL_ROOT="${INSTALL_ROOT:-$HOME}"
APP_NAME="Atlas for Mac.app"
SOURCE_APP_PATH="$MOUNT_POINT/$APP_NAME"
INSTALLED_APP_PATH="$INSTALL_ROOT/Applications/$APP_NAME"
INFO_PLIST="$INSTALLED_APP_PATH/Contents/Info.plist"
KEEP_INSTALLED_APP="${KEEP_INSTALLED_APP:-0}"
cleanup() {
if mount | grep -q "on $MOUNT_POINT "; then
hdiutil detach "$MOUNT_POINT" -quiet || true
fi
if [[ "$KEEP_INSTALLED_APP" != "1" && -d "$INSTALLED_APP_PATH" ]]; then
python3 - "$INSTALLED_APP_PATH" <<'PY'
from pathlib import Path
import shutil, sys
app = Path(sys.argv[1])
if app.exists():
shutil.rmtree(app)
PY
fi
}
trap cleanup EXIT
if [[ ! -f "$DMG_PATH" ]]; then
echo "DMG not found: $DMG_PATH" >&2
exit 1
fi
python3 - "$MOUNT_POINT" <<'PY'
from pathlib import Path
import shutil, sys
mount_path = Path(sys.argv[1])
if mount_path.exists():
shutil.rmtree(mount_path)
mount_path.mkdir(parents=True, exist_ok=True)
PY
mkdir -p "$INSTALL_ROOT/Applications"
hdiutil attach "$DMG_PATH" -mountpoint "$MOUNT_POINT" -nobrowse -quiet
if [[ ! -d "$SOURCE_APP_PATH" ]]; then
echo "Mounted app not found at $SOURCE_APP_PATH" >&2
exit 1
fi
python3 - "$SOURCE_APP_PATH" "$INSTALLED_APP_PATH" <<'PY'
from pathlib import Path
import shutil, sys
src = Path(sys.argv[1])
dst = Path(sys.argv[2])
if dst.exists():
shutil.rmtree(dst)
shutil.copytree(src, dst, symlinks=True)
PY
APP_DISPLAY_NAME=$(/usr/bin/defaults read "$INFO_PLIST" CFBundleDisplayName 2>/dev/null || echo "")
if [[ "$APP_DISPLAY_NAME" != "Atlas for Mac" ]]; then
echo "Unexpected installed app display name: ${APP_DISPLAY_NAME:-<empty>}" >&2
exit 1
fi
echo "DMG install validation succeeded"
echo "Installed app path: $INSTALLED_APP_PATH"

View File

@@ -0,0 +1,44 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
PKG_PATH="${PKG_PATH:-$ROOT_DIR/dist/native/Atlas-for-Mac.pkg}"
INSTALL_ROOT="${INSTALL_ROOT:-$HOME}"
APP_PATH="$INSTALL_ROOT/Applications/Atlas for Mac.app"
INFO_PLIST="$APP_PATH/Contents/Info.plist"
KEEP_INSTALLED_APP="${KEEP_INSTALLED_APP:-0}"
cleanup() {
if [[ "$KEEP_INSTALLED_APP" != "1" && -d "$APP_PATH" ]]; then
python3 - <<'PY'
from pathlib import Path
import shutil, os
app = Path(os.environ['APP_PATH'])
if app.exists():
shutil.rmtree(app)
PY
fi
}
trap cleanup EXIT
if [[ ! -f "$PKG_PATH" ]]; then
echo "Installer package not found: $PKG_PATH" >&2
exit 1
fi
mkdir -p "$INSTALL_ROOT/Applications"
installer -allowUntrusted -pkg "$PKG_PATH" -target CurrentUserHomeDirectory >/dev/null
if [[ ! -d "$APP_PATH" ]]; then
echo "Installed app not found at $APP_PATH" >&2
exit 1
fi
APP_DISPLAY_NAME=$(/usr/bin/defaults read "$INFO_PLIST" CFBundleDisplayName 2>/dev/null || echo "")
if [[ "$APP_DISPLAY_NAME" != "Atlas for Mac" ]]; then
echo "Unexpected installed app display name: ${APP_DISPLAY_NAME:-<empty>}" >&2
exit 1
fi
echo "Installer validation succeeded"
echo "Installed app path: $APP_PATH"