mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 08:03:12 +00:00
* feat(telemetry): measure macOS stale-daemon adoption and cwd denials Adds two enum-only PostHog events so #17696 can be sized instead of guessed at: - daemon_adopted: once per macOS launch that keeps a daemon an earlier app launch forked (invisible to daemon_lifecycle, which only sees replacements). Carries app-version match, spawner-path class (installed app / Squirrel ShipIt cache / other / missing), the existing TCC attribution verdict, and the bucketed live-session count. - daemon_pty_cwd_denied: the symptom itself. The daemon probes the requested cwd in its own process (only its TCC context counts) and returns an additive cwdReadableByDaemon field; the app emits only when the daemon was denied AND the app can read the same path, so a missing or genuinely unreadable cwd never counts. Non-permission errors read as readable on purpose. Both emitters swallow every failure; nothing here can delay or fail daemon startup or a PTY spawn. Off macOS neither event fires. The new wire field is optional, so older daemons and clients are unaffected. * fix(telemetry): keep cwd-denial classification inside the swallow guard Read the pid record at emit time (inside the try) rather than passing the adapter's startup snapshot: a throwing app-environment read can no longer escape spawn(), and a denial after a respawn is billed to the daemon that actually spawned the PTY.
90 lines
3.6 KiB
TypeScript
90 lines
3.6 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { classifyDaemonPtyCwd, classifyDaemonSpawnerPath } from './daemon-adoption-telemetry'
|
|
import { eventSchemas } from './telemetry-event-registry'
|
|
|
|
describe('classifyDaemonSpawnerPath', () => {
|
|
const alwaysExists = () => true
|
|
|
|
it('classifies the installed app, the ShipIt staging area, and everything else', () => {
|
|
expect(
|
|
classifyDaemonSpawnerPath('/Applications/Orca.app/Contents/MacOS/Orca', alwaysExists)
|
|
).toBe('applications')
|
|
expect(
|
|
classifyDaemonSpawnerPath('/private/Applications/Orca.app/Contents/MacOS/Orca', alwaysExists)
|
|
).toBe('applications')
|
|
expect(
|
|
classifyDaemonSpawnerPath(
|
|
'/Users/a/Library/Caches/com.stablyai.orca.ShipIt/update.abc/Orca.app/Contents/MacOS/Orca',
|
|
alwaysExists
|
|
)
|
|
).toBe('updater-cache')
|
|
expect(
|
|
classifyDaemonSpawnerPath('/Users/a/Applications/Orca.app/Contents/MacOS/Orca', alwaysExists)
|
|
).toBe('other')
|
|
expect(classifyDaemonSpawnerPath('/tmp/OrcaA.app/Contents/MacOS/Orca', alwaysExists)).toBe(
|
|
'other'
|
|
)
|
|
})
|
|
|
|
it('reports a deleted spawner as missing and an unrecorded one as unknown', () => {
|
|
expect(
|
|
classifyDaemonSpawnerPath('/Applications/Orca.app/Contents/MacOS/Orca', () => false)
|
|
).toBe('missing')
|
|
expect(classifyDaemonSpawnerPath(null, alwaysExists)).toBe('unknown')
|
|
})
|
|
})
|
|
|
|
describe('classifyDaemonPtyCwd', () => {
|
|
it('maps the TCC-protected home folders and separates the rest of home from outside it', () => {
|
|
expect(classifyDaemonPtyCwd('/Users/a/Documents/repo', '/Users/a')).toBe('documents')
|
|
expect(classifyDaemonPtyCwd('/Users/a/Desktop', '/Users/a/')).toBe('desktop')
|
|
expect(classifyDaemonPtyCwd('/Users/a/Downloads/x/y', '/Users/a')).toBe('downloads')
|
|
expect(classifyDaemonPtyCwd('/Users/a/projects/repo', '/Users/a')).toBe('other-home')
|
|
expect(classifyDaemonPtyCwd('/Users/a', '/Users/a')).toBe('other-home')
|
|
expect(classifyDaemonPtyCwd('/Volumes/ext/repo', '/Users/a')).toBe('outside-home')
|
|
// A sibling home that merely shares the prefix is not inside this home.
|
|
expect(classifyDaemonPtyCwd('/Users/ab/Documents', '/Users/a')).toBe('outside-home')
|
|
})
|
|
})
|
|
|
|
// Privacy invariant: enum-only. A raw path, version, or exact count must be rejected by .strict().
|
|
describe('daemon_adopted / daemon_pty_cwd_denied schemas', () => {
|
|
const adopted = {
|
|
app_version_match: 'different',
|
|
spawner_path_class: 'updater-cache',
|
|
tcc_attribution: 'intact',
|
|
live_session_count_bucket: '2-5'
|
|
}
|
|
const denied = {
|
|
cwd_class: 'documents',
|
|
app_version_match: 'different',
|
|
spawner_path_class: 'updater-cache'
|
|
}
|
|
|
|
it('accepts the enum payloads', () => {
|
|
expect(eventSchemas.daemon_adopted.safeParse(adopted).success).toBe(true)
|
|
expect(eventSchemas.daemon_pty_cwd_denied.safeParse(denied).success).toBe(true)
|
|
})
|
|
|
|
it('rejects leaked paths, versions, counts, and unknown enum values', () => {
|
|
for (const leak of [
|
|
{ spawner_exec_path: '/Users/alice/Library/Caches/ShipIt/Orca.app' },
|
|
{ app_version: '1.4.187' },
|
|
{ live_session_count: 3 },
|
|
{ cwd: '/Users/alice/Documents' }
|
|
]) {
|
|
expect(eventSchemas.daemon_adopted.safeParse({ ...adopted, ...leak }).success).toBe(false)
|
|
expect(eventSchemas.daemon_pty_cwd_denied.safeParse({ ...denied, ...leak }).success).toBe(
|
|
false
|
|
)
|
|
}
|
|
expect(
|
|
eventSchemas.daemon_adopted.safeParse({ ...adopted, spawner_path_class: '/Applications' })
|
|
.success
|
|
).toBe(false)
|
|
expect(
|
|
eventSchemas.daemon_pty_cwd_denied.safeParse({ ...denied, cwd_class: 'Documents' }).success
|
|
).toBe(false)
|
|
})
|
|
})
|