@hasna/recordings 0.2.14 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile.package +4 -5
- package/README.md +113 -8
- package/bun.lock +2 -2
- package/dist/__tests__/helpers/installer-guard-execution.d.ts +22 -0
- package/dist/__tests__/helpers/installer-guard-execution.d.ts.map +1 -0
- package/dist/__tests__/helpers/installer-preflight.d.ts +22 -0
- package/dist/__tests__/helpers/installer-preflight.d.ts.map +1 -0
- package/dist/__tests__/helpers/native-fs-guard.d.ts.map +1 -1
- package/dist/__tests__/helpers/source-assertions.d.ts +169 -0
- package/dist/__tests__/helpers/source-assertions.d.ts.map +1 -0
- package/dist/__tests__/preload.d.ts +1 -4
- package/dist/__tests__/preload.d.ts.map +1 -1
- package/dist/cli/desktop-snapshot.d.ts +20 -0
- package/dist/cli/desktop-snapshot.d.ts.map +1 -0
- package/dist/cli/index.js +2094 -280
- package/dist/cli/macos-permissions.d.ts +72 -0
- package/dist/cli/macos-permissions.d.ts.map +1 -1
- package/dist/cli/macos-shortcut.d.ts +139 -0
- package/dist/cli/macos-shortcut.d.ts.map +1 -0
- package/dist/cli/trigger-probe.d.ts +172 -0
- package/dist/cli/trigger-probe.d.ts.map +1 -0
- package/dist/db/database.d.ts +9 -0
- package/dist/db/database.d.ts.map +1 -1
- package/dist/http/client.d.ts +19 -7
- package/dist/http/client.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +635 -50
- package/dist/lib/capture-probe.d.ts +216 -0
- package/dist/lib/capture-probe.d.ts.map +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/macos-bundle.d.ts +50 -0
- package/dist/lib/macos-bundle.d.ts.map +1 -0
- package/dist/lib/persistence-probe.d.ts +208 -0
- package/dist/lib/persistence-probe.d.ts.map +1 -0
- package/dist/lib/recorder.d.ts.map +1 -1
- package/dist/lib/retired-deployment-modes.d.ts +24 -0
- package/dist/lib/retired-deployment-modes.d.ts.map +1 -0
- package/dist/lib/transcriber.d.ts +60 -0
- package/dist/lib/transcriber.d.ts.map +1 -1
- package/dist/mcp/index.js +141 -57
- package/dist/server/cloud-config.d.ts +25 -3
- package/dist/server/cloud-config.d.ts.map +1 -1
- package/dist/server/cloud-readiness.d.ts.map +1 -1
- package/dist/server/cloud.d.ts +8 -7
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.js +188 -80
- package/dist/server/migrate-command.d.ts.map +1 -1
- package/dist/server/serve.d.ts.map +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +109 -50
- package/dist/store.d.ts +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/package.json +25 -6
- package/scripts/ci-linux-suite.ts +403 -0
- package/scripts/ci-native-build.ts +402 -0
- package/scripts/enforce_identity_migration.sh +110 -0
- package/scripts/generate-sdk.ts +1 -1
- package/scripts/install_macos_app.sh +192 -31
- package/scripts/macos_artifact.ts +323 -43
- package/scripts/native/realtime-settle-probe/README.md +39 -0
- package/scripts/native/realtime-settle-probe/main.swift +135 -0
- package/scripts/policy/local-only-approved-targets.txt +21 -0
- package/scripts/read_local_only_targets.sh +203 -0
- package/scripts/scan-artifact.ts +40 -0
- package/scripts/set-version.ts +145 -0
- package/scripts/smoke_macos_app.sh +62 -16
- package/scripts/vacuity-manifest-gen.ts +96 -0
- package/scripts/vacuity-manifests/enhancement-screen-mirror.tsv +44 -0
- package/scripts/vacuity-manifests/install-chain.tsv +13 -0
- package/scripts/vacuity-manifests/must-survive-controls.tsv +10 -0
- package/scripts/vacuity-manifests/reorder.tsv +4 -0
- package/scripts/vacuity-manifests/source-side.tsv +15 -0
- package/scripts/vacuity-manifests/variable-operands.tsv +16 -0
- package/scripts/vacuity-manifests/version-sites.tsv +61 -0
- package/scripts/vacuity-mutation-battery.ts +266 -0
- package/src/native/Recordings/App/MenuBarStatusView.swift +23 -11
- package/src/native/Recordings/App/RecordingsApp.swift +37 -1
- package/src/native/Recordings/App/RuntimeSmoke.swift +5 -1
- package/src/native/Recordings/App/SidebarView.swift +1 -1
- package/src/native/Recordings/Package.swift +24 -5
- package/src/native/Recordings/RecordingsLib/EnhancementScreen.swift +91 -0
- package/src/native/Recordings/RecordingsLib/FnKeyMonitor.swift +27 -4
- package/src/native/Recordings/RecordingsLib/Info.plist +2 -2
- package/src/native/Recordings/RecordingsLib/MenuBarPresentation.swift +56 -3
- package/src/native/Recordings/RecordingsLib/NativePCMRecorder.swift +13 -0
- package/src/native/Recordings/RecordingsLib/PasteDeliveryVerification.swift +460 -0
- package/src/native/Recordings/RecordingsLib/PermissionRequestLaunchPlan.swift +21 -1
- package/src/native/Recordings/RecordingsLib/RealtimeTranscriptionClient.swift +41 -7
- package/src/native/Recordings/RecordingsLib/RecordingAttemptAlert.swift +36 -0
- package/src/native/Recordings/RecordingsLib/RecordingEngine.swift +1071 -75
- package/src/native/Recordings/RecordingsLib/SettingsView.swift +47 -3
- package/src/native/Recordings/RecordingsLib/VoiceShortcuts.swift +11 -6
- package/src/native/Recordings/RecordingsTests/BarOnlyLaunchPlanTests.swift +99 -0
- package/src/native/Recordings/RecordingsTests/CLIRunnerTests.swift +3 -3
- package/src/native/Recordings/RecordingsTests/EnhancementScreenTests.swift +191 -0
- package/src/native/Recordings/RecordingsTests/MenuBarPresentationTests.swift +144 -4
- package/src/native/Recordings/RecordingsTests/PasteDeliveryVerificationTests.swift +463 -0
- package/src/native/Recordings/RecordingsTests/PasteTargetTests.swift +33 -20
- package/src/native/Recordings/RecordingsTests/ProjectStoreTests.swift +1 -1
- package/src/native/Recordings/RecordingsTests/RealtimeSettleBenchmark.swift +200 -0
- package/src/native/Recordings/RecordingsTests/RealtimeSettleBudgetTests.swift +80 -0
- package/src/native/Recordings/RecordingsTests/RealtimeTranscriptionTests.swift +22 -4
- package/src/native/Recordings/RecordingsTests/RecordingEngineDeliveryTests.swift +12 -6
- package/src/native/Recordings/RecordingsTests/RecordingEngineHomeIsolationTests.swift +67 -0
- package/src/native/Recordings/RecordingsTests/RecordingStartGateTests.swift +12 -3
- package/src/native/Recordings/RecordingsTests/RecordingStartTimingTests.swift +207 -11
- package/src/native/Recordings/RecordingsTests/SpeechIntentTests.swift +17 -6
- package/src/native/Recordings/RecordingsTests/TestHomeDirectory.swift +23 -0
- package/src/native/Recordings/Updater/Broker/ApplicationProcessQuiescence.swift +7 -1
- package/src/native/Recordings/Updater/Broker/AtomicActivation.swift +10 -10
- package/src/native/Recordings/Updater/Broker/BrokerMain.swift +5 -1
- package/src/native/Recordings/Updater/Broker/HostOSProductVersion.swift +1 -0
- package/src/native/Recordings/Updater/Broker/PeerIdentity.swift +59 -3
- package/src/native/Recordings/Updater/Protocol/UpdateProtocol.swift +21 -2
- package/src/native/Recordings/Updater/ProtocolTests/ExpectationIntegrityTests.swift +60 -0
- package/src/native/Recordings/Updater/ProtocolTests/UpdateXPCInterfaceTests.swift +113 -0
- package/src/native/Recordings/Updater/VerifierLauncher/RecordingsVerifierLauncher.c +106 -5
- package/src/native/Recordings/build.sh +226 -20
- package/scripts/native/prebuilds/darwin-universal/recordings_fs_guard.node +0 -0
|
@@ -83,7 +83,7 @@ fi
|
|
|
83
83
|
readonly RELEASE_SUBTYPE
|
|
84
84
|
RELEASE_ARCHITECTURES=(arm64 x86_64)
|
|
85
85
|
|
|
86
|
-
CODESIGN_IDENTITY="${RECORDINGS_CODESIGN_IDENTITY:-}"
|
|
86
|
+
CODESIGN_IDENTITY="${RECORDINGS_CODESIGN_IDENTITY:-${HASNA_CODESIGN_IDENTITY:-}}"
|
|
87
87
|
EXPECTED_TEAM_ID="${RECORDINGS_EXPECTED_TEAM_IDENTIFIER:-}"
|
|
88
88
|
NOTARY_PROFILE="${RECORDINGS_NOTARY_KEYCHAIN_PROFILE:-}"
|
|
89
89
|
INSTALLER_IDENTITY="${RECORDINGS_INSTALLER_CODESIGN_IDENTITY:-}"
|
|
@@ -96,6 +96,41 @@ COMPATIBLE_COHORT_MANIFEST="${RECORDINGS_RELEASE_COMPATIBLE_COHORT_MANIFEST:-}"
|
|
|
96
96
|
LOCAL_APPROVED_TARGET="${RECORDINGS_LOCAL_APPROVED_TARGET:-}"
|
|
97
97
|
LOCAL_APPROVED_TARGET_IDENTITY_KIND="${RECORDINGS_LOCAL_APPROVED_TARGET_IDENTITY_KIND:-}"
|
|
98
98
|
LOCAL_APPROVED_TARGET_IDENTITY_SHA256="${RECORDINGS_LOCAL_APPROVED_TARGET_IDENTITY_SHA256:-}"
|
|
99
|
+
VARIANT="${RECORDINGS_VARIANT:-full}"
|
|
100
|
+
case "$VARIANT" in
|
|
101
|
+
full|bar) ;;
|
|
102
|
+
*)
|
|
103
|
+
echo "RECORDINGS_VARIANT must be full or bar; got: $VARIANT" >&2
|
|
104
|
+
exit 2
|
|
105
|
+
;;
|
|
106
|
+
esac
|
|
107
|
+
if [ "$MODE" = "release" ] && [ "$VARIANT" = "bar" ]; then
|
|
108
|
+
# The bar variant is a deliberate product change (no workspace window, accessory
|
|
109
|
+
# launch); a release that carries it must be explicitly marked so a default release
|
|
110
|
+
# can never silently emit a bar artifact.
|
|
111
|
+
if [ "${RECORDINGS_RELEASE_BAR_VARIANT_MARKED:-0}" != "1" ]; then
|
|
112
|
+
echo "release-mode bar-variant builds require RECORDINGS_RELEASE_BAR_VARIANT_MARKED=1 to proceed explicitly." >&2
|
|
113
|
+
exit 2
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
readonly VARIANT
|
|
117
|
+
VARIANT_SWIFT_FLAGS=()
|
|
118
|
+
if [ "$VARIANT" = "bar" ]; then
|
|
119
|
+
VARIANT_SWIFT_FLAGS=(-Xswiftc -DRECORDINGS_BAR_ONLY)
|
|
120
|
+
fi
|
|
121
|
+
# Fleet naming rule (knowledge k_msxd5rz3_jfvl3i): every Hasna macOS app is
|
|
122
|
+
# Hasna<Name>.app with 'Hasna' at the beginning. The full app keeps its historical
|
|
123
|
+
# Recordings.app name (its rename is the rule's recorded follow-up decision); the
|
|
124
|
+
# bar-only artifact is named per the rule NOW — HasnaRecordings.app. The 'bar' is the
|
|
125
|
+
# variant, never a separate app name: bundle identifier stays com.hasna.recordings so
|
|
126
|
+
# TCC keeps keying on bundle id + signing identity, and the executable inside the
|
|
127
|
+
# bundle stays "Recordings".
|
|
128
|
+
APP_BUNDLE_NAME="Recordings.app"
|
|
129
|
+
if [ "$VARIANT" = "bar" ]; then
|
|
130
|
+
APP_BUNDLE_NAME="HasnaRecordings.app"
|
|
131
|
+
fi
|
|
132
|
+
readonly APP_BUNDLE_NAME
|
|
133
|
+
APP_BASENAME="${APP_BUNDLE_NAME%.app}"
|
|
99
134
|
PLIST_BUDDY="$(select_executable "/usr/libexec/PlistBuddy" "${RECORDINGS_TEST_PLIST_BUDDY_EXECUTABLE:-${PLIST_BUDDY:-}}")"
|
|
100
135
|
PLUTIL="$(select_executable "/usr/bin/plutil" "${RECORDINGS_TEST_PLUTIL_EXECUTABLE:-${PLUTIL:-}}")"
|
|
101
136
|
BUN_EXECUTABLE="${BUN_EXECUTABLE:-}"
|
|
@@ -134,6 +169,48 @@ LIPO_EXECUTABLE="$(select_executable "/usr/bin/lipo" "${RECORDINGS_TEST_LIPO_EXE
|
|
|
134
169
|
STAT_EXECUTABLE="$(select_executable "/usr/bin/stat" "${RECORDINGS_TEST_STAT_EXECUTABLE:-}")"
|
|
135
170
|
TEST_GIT_EXECUTABLE="$(select_executable "" "${RECORDINGS_TEST_GIT_EXECUTABLE:-}")"
|
|
136
171
|
TEST_SWIFT_EXECUTABLE="$(select_executable "" "${RECORDINGS_TEST_SWIFT_EXECUTABLE:-}")"
|
|
172
|
+
SECURITY_EXECUTABLE="$(select_executable "/usr/bin/security" "${RECORDINGS_TEST_SECURITY_EXECUTABLE:-}")"
|
|
173
|
+
|
|
174
|
+
# Developer ID signing identity support. The identity comes from RECORDINGS_CODESIGN_IDENTITY
|
|
175
|
+
# (legacy) or HASNA_CODESIGN_IDENTITY (canonical name), and when neither is supplied the
|
|
176
|
+
# keychain is consulted with `security find-identity -v -p codesigning` and the first
|
|
177
|
+
# "Developer ID Application:" identity is used. Signing NEVER silently falls back to ad-hoc
|
|
178
|
+
# when a Developer ID was requested: release builds always require one, and a local build
|
|
179
|
+
# with RECORDINGS_SIGNING_REQUIRED=1 fails loudly when none exists.
|
|
180
|
+
discover_developer_id_identity() {
|
|
181
|
+
local listing
|
|
182
|
+
listing="$("$SECURITY_EXECUTABLE" find-identity -v -p codesigning 2>/dev/null)" || return 0
|
|
183
|
+
printf '%s\n' "$listing" | "$AWK_EXECUTABLE" -F'"' '/Developer ID Application:/ { print $2; exit }'
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
derive_team_id() {
|
|
187
|
+
local identity="$1"
|
|
188
|
+
local team_id
|
|
189
|
+
team_id="$(printf '%s\n' "$identity" | "$SED_EXECUTABLE" -n 's/.*(\([A-Z0-9]\{10\}\))$/\1/p')"
|
|
190
|
+
if ! [[ "$team_id" =~ ^[A-Z0-9]{10}$ ]]; then
|
|
191
|
+
echo "Could not derive a 10-character Developer ID team from the signing identity: $identity" >&2
|
|
192
|
+
return 1
|
|
193
|
+
fi
|
|
194
|
+
printf '%s\n' "$team_id"
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
resolve_signing_identity() {
|
|
198
|
+
# Called when no explicit identity was supplied. Fails loudly when a Developer ID
|
|
199
|
+
# was requested but none can be found; the caller decides whether one was requested.
|
|
200
|
+
if [ "$HOST_PLATFORM" != "Darwin" ]; then
|
|
201
|
+
return 0
|
|
202
|
+
fi
|
|
203
|
+
local discovered
|
|
204
|
+
discovered="$(discover_developer_id_identity)"
|
|
205
|
+
if [ -z "$discovered" ]; then
|
|
206
|
+
echo "Developer ID signing was requested but no Developer ID Application identity found in the keychain; never silently ad-hoc when a Developer ID is requested." >&2
|
|
207
|
+
return 1
|
|
208
|
+
fi
|
|
209
|
+
CODESIGN_IDENTITY="$discovered"
|
|
210
|
+
if [ -z "$EXPECTED_TEAM_ID" ]; then
|
|
211
|
+
EXPECTED_TEAM_ID="$(derive_team_id "$CODESIGN_IDENTITY")" || return 1
|
|
212
|
+
fi
|
|
213
|
+
}
|
|
137
214
|
|
|
138
215
|
require_executable() {
|
|
139
216
|
local label="$1"
|
|
@@ -253,6 +330,7 @@ require_executable "ID_EXECUTABLE" "$ID_EXECUTABLE"
|
|
|
253
330
|
require_executable "STAT_EXECUTABLE" "$STAT_EXECUTABLE"
|
|
254
331
|
if [ "$HOST_PLATFORM" = "Darwin" ]; then
|
|
255
332
|
require_executable "LIPO_EXECUTABLE" "$LIPO_EXECUTABLE"
|
|
333
|
+
require_executable "SECURITY_EXECUTABLE" "$SECURITY_EXECUTABLE"
|
|
256
334
|
fi
|
|
257
335
|
require_bun_executable "$BUN_EXECUTABLE"
|
|
258
336
|
if [ "$MODE" = "release" ]; then
|
|
@@ -380,6 +458,8 @@ if [ "$SOURCE_PACKAGE_ROOT" != "$PACKAGE_ROOT" ]; then
|
|
|
380
458
|
"$SOURCE_PACKAGE_ROOT/scripts/native_fs_guard.ts" \
|
|
381
459
|
"$SOURCE_PACKAGE_ROOT/scripts/build_native_fs_guard.sh" \
|
|
382
460
|
"$SOURCE_PACKAGE_ROOT/scripts/native/recordings_fs_guard.c" \
|
|
461
|
+
"$SOURCE_PACKAGE_ROOT/scripts/policy/local-only-approved-targets.txt" \
|
|
462
|
+
"$SOURCE_PACKAGE_ROOT/scripts/read_local_only_targets.sh" \
|
|
383
463
|
"$SOURCE_PACKAGE_ROOT/packaging/macos/build_release_pkg.sh" \
|
|
384
464
|
"$SOURCE_PACKAGE_ROOT/packaging/macos/release_lifecycle.ts" \
|
|
385
465
|
"$SOURCE_PACKAGE_ROOT/packaging/macos/Verifier.entitlements" \
|
|
@@ -543,11 +623,23 @@ run_codesign() {
|
|
|
543
623
|
}
|
|
544
624
|
|
|
545
625
|
run_swift() {
|
|
626
|
+
# VARIANT_SWIFT_FLAGS is empty for every full build (the default). A bare
|
|
627
|
+
# "${arr[@]}" on an EMPTY array under `set -u` aborts bash < 4.4 — macOS
|
|
628
|
+
# /bin/bash is 3.2.57 — with `unbound variable`, which killed every build the
|
|
629
|
+
# moment the flags existed. The ${arr[0]+"${arr[@]}"} guard is the script-wide
|
|
630
|
+
# idiom (see run_bun, run_xcrun, run_release_sensitive_tool); do not reintroduce
|
|
631
|
+
# a bare expansion here.
|
|
632
|
+
#
|
|
633
|
+
# The flags are arguments TO swift (after the executable), never before it:
|
|
634
|
+
# placed before the executable they would be consumed by /usr/bin/env as its
|
|
635
|
+
# own options and the build would die with `env: '-Xswiftc': No such file`.
|
|
546
636
|
"$ENV_EXECUTABLE" -i \
|
|
547
637
|
HOME="$BUILD_HOME" \
|
|
548
638
|
PATH="$SANITIZED_PATH" \
|
|
549
639
|
TMPDIR="$BUILD_WORK_DIR" \
|
|
550
|
-
"$SWIFT_EXECUTABLE"
|
|
640
|
+
"$SWIFT_EXECUTABLE" \
|
|
641
|
+
${VARIANT_SWIFT_FLAGS[0]+"${VARIANT_SWIFT_FLAGS[@]}"} \
|
|
642
|
+
"$@"
|
|
551
643
|
}
|
|
552
644
|
|
|
553
645
|
run_lipo() {
|
|
@@ -937,8 +1029,19 @@ BUILDER_IDENTITY_KIND="none"
|
|
|
937
1029
|
BUILDER_IDENTITY_SHA256="none"
|
|
938
1030
|
if [ "$MODE" = "release" ]; then
|
|
939
1031
|
if [ -z "$CODESIGN_IDENTITY" ] || [ "$CODESIGN_IDENTITY" = "-" ]; then
|
|
940
|
-
|
|
941
|
-
|
|
1032
|
+
# No explicit identity: discover the Developer ID Application identity from the
|
|
1033
|
+
# keychain. Release signing is never optional, so "requested but not found" fails
|
|
1034
|
+
# loudly instead of degrading to an ad-hoc signature.
|
|
1035
|
+
if [ "$HOST_PLATFORM" = "Darwin" ]; then
|
|
1036
|
+
resolve_signing_identity || {
|
|
1037
|
+
echo "Release builds require a Developer ID Application identity in RECORDINGS_CODESIGN_IDENTITY or HASNA_CODESIGN_IDENTITY." >&2
|
|
1038
|
+
exit 1
|
|
1039
|
+
}
|
|
1040
|
+
fi
|
|
1041
|
+
if [ -z "$CODESIGN_IDENTITY" ] || [ "$CODESIGN_IDENTITY" = "-" ]; then
|
|
1042
|
+
echo "Release builds require RECORDINGS_CODESIGN_IDENTITY or HASNA_CODESIGN_IDENTITY for a Developer ID Application identity." >&2
|
|
1043
|
+
exit 1
|
|
1044
|
+
fi
|
|
942
1045
|
fi
|
|
943
1046
|
if [ -z "$EXPECTED_TEAM_ID" ]; then
|
|
944
1047
|
echo "Release builds require RECORDINGS_EXPECTED_TEAM_IDENTIFIER to pin the Developer ID team." >&2
|
|
@@ -991,8 +1094,34 @@ if [ "$MODE" = "release" ]; then
|
|
|
991
1094
|
fi
|
|
992
1095
|
fi
|
|
993
1096
|
elif [ "$MODE" = "local" ]; then
|
|
994
|
-
|
|
995
|
-
|
|
1097
|
+
# Same policy file and same sourced reader the installer uses. The artifact tool
|
|
1098
|
+
# re-implements the same rules in TypeScript and re-checks the target later, so
|
|
1099
|
+
# agreement between the two implementations rests on their shared contract test,
|
|
1100
|
+
# not on shared code.
|
|
1101
|
+
#
|
|
1102
|
+
# Both resolve from $SOURCE_PACKAGE_ROOT — the `git archive` of $SOURCE_SHA — and not
|
|
1103
|
+
# from $PACKAGE_ROOT. They used to read $PACKAGE_ROOT, which is the mutable working
|
|
1104
|
+
# tree, so this gate validated a different file from the one the artifact was built
|
|
1105
|
+
# from: with the archived policy listing only station06, a working-tree policy listing
|
|
1106
|
+
# "attacker" got "attacker" approved, and station06 refused. Every other build input
|
|
1107
|
+
# is resolved from the snapshot for exactly this reason (see the required-snapshot-input
|
|
1108
|
+
# loop above, which already demands both of these paths inside the archive), and a gate
|
|
1109
|
+
# that checks a file the artifact does not contain is not a gate.
|
|
1110
|
+
LOCAL_TARGET_POLICY="${SOURCE_PACKAGE_ROOT}/scripts/policy/local-only-approved-targets.txt"
|
|
1111
|
+
LOCAL_TARGET_READER="${SOURCE_PACKAGE_ROOT}/scripts/read_local_only_targets.sh"
|
|
1112
|
+
[ -f "$LOCAL_TARGET_READER" ] && [ ! -L "$LOCAL_TARGET_READER" ] || {
|
|
1113
|
+
echo "Packaged local-only approved target reader is missing." >&2
|
|
1114
|
+
exit 1
|
|
1115
|
+
}
|
|
1116
|
+
# shellcheck source=/dev/null
|
|
1117
|
+
. "$LOCAL_TARGET_READER"
|
|
1118
|
+
LOCAL_APPROVED_TARGET_MATCHED=0
|
|
1119
|
+
LOCAL_APPROVED_TARGET_LIST=""
|
|
1120
|
+
read_local_only_targets \
|
|
1121
|
+
"$LOCAL_TARGET_POLICY" LOCAL_APPROVED_TARGET_LIST LOCAL_APPROVED_TARGET_MATCHED \
|
|
1122
|
+
"$LOCAL_APPROVED_TARGET" || exit 1
|
|
1123
|
+
if [ "$LOCAL_APPROVED_TARGET_MATCHED" -ne 1 ]; then
|
|
1124
|
+
echo "Local-only builds require an approved RECORDINGS_LOCAL_APPROVED_TARGET (${LOCAL_APPROVED_TARGET_LIST})." >&2
|
|
996
1125
|
exit 1
|
|
997
1126
|
fi
|
|
998
1127
|
if ! [[ "$LOCAL_APPROVED_TARGET_IDENTITY_SHA256" =~ ^[a-f0-9]{64}$ ]]; then
|
|
@@ -1031,13 +1160,75 @@ elif [ "$MODE" = "local" ]; then
|
|
|
1031
1160
|
echo "Local-only artifacts must be built on a different authenticated Tailscale node." >&2
|
|
1032
1161
|
exit 1
|
|
1033
1162
|
fi
|
|
1034
|
-
|
|
1035
|
-
|
|
1163
|
+
# Signing identity for a local-station artifact.
|
|
1164
|
+
#
|
|
1165
|
+
# This used to be an unconditional `CODESIGN_IDENTITY="-"`, and that was the defect
|
|
1166
|
+
# behind "the Fn key does nothing". Hold-to-talk is a CGEventTap (RecordingsLib/
|
|
1167
|
+
# FnKeyMonitor.swift), macOS only creates that tap for a process with Accessibility,
|
|
1168
|
+
# and TCC keys every grant to bundle identifier PLUS code-signing identity. An ad-hoc
|
|
1169
|
+
# signature has no identity to key on beyond a CDHash that changes on every rebuild,
|
|
1170
|
+
# so each reinstall orphaned the grant, AXIsProcessTrusted() stayed false and the app
|
|
1171
|
+
# logged "fn monitor start ok=false" forever. Ad-hoc is therefore not a neutral default
|
|
1172
|
+
# here — it structurally prevents the permission the feature needs from ever sticking.
|
|
1173
|
+
#
|
|
1174
|
+
# So when a Developer ID Application identity is supplied, sign with it and pin its
|
|
1175
|
+
# team. That is the same stable identity a release uses; what still separates this from
|
|
1176
|
+
# a release is notarization, the single-target binding, and the builder attestation
|
|
1177
|
+
# above, none of which are relaxed. With no identity supplied the old ad-hoc behaviour
|
|
1178
|
+
# is kept verbatim, because a Mac without the signing key must still be able to build.
|
|
1179
|
+
if [ -z "$CODESIGN_IDENTITY" ] || [ "$CODESIGN_IDENTITY" = "-" ]; then
|
|
1180
|
+
if [ "${RECORDINGS_SIGNING_REQUIRED:-0}" = "1" ]; then
|
|
1181
|
+
# A Developer ID was explicitly requested for this local build: discover it
|
|
1182
|
+
# from the keychain and fail loudly when none exists.
|
|
1183
|
+
resolve_signing_identity || exit 1
|
|
1184
|
+
elif [ "$HOST_PLATFORM" = "Darwin" ]; then
|
|
1185
|
+
# The DEFAULT route is the keychain: `security find-identity` and use the
|
|
1186
|
+
# Developer ID Application identity when one exists. That is the stable
|
|
1187
|
+
# signing identity TCC grants key on — an ad-hoc signature has no identity
|
|
1188
|
+
# to key on beyond a CDHash that changes on every rebuild, which orphans
|
|
1189
|
+
# the Accessibility grant and breaks the Fn hold-to-talk path. A Mac
|
|
1190
|
+
# without the signing key still builds ad-hoc (the old behaviour), but the
|
|
1191
|
+
# fallback is LOUD, never silent, and RECORDINGS_SIGNING_REQUIRED=1 above
|
|
1192
|
+
# turns it into a hard failure.
|
|
1193
|
+
discovered_identity="$(discover_developer_id_identity)"
|
|
1194
|
+
if [ -n "$discovered_identity" ]; then
|
|
1195
|
+
CODESIGN_IDENTITY="$discovered_identity"
|
|
1196
|
+
if [ -z "$EXPECTED_TEAM_ID" ]; then
|
|
1197
|
+
EXPECTED_TEAM_ID="$(derive_team_id "$CODESIGN_IDENTITY")" || exit 1
|
|
1198
|
+
fi
|
|
1199
|
+
else
|
|
1200
|
+
echo "WARNING: no Developer ID Application identity found in the keychain; local build falls back to ad-hoc signing (set RECORDINGS_SIGNING_REQUIRED=1 to fail instead)." >&2
|
|
1201
|
+
fi
|
|
1202
|
+
fi
|
|
1203
|
+
fi
|
|
1204
|
+
if [ -n "$CODESIGN_IDENTITY" ] && [ "$CODESIGN_IDENTITY" != "-" ]; then
|
|
1205
|
+
if [[ "$CODESIGN_IDENTITY" != "Developer ID Application:"* ]]; then
|
|
1206
|
+
echo "Local-station signing requires a Developer ID Application identity in RECORDINGS_CODESIGN_IDENTITY." >&2
|
|
1207
|
+
exit 1
|
|
1208
|
+
fi
|
|
1209
|
+
if [ -z "$EXPECTED_TEAM_ID" ]; then
|
|
1210
|
+
echo "Local-station Developer ID signing requires RECORDINGS_EXPECTED_TEAM_IDENTIFIER to pin the team." >&2
|
|
1211
|
+
exit 1
|
|
1212
|
+
fi
|
|
1213
|
+
if [ "$EXPECTED_TEAM_ID" = "ADHOC" ]; then
|
|
1214
|
+
echo "RECORDINGS_EXPECTED_TEAM_IDENTIFIER=ADHOC is not a Developer ID team." >&2
|
|
1215
|
+
exit 1
|
|
1216
|
+
fi
|
|
1217
|
+
LOCAL_SIGNING_MODE="developer_id"
|
|
1218
|
+
else
|
|
1219
|
+
CODESIGN_IDENTITY="-"
|
|
1220
|
+
EXPECTED_TEAM_ID="ADHOC"
|
|
1221
|
+
LOCAL_SIGNING_MODE="ad_hoc"
|
|
1222
|
+
fi
|
|
1036
1223
|
ARTIFACT_POLICY="local_only"
|
|
1037
1224
|
APPROVED_TARGET="$LOCAL_APPROVED_TARGET"
|
|
1038
1225
|
APPROVED_TARGET_IDENTITY_KIND="$LOCAL_APPROVED_TARGET_IDENTITY_KIND"
|
|
1039
1226
|
APPROVED_TARGET_IDENTITY_SHA256="$LOCAL_APPROVED_TARGET_IDENTITY_SHA256"
|
|
1040
|
-
|
|
1227
|
+
if [ "$LOCAL_SIGNING_MODE" = "developer_id" ]; then
|
|
1228
|
+
echo "WARNING: local-only artifacts are Developer ID signed, non-notarized, and restricted to ${APPROVED_TARGET}." >&2
|
|
1229
|
+
else
|
|
1230
|
+
echo "WARNING: local-only artifacts are ad-hoc signed, non-notarized, and restricted to ${APPROVED_TARGET}." >&2
|
|
1231
|
+
fi
|
|
1041
1232
|
echo "WARNING: installing can change code identity and require Microphone or Accessibility reauthorization." >&2
|
|
1042
1233
|
else
|
|
1043
1234
|
BUILD_CONFIGURATION="debug"
|
|
@@ -1075,9 +1266,9 @@ if [ "$MODE" = "release" ]; then
|
|
|
1075
1266
|
else
|
|
1076
1267
|
OUTPUT_BUILD_DIR="$SCRIPT_DIR/.build/$BUILD_CONFIGURATION"
|
|
1077
1268
|
fi
|
|
1078
|
-
OUTPUT_APP_DIR="$OUTPUT_BUILD_DIR
|
|
1269
|
+
OUTPUT_APP_DIR="$OUTPUT_BUILD_DIR/$APP_BUNDLE_NAME"
|
|
1079
1270
|
SWIFT_PRODUCT_DIR="$SWIFT_SCRATCH_PATH/$BUILD_CONFIGURATION"
|
|
1080
|
-
APP_DIR="$BUILD_WORK_DIR
|
|
1271
|
+
APP_DIR="$BUILD_WORK_DIR/$APP_BUNDLE_NAME"
|
|
1081
1272
|
CONTENTS="$APP_DIR/Contents"
|
|
1082
1273
|
MACOS="$CONTENTS/MacOS"
|
|
1083
1274
|
RESOURCES="$CONTENTS/Resources"
|
|
@@ -1235,6 +1426,16 @@ if [ "$MODE" = "release" ] && [ "$HOST_PLATFORM" = "Darwin" ]; then
|
|
|
1235
1426
|
fi
|
|
1236
1427
|
fi
|
|
1237
1428
|
"$CP_EXECUTABLE" "$SOURCE_NATIVE_DIR/RecordingsLib/Info.plist" "$CONTENTS/Info.plist"
|
|
1429
|
+
if [ "$VARIANT" = "bar" ]; then
|
|
1430
|
+
# The bar is an accessory app: LSUIElement keeps it out of the Dock and the app
|
|
1431
|
+
# switcher, and the app's window-declaring control flow (RECORDINGS_BAR_ONLY)
|
|
1432
|
+
# keeps the workspace window absent. The bundle identifier stays com.hasna.recordings
|
|
1433
|
+
# so TCC grants continue to key on bundle id + signing identity, and the bundle is
|
|
1434
|
+
# named per the fleet rule (knowledge k_msxd5rz3_jfvl3i) — HasnaRecordings.app with
|
|
1435
|
+
# the display name "Hasna Recordings"; 'Hasna' at the beginning of the name.
|
|
1436
|
+
"$PLIST_BUDDY" -c 'Add :LSUIElement bool true' "$CONTENTS/Info.plist"
|
|
1437
|
+
"$PLIST_BUDDY" -c 'Set :CFBundleDisplayName Hasna Recordings' "$CONTENTS/Info.plist"
|
|
1438
|
+
fi
|
|
1238
1439
|
VERSION="$("$PLIST_BUDDY" -c 'Print :CFBundleShortVersionString' "$CONTENTS/Info.plist")"
|
|
1239
1440
|
|
|
1240
1441
|
compute_release_publication_identity() {
|
|
@@ -1248,6 +1449,7 @@ compute_release_publication_identity() {
|
|
|
1248
1449
|
--component "release_sequence=$RELEASE_SEQUENCE"
|
|
1249
1450
|
--component "key_epoch=$KEY_EPOCH"
|
|
1250
1451
|
--component "expires_at_utc=$ENVELOPE_EXPIRES_AT_UTC"
|
|
1452
|
+
--component "variant=$VARIANT"
|
|
1251
1453
|
)
|
|
1252
1454
|
identity_arguments+=(--component "envelope_public_key_sha256=$ENVELOPE_PUBLIC_KEY_SHA256")
|
|
1253
1455
|
if [ "$RELEASE_SUBTYPE" = "initial-bootstrap" ]; then
|
|
@@ -1266,7 +1468,7 @@ compute_release_publication_identity() {
|
|
|
1266
1468
|
|
|
1267
1469
|
reserve_release_output() {
|
|
1268
1470
|
local release_set_basename reserved_output
|
|
1269
|
-
release_set_basename="
|
|
1471
|
+
release_set_basename="${APP_BASENAME}-${VERSION}-macos-${RELEASE_SUBTYPE}"
|
|
1270
1472
|
compute_release_publication_identity
|
|
1271
1473
|
RELEASE_OUTPUT_ROOT="$OUTPUT_BUILD_DIR"
|
|
1272
1474
|
RELEASE_FINAL_DIR="$RELEASE_OUTPUT_ROOT/${release_set_basename}.release"
|
|
@@ -1333,7 +1535,7 @@ reserve_release_output() {
|
|
|
1333
1535
|
RELEASE_STAGING_DIR="$($MKTEMP_EXECUTABLE -d "$RELEASE_OUTPUT_ROOT/.${release_set_basename}.staging.XXXXXX")"
|
|
1334
1536
|
"$CHMOD_EXECUTABLE" 0700 "$RELEASE_STAGING_DIR"
|
|
1335
1537
|
OUTPUT_BUILD_DIR="$RELEASE_STAGING_DIR"
|
|
1336
|
-
OUTPUT_APP_DIR="$OUTPUT_BUILD_DIR
|
|
1538
|
+
OUTPUT_APP_DIR="$OUTPUT_BUILD_DIR/$APP_BUNDLE_NAME"
|
|
1337
1539
|
}
|
|
1338
1540
|
|
|
1339
1541
|
if [ "$MODE" = "release" ]; then
|
|
@@ -1468,8 +1670,8 @@ run_signed_helper_contract() {
|
|
|
1468
1670
|
HOME="$contract_home"
|
|
1469
1671
|
PATH="/usr/bin:/bin:/usr/sbin:/sbin"
|
|
1470
1672
|
TMPDIR="$contract_home"
|
|
1471
|
-
|
|
1472
|
-
|
|
1673
|
+
HASNA_RECORDINGS_CLIENT_STORE="sqlite"
|
|
1674
|
+
RECORDINGS_CLIENT_STORE="sqlite"
|
|
1473
1675
|
HASNA_RECORDINGS_DB_PATH="$contract_home/recordings.db"
|
|
1474
1676
|
RECORDINGS_AUDIO_DIR="$contract_home/audio"
|
|
1475
1677
|
)
|
|
@@ -1521,6 +1723,7 @@ if [ "$MODE" != "debug" ]; then
|
|
|
1521
1723
|
--team-id "$EXPECTED_TEAM_ID" \
|
|
1522
1724
|
--package-root "$PACKAGE_ROOT" \
|
|
1523
1725
|
--artifact-policy "$ARTIFACT_POLICY" \
|
|
1726
|
+
--variant "$VARIANT" \
|
|
1524
1727
|
--approved-target "$APPROVED_TARGET" \
|
|
1525
1728
|
--approved-target-identity-kind "$APPROVED_TARGET_IDENTITY_KIND" \
|
|
1526
1729
|
--approved-target-identity-sha256 "$APPROVED_TARGET_IDENTITY_SHA256" \
|
|
@@ -1578,7 +1781,7 @@ run_codesign --verify --deep --strict --verbose=2 "$APP_DIR"
|
|
|
1578
1781
|
TMPDIR="$BUILD_WORK_DIR" \
|
|
1579
1782
|
SSH_CONNECTION="${SSH_CONNECTION:-}" \
|
|
1580
1783
|
${SMOKE_TEST_ENVIRONMENT[0]+"${SMOKE_TEST_ENVIRONMENT[@]}"} \
|
|
1581
|
-
"$BASH_EXECUTABLE" "$SMOKE_SCRIPT" "$APP_DIR" "$BUN_EXECUTABLE"
|
|
1784
|
+
"$BASH_EXECUTABLE" "$SMOKE_SCRIPT" "$APP_DIR" "$BUN_EXECUTABLE" --variant "$VARIANT"
|
|
1582
1785
|
|
|
1583
1786
|
publish_app_output() {
|
|
1584
1787
|
local source_tree_digest
|
|
@@ -1742,7 +1945,7 @@ publish_complete_release_set() {
|
|
|
1742
1945
|
RELEASE_DIRECTORY_PUBLISHED=1
|
|
1743
1946
|
RELEASE_STAGING_DIR=""
|
|
1744
1947
|
OUTPUT_BUILD_DIR="$RELEASE_FINAL_DIR"
|
|
1745
|
-
OUTPUT_APP_DIR="$OUTPUT_BUILD_DIR
|
|
1948
|
+
OUTPUT_APP_DIR="$OUTPUT_BUILD_DIR/$APP_BUNDLE_NAME"
|
|
1746
1949
|
run_bun "$SOURCE_PACKAGE_ROOT/scripts/macos_artifact.ts" complete-release-publication \
|
|
1747
1950
|
--destination "$RELEASE_FINAL_DIR" \
|
|
1748
1951
|
--reservation "$RELEASE_RESERVATION" \
|
|
@@ -1768,7 +1971,7 @@ if [ "$MODE" = "debug" ]; then
|
|
|
1768
1971
|
fi
|
|
1769
1972
|
|
|
1770
1973
|
if [ "$MODE" = "local" ]; then
|
|
1771
|
-
ARTIFACT_BASENAME="
|
|
1974
|
+
ARTIFACT_BASENAME="${APP_BASENAME}-${VERSION}-macos-${APPROVED_TARGET}-local-only"
|
|
1772
1975
|
FINAL_ARCHIVE="$OUTPUT_BUILD_DIR/${ARTIFACT_BASENAME}.zip"
|
|
1773
1976
|
FINAL_MANIFEST="$OUTPUT_BUILD_DIR/${ARTIFACT_BASENAME}.manifest.json"
|
|
1774
1977
|
"$RM_EXECUTABLE" -f "$FINAL_ARCHIVE" "$FINAL_MANIFEST"
|
|
@@ -1781,9 +1984,11 @@ if [ "$MODE" = "local" ]; then
|
|
|
1781
1984
|
--archive "$FINAL_ARCHIVE" \
|
|
1782
1985
|
--manifest "$FINAL_MANIFEST" \
|
|
1783
1986
|
--package-root "$PACKAGE_ROOT" \
|
|
1987
|
+
--variant "$VARIANT" \
|
|
1784
1988
|
--approved-target "$APPROVED_TARGET" \
|
|
1785
1989
|
--approved-target-identity-kind "$APPROVED_TARGET_IDENTITY_KIND" \
|
|
1786
|
-
--approved-target-identity-sha256 "$APPROVED_TARGET_IDENTITY_SHA256"
|
|
1990
|
+
--approved-target-identity-sha256 "$APPROVED_TARGET_IDENTITY_SHA256" \
|
|
1991
|
+
--expected-team-id "$EXPECTED_TEAM_ID"
|
|
1787
1992
|
publish_app_output
|
|
1788
1993
|
verify_source_unchanged
|
|
1789
1994
|
echo "Built immutable local-only app artifact: $FINAL_ARCHIVE"
|
|
@@ -1794,7 +1999,7 @@ fi
|
|
|
1794
1999
|
|
|
1795
2000
|
verify_signed_code "$HELPERS/recordings" "Companion CLI"
|
|
1796
2001
|
verify_signed_code "$APP_DIR" "Recordings.app"
|
|
1797
|
-
ARTIFACT_BASENAME="
|
|
2002
|
+
ARTIFACT_BASENAME="${APP_BASENAME}-${VERSION}-macos-${RELEASE_SUBTYPE}"
|
|
1798
2003
|
NOTARY_ARCHIVE="$OUTPUT_BUILD_DIR/${ARTIFACT_BASENAME}-notarization.zip"
|
|
1799
2004
|
FINAL_ARCHIVE="$OUTPUT_BUILD_DIR/${ARTIFACT_BASENAME}.zip"
|
|
1800
2005
|
FINAL_MANIFEST="$OUTPUT_BUILD_DIR/${ARTIFACT_BASENAME}.manifest.json"
|
|
@@ -1857,6 +2062,7 @@ run_bun "$SOURCE_PACKAGE_ROOT/scripts/macos_artifact.ts" finalize \
|
|
|
1857
2062
|
--manifest "$FINAL_MANIFEST" \
|
|
1858
2063
|
--package-root "$PACKAGE_ROOT" \
|
|
1859
2064
|
--team-id "$EXPECTED_TEAM_ID" \
|
|
2065
|
+
--variant "$VARIANT" \
|
|
1860
2066
|
--notary-log "$NOTARY_LOG" \
|
|
1861
2067
|
--notary-submission-id "$NOTARY_ID" \
|
|
1862
2068
|
--submitted-archive-sha256 "$NOTARY_ARCHIVE_SHA256"
|
|
Binary file
|