caveat-cli 0.20.3 → 0.21.1

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.
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __caveat_createRequire } from 'node:module';
3
+ const require = __caveat_createRequire(import.meta.url);
4
+
5
+ // ../../packages/core/src/managedDeploymentRuntime.ts
6
+ import { createHash as createHash2 } from "node:crypto";
7
+ import { existsSync, lstatSync, readFileSync, realpathSync } from "node:fs";
8
+ import { join as join2, resolve, relative, sep } from "node:path";
9
+ import { homedir } from "node:os";
10
+
11
+ // ../../packages/core/src/platform.ts
12
+ import { spawnSync } from "node:child_process";
13
+ import { createHash } from "node:crypto";
14
+ import { join, isAbsolute, win32 } from "node:path";
15
+ function isWindows(platform = process.platform) {
16
+ return platform === "win32";
17
+ }
18
+
19
+ // ../../packages/core/src/managedDeploymentRuntime.ts
20
+ var sha = (data) => createHash2("sha256").update(data).digest("hex");
21
+ var releasePattern = /^\d+\.\d+\.\d+-[a-f0-9]{20}$/;
22
+ var versionPattern = /^\d+\.\d+\.\d+$/;
23
+ var MAX_FILES = 4096;
24
+ function fail(reason) {
25
+ throw Error(`managed_deployment_${reason}`);
26
+ }
27
+ function canonicalHome(userHome = homedir()) {
28
+ const path = resolve(userHome);
29
+ return existsSync(path) ? realpathSync(path) : path;
30
+ }
31
+ function managedDeploymentPaths(userHome = homedir()) {
32
+ const root = join2(canonicalHome(userHome), ".local", "share", "caveat", "managed-v1");
33
+ return {
34
+ root,
35
+ releases: join2(root, "releases"),
36
+ entry: join2(root, "entry"),
37
+ launcher: join2(root, "entry", "caveat.mjs"),
38
+ runtime: join2(root, "entry", "managed-deployment.js"),
39
+ pointer: join2(root, "active.json"),
40
+ lock: join2(root, "installer.lock")
41
+ };
42
+ }
43
+ function ownerStat(path, directory, options) {
44
+ const s = lstatSync(path);
45
+ if (s.isSymbolicLink() || (directory ? !s.isDirectory() : !s.isFile())) fail("unsafe_path");
46
+ if (!(options.windows ?? isWindows()) && ((s.mode & 18) !== 0 || typeof process.getuid === "function" && s.uid !== process.getuid())) fail("unsafe_owner_or_mode");
47
+ return s;
48
+ }
49
+ function assertAncestors(options) {
50
+ const paths = managedDeploymentPaths(options.userHome);
51
+ const home = canonicalHome(options.userHome);
52
+ ownerStat(home, true, options);
53
+ let path = home;
54
+ for (const part of relative(home, paths.root).split(sep)) {
55
+ path = join2(path, part);
56
+ ownerStat(path, true, options);
57
+ }
58
+ if (realpathSync(paths.root) !== paths.root) fail("root_redirected");
59
+ return paths;
60
+ }
61
+ function checkReleaseMetadata(pointer, options) {
62
+ const paths = managedDeploymentPaths(options.userHome);
63
+ if (pointer.schema !== 1 || !releasePattern.test(pointer.release) || !/^[a-f0-9]{64}$/.test(pointer.manifestSha256)) fail("invalid_pointer");
64
+ const releaseRoot = join2(paths.releases, pointer.release);
65
+ ownerStat(paths.releases, true, options);
66
+ ownerStat(releaseRoot, true, options);
67
+ const manifestPath = join2(releaseRoot, "manifest.json");
68
+ if (ownerStat(manifestPath, false, options).size > 1024 * 1024) fail("manifest_too_large");
69
+ const bytes = readFileSync(manifestPath);
70
+ if (sha(bytes) !== pointer.manifestSha256) fail("manifest_changed");
71
+ const manifest = JSON.parse(bytes.toString());
72
+ if (manifest.schema !== 1 || !versionPattern.test(manifest.version) || !pointer.release.startsWith(manifest.version + "-") || !Array.isArray(manifest.files) || manifest.files.length > MAX_FILES) fail("invalid_manifest");
73
+ const packageRoot = join2(releaseRoot, "package");
74
+ ownerStat(packageRoot, true, options);
75
+ ownerStat(join2(packageRoot, "dist"), true, options);
76
+ const cliScriptPath = join2(packageRoot, "dist", "caveat.js");
77
+ ownerStat(cliScriptPath, false, options);
78
+ return { pointer, manifest, packageRoot, cliScriptPath, launcher: paths.launcher };
79
+ }
80
+ function readManagedDeployment(options = {}) {
81
+ const paths = assertAncestors(options);
82
+ ownerStat(paths.entry, true, options);
83
+ ownerStat(paths.launcher, false, options);
84
+ ownerStat(paths.runtime, false, options);
85
+ if (ownerStat(paths.pointer, false, options).size > 1024) fail("pointer_too_large");
86
+ const pointer = JSON.parse(readFileSync(paths.pointer, "utf8"));
87
+ if (Object.keys(pointer).sort().join(",") !== "manifestSha256,release,schema") fail("invalid_pointer");
88
+ return checkReleaseMetadata(pointer, options);
89
+ }
90
+ function managedRegistrationPath(cliScriptPath, options = {}) {
91
+ const paths = managedDeploymentPaths(options.userHome);
92
+ if (!existsSync(paths.pointer)) return cliScriptPath;
93
+ const active = readManagedDeployment(options);
94
+ return active.launcher;
95
+ }
96
+ var managedDeploymentInternal = { sha, fail, canonicalHome, ownerStat, assertAncestors, checkReleaseMetadata, versionPattern, releasePattern };
97
+ export {
98
+ managedDeploymentInternal,
99
+ managedDeploymentPaths,
100
+ managedRegistrationPath,
101
+ readManagedDeployment
102
+ };
103
+ //# sourceMappingURL=managed-deployment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/core/src/managedDeploymentRuntime.ts","../../../packages/core/src/platform.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, lstatSync, readFileSync, realpathSync } from 'node:fs';\nimport { join, resolve, relative, isAbsolute, sep } from 'node:path';\nimport { homedir } from 'node:os';\nimport { isWindows } from './platform.js';\nimport type { runWindowsAcl } from './privateWindowsAcl.js';\n\nexport type FileRecord = { path: string; sha256: string; bytes: number };\nexport type Manifest = { schema: 1; version: string; files: FileRecord[] };\nexport type Pointer = { schema: 1; release: string; manifestSha256: string };\nexport type ManagedRuntimeOptions = { userHome?: string; windows?: boolean; aclRunner?: typeof runWindowsAcl };\nconst sha = (data: string | Buffer) => createHash('sha256').update(data).digest('hex');\nconst releasePattern = /^\\d+\\.\\d+\\.\\d+-[a-f0-9]{20}$/;\nconst versionPattern = /^\\d+\\.\\d+\\.\\d+$/;\nconst MAX_FILES = 4096;\nfunction fail(reason: string): never { throw Error(`managed_deployment_${reason}`); }\nfunction canonicalHome(userHome = homedir()) {\n const path=resolve(userHome);\n // macOS /var -> /private/var and other OS-level aliases may precede the\n // user profile. Descendants of the canonical home still reject redirects.\n return existsSync(path) ? realpathSync(path) : path;\n}\nexport function managedDeploymentPaths(userHome = homedir()) {\n const root = join(canonicalHome(userHome), '.local', 'share', 'caveat', 'managed-v1');\n return { root, releases: join(root, 'releases'), entry: join(root, 'entry'),\n launcher: join(root, 'entry', 'caveat.mjs'), runtime: join(root, 'entry', 'managed-deployment.js'),\n pointer: join(root, 'active.json'), lock: join(root, 'installer.lock') };\n}\nfunction ownerStat(path: string, directory: boolean, options: ManagedRuntimeOptions) {\n const s = lstatSync(path);\n if (s.isSymbolicLink() || (directory ? !s.isDirectory() : !s.isFile())) fail('unsafe_path');\n if (!(options.windows ?? isWindows()) && ((s.mode & 0o022) !== 0 || (typeof process.getuid === 'function' && s.uid !== process.getuid()))) fail('unsafe_owner_or_mode');\n return s;\n}\nfunction assertAncestors(options: ManagedRuntimeOptions) {\n const paths = managedDeploymentPaths(options.userHome);\n const home = canonicalHome(options.userHome);\n ownerStat(home, true, options);\n let path = home;\n for (const part of relative(home, paths.root).split(sep)) {\n path = join(path, part); ownerStat(path, true, options);\n }\n if (realpathSync(paths.root) !== paths.root) fail('root_redirected');\n return paths;\n}\nfunction checkReleaseMetadata(pointer: Pointer, options: ManagedRuntimeOptions) {\n const paths = managedDeploymentPaths(options.userHome);\n if (pointer.schema !== 1 || !releasePattern.test(pointer.release) || !/^[a-f0-9]{64}$/.test(pointer.manifestSha256)) fail('invalid_pointer');\n const releaseRoot = join(paths.releases, pointer.release);\n ownerStat(paths.releases, true, options); ownerStat(releaseRoot, true, options);\n const manifestPath = join(releaseRoot, 'manifest.json');\n if (ownerStat(manifestPath, false, options).size > 1024 * 1024) fail('manifest_too_large');\n const bytes = readFileSync(manifestPath);\n if (sha(bytes) !== pointer.manifestSha256) fail('manifest_changed');\n const manifest = JSON.parse(bytes.toString()) as Manifest;\n if (manifest.schema !== 1 || !versionPattern.test(manifest.version) || !pointer.release.startsWith(manifest.version + '-') || !Array.isArray(manifest.files) || manifest.files.length > MAX_FILES) fail('invalid_manifest');\n const packageRoot = join(releaseRoot, 'package');\n ownerStat(packageRoot, true, options); ownerStat(join(packageRoot, 'dist'), true, options);\n const cliScriptPath = join(packageRoot, 'dist', 'caveat.js'); ownerStat(cliScriptPath, false, options);\n return { pointer, manifest, packageRoot, cliScriptPath, launcher: paths.launcher };\n}\n/** Startup checks only: no process creation or package-wide content scan. */\nexport function readManagedDeployment(options: ManagedRuntimeOptions = {}) {\n const paths = assertAncestors(options);\n ownerStat(paths.entry, true, options); ownerStat(paths.launcher, false, options); ownerStat(paths.runtime, false, options);\n if (ownerStat(paths.pointer, false, options).size > 1024) fail('pointer_too_large');\n const pointer = JSON.parse(readFileSync(paths.pointer, 'utf8')) as Pointer;\n if (Object.keys(pointer).sort().join(',') !== 'manifestSha256,release,schema') fail('invalid_pointer');\n return checkReleaseMetadata(pointer, options);\n}\n/** Direct npm callers register the active stable entry when it owns this package. */\nexport function managedRegistrationPath(cliScriptPath: string, options: ManagedRuntimeOptions = {}) {\n const paths = managedDeploymentPaths(options.userHome);\n if (!existsSync(paths.pointer)) return cliScriptPath;\n const active = readManagedDeployment(options);\n // A managed installation explicitly selects its active release. An npm-bin\n // caller must not rewrite registrations back to its own version directory.\n return active.launcher;\n}\n\nexport const managedDeploymentInternal = { sha, fail, canonicalHome, ownerStat, assertAncestors, checkReleaseMetadata, versionPattern, releasePattern };\n","import type { Stats } from 'node:fs';\nimport { spawnSync } from 'node:child_process';\nimport { XMLParser } from 'fast-xml-parser';\nimport { createHash } from 'node:crypto';\nimport { join, isAbsolute, win32 } from 'node:path';\n\n/**\n * OS 依存の判定はこのモジュールに集約する。他のファイルで\n * `process.platform` / `win32` を直接分岐しない(データとして記録する\n * fingerprint 等は除く)。全関数は platform を引数で受けてテスト可能にする。\n */\n\nexport function isWindows(platform: NodeJS.Platform = process.platform): boolean {\n return platform === 'win32';\n}\n\n/**\n * env を考慮した Windows 判定。`OS=Windows_NT` は Windows native shell が必ず持つ\n * 環境変数で、テストが env 注入だけで Windows 経路を選べるようにする\n * (runtimeErrors が独自に持っていた判定をここへ集約。v0.17.5)。\n */\nexport function isWindowsEnv(\n env: NodeJS.ProcessEnv,\n platform: NodeJS.Platform = process.platform,\n): boolean {\n return env.OS === 'Windows_NT' || isWindows(platform);\n}\n\n/**\n * owner-only 所有チェック。Node の POSIX mode/uid フィールドは Windows では\n * ACL のビューにならないため、Windows は構造チェック(呼び出し側のマーカー・\n * スキーマ検証や親ディレクトリの ACL)に委ねて素通しする。\n */\nexport function isPrivateOwnerStat(\n stat: Stats,\n uid: number | undefined,\n platform: NodeJS.Platform = process.platform,\n): boolean {\n return isWindows(platform)\n || ((stat.mode & 0o077) === 0 && (uid === undefined || stat.uid === uid));\n}\n\n/**\n * Windows native Codex hook command は quoted Node パスを PowerShell で\n * 実行するため call operator `&` が必要(v0.17.1)。POSIX は不要。\n */\nexport function powershellCallPrefix(platform: NodeJS.Platform = process.platform): string {\n return isWindows(platform) ? '& ' : '';\n}\n\n/** PATH 走査で node 実行ファイルとして探す名前の候補。 */\nexport function nodeExecutableNames(platform: NodeJS.Platform = process.platform): string[] {\n return isWindows(platform)\n ? ['node.exe', 'node.cmd', 'node.bat', 'node']\n : ['node'];\n}\n\n/**\n * ファイルシステムが case-insensitive な Windows ではパス比較用に小文字化する。\n * 呼び出し側で区切り文字の正規化(\\\\ → /)を済ませてから渡す。\n */\nexport function normalizePathCase(\n normalizedPath: string,\n platform: NodeJS.Platform = process.platform,\n): string {\n return isWindows(platform) ? normalizedPath.toLowerCase() : normalizedPath;\n}\n\nexport interface ScheduleCommand { command: string; args: string[] }\n/** Resolve the current token, never a guessed USERDOMAIN/account pair. */\nexport function nativeScheduleUserId(\n username: string,\n platform: NodeJS.Platform = process.platform,\n run: (command: ScheduleCommand) => { status: number; stdout: string } = command => {\n const result = spawnSync(command.command, command.args, { encoding: 'utf8', timeout: 30_000, windowsHide: true });\n if (result.error) throw Error('schedule_identity_spawn_failed');\n return { status: result.status ?? -1, stdout: result.stdout ?? '' };\n },\n systemRoot = process.env.SystemRoot,\n): string {\n if (!isWindows(platform)) return username;\n let phase: 'root' | 'spawn' | 'exit' | 'output' = 'root';\n try {\n if (!systemRoot || !win32.isAbsolute(systemRoot) || /[\\x00-\\x1f]/.test(systemRoot)) throw Error('schedule_system_root_unavailable');\n phase = 'spawn';\n const result = run({ command: win32.join(systemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe'), args: ['-NoProfile', '-NonInteractive', '-Command',\n \"$ErrorActionPreference='Stop';try{[Console]::Write([System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value);exit 0}catch{exit 1}\"] });\n phase = 'exit';\n if (result.status !== 0) throw Error('schedule_identity_exit_failed');\n phase = 'output';\n const sid = result.stdout.trim();\n if (/^S-1-\\d+(?:-\\d+){1,15}$/.test(sid)) return sid;\n } catch { /* Never fall back to environment/account-name guesses. */ }\n throw Error(`schedule_user_identity_unavailable_${phase}`);\n}\n\nexport interface NativeSyncSchedule {\n id: string;\n kind: 'systemd-user' | 'launchd-user' | 'windows-task';\n files: { path: string; content: string; encoding?: 'utf16le' }[];\n query: ScheduleCommand;\n inspect: ScheduleCommand;\n install: ScheduleCommand[];\n remove: ScheduleCommand[];\n reload: ScheduleCommand[];\n argv: string[];\n}\n/** Exact persisted bytes; absent encoding preserves legacy UTF-8 ownership. */\nexport function nativeScheduleFileBytes(file: NativeSyncSchedule['files'][number]): Buffer {\n if (file.encoding === 'utf16le') return Buffer.concat([Buffer.from([0xff, 0xfe]), Buffer.from(file.content, 'utf16le')]);\n if (file.encoding !== undefined) throw Error('schedule_definition_encoding_invalid');\n return Buffer.from(file.content, 'utf8');\n}\n\nexport interface NativeSyncScheduleOptions {\n caveatHome: string; userHome: string; nodePath: string; cliPath: string;\n platform?: NodeJS.Platform; uid?: number; userId?: string;\n}\n\nconst xml = (value: string) => value.replace(/[&<>\"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&apos;' })[c]!);\nconst unitArg = (value: string) => `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/%/g, '%%').replace(/\\$/g, () => '$$')}\"`;\n/** Standard Windows argv quoting, without invoking cmd.exe or PowerShell. */\nexport function quoteWindowsArgument(value: string): string {\n return `\"${value.replace(/(\\\\*)\"/g, '$1$1\\\\\"').replace(/(\\\\+)$/g, '$1$1')}\"`;\n}\n\nexport function nativeSyncSchedule(opts: NativeSyncScheduleOptions): NativeSyncSchedule {\n const platform = opts.platform ?? process.platform;\n const absolute = platform === 'win32' ? win32.isAbsolute : isAbsolute;\n for (const value of [opts.caveatHome, opts.userHome, opts.nodePath, opts.cliPath]) {\n if (!absolute(value) || /[\\x00-\\x1f]/.test(value)) throw Error('schedule_absolute_path_required');\n }\n const suffix = createHash('sha256').update(normalizePathCase(opts.caveatHome, platform)).digest('hex').slice(0, 16);\n const id = `caveat-autosync-${suffix}`;\n const argv = [opts.nodePath, opts.cliPath, 'autosync', 'run', '--json', '--caveat-home', opts.caveatHome, '--user-home', opts.userHome];\n const command = (name: string, ...args: string[]): ScheduleCommand => ({ command: name, args });\n if (platform === 'linux') {\n const service = join(opts.userHome, '.config', 'systemd', 'user', `${id}.service`);\n const timer = join(opts.userHome, '.config', 'systemd', 'user', `${id}.timer`);\n return { id, kind: 'systemd-user', argv, files: [\n { path: service, content: `[Unit]\\nDescription=Caveat private knowledge reception\\n[Service]\\nType=oneshot\\nTimeoutStartSec=10min\\nExecStart=${argv.map(unitArg).join(' ')}\\nSuccessExitStatus=2\\n` },\n { path: timer, content: `[Unit]\\nDescription=Caveat reception timer\\n[Timer]\\nOnBootSec=60s\\nOnUnitInactiveSec=60s\\nUnit=${id}.service\\n[Install]\\nWantedBy=timers.target\\n` },\n ], query: command('systemctl', '--user', 'is-active', `${id}.timer`),\n inspect: command('systemctl', '--user', 'show', `${id}.timer`, '--property=LoadState', '--value'),\n install: [command('systemctl', '--user', 'link', service, timer), command('systemctl', '--user', 'daemon-reload'), command('systemctl', '--user', 'enable', '--now', `${id}.timer`)],\n remove: [command('systemctl', '--user', 'stop', `${id}.timer`, `${id}.service`), command('systemctl', '--user', 'disable', `${id}.timer`, `${id}.service`)],\n reload: [command('systemctl', '--user', 'daemon-reload')] };\n }\n if (platform === 'darwin') {\n if (!Number.isInteger(opts.uid) || opts.uid! < 0) throw Error('schedule_uid_required');\n const label = `dev.caveat.${id}`;\n const file = join(opts.userHome, 'Library', 'LaunchAgents', `${label}.plist`);\n const domain = `gui/${opts.uid}`;\n return { id: label, kind: 'launchd-user', argv, files: [{ path: file, content: `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<plist version=\"1.0\"><dict><key>Label</key><string>${label}</string><key>ProgramArguments</key><array>${argv.map(a => `<string>${xml(a)}</string>`).join('')}</array><key>StartInterval</key><integer>60</integer></dict></plist>\\n` }],\n query: command('launchctl', 'print', `${domain}/${label}`),\n inspect: command('launchctl', 'print', `${domain}/${label}`),\n install: [command('launchctl', 'bootstrap', domain, file)],\n remove: [command('launchctl', 'bootout', `${domain}/${label}`)], reload: [] };\n }\n if (platform === 'win32') {\n if (!opts.userId || /[\\x00-\\x1f]/.test(opts.userId)) throw Error('schedule_user_id_required');\n const file = join(opts.caveatHome, 'sync', `${id}.xml`);\n // schtasks imports a BOM-marked UTF-16LE file, matching its Unicode XML\n // declaration; BOM-less UTF-8 corrupted non-ASCII paths on Windows.\n // Daily repetition avoids locale-sensitive date arguments to schtasks.\n const content = `<?xml version=\"1.0\" encoding=\"UTF-16\"?>\\n<Task version=\"1.2\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\"><RegistrationInfo><Description>Caveat private knowledge reception ${id}</Description></RegistrationInfo><Triggers><CalendarTrigger><Repetition><Interval>PT1M</Interval><Duration>P1D</Duration><StopAtDurationEnd>false</StopAtDurationEnd></Repetition><StartBoundary>2020-01-01T00:00:00</StartBoundary><Enabled>true</Enabled><ScheduleByDay><DaysInterval>1</DaysInterval></ScheduleByDay></CalendarTrigger></Triggers><Principals><Principal id=\"CurrentUser\"><UserId>${xml(opts.userId)}</UserId><LogonType>InteractiveToken</LogonType><RunLevel>LeastPrivilege</RunLevel></Principal></Principals><Settings><MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><ExecutionTimeLimit>PT10M</ExecutionTimeLimit><Enabled>true</Enabled></Settings><Actions Context=\"CurrentUser\"><Exec><Command>${xml(opts.nodePath)}</Command><Arguments>${xml(argv.slice(1).map(quoteWindowsArgument).join(' '))}</Arguments></Exec></Actions></Task>\\n`;\n return { id, kind: 'windows-task', argv, files: [{ path: file, content, encoding: 'utf16le' }],\n query: command('powershell.exe', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(\n `$ErrorActionPreference = 'Stop'; try { $scheduler = New-Object -ComObject Schedule.Service; $scheduler.Connect(); $task = $scheduler.GetFolder('\\\\').GetTask('${id}'); $bytes = (New-Object System.Text.UTF8Encoding($false)).GetBytes($task.Xml); $stdout = [Console]::OpenStandardOutput(); $stdout.Write($bytes, 0, $bytes.Length); $stdout.Flush(); exit 0 } catch { exit 1 }`, 'utf16le').toString('base64')),\n inspect: command('powershell.exe', '-NoProfile', '-NonInteractive', '-Command',\n `try { $scheduler = New-Object -ComObject Schedule.Service; $scheduler.Connect(); $null = $scheduler.GetFolder('\\\\').GetTask('${id}'); exit 0 } catch { $failure = $_.Exception; while ($failure.InnerException) { $failure = $failure.InnerException }; if ($failure.HResult -eq -2147024894) { exit 3 }; exit 1 }`),\n install: [command('schtasks.exe', '/Create', '/TN', id, '/XML', file)],\n remove: [command('schtasks.exe', '/Delete', '/TN', id, '/F')], reload: [] };\n }\n throw Error('schedule_platform_unsupported');\n}\n\n/** Presence only; command failures are not a successful registration. */\nexport function nativeSchedulePresent(kind: NativeSyncSchedule['kind'], status: number, stdout: string): boolean {\n if (kind === 'systemd-user') {\n if (stdout.trim() === 'loaded') return true;\n if (stdout.trim() === 'not-found') return false;\n throw Error('schedule_inspection_failed');\n }\n if (status === 0) return true;\n if (kind === 'launchd-user' && status === 113) return false;\n // The fixed COM probe maps only HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)\n // to 3. Access denial/service errors must never mean an absent task.\n if (kind === 'windows-task' && status === 3) return false;\n throw Error('schedule_inspection_failed');\n}\n\n/** Compare the native readback without depending on locale-specific error text. */\nexport function nativeScheduleReadbackMatches(plan: NativeSyncSchedule, stdout: string): boolean {\n if (plan.kind !== 'windows-task') return true;\n try {\n const parser = new XMLParser({ ignoreAttributes: false, removeNSPrefix: true, trimValues: false, parseTagValue: false });\n const actual = parser.parse(stdout).Task;\n const expected = parser.parse(plan.files[0]!.content).Task;\n // Task Scheduler exports omit these schema defaults. Explicit changes still fail.\n // https://learn.microsoft.com/windows/win32/taskschd/task-scheduler-schema\n const defaulted = (value: unknown, fallback: string) => value === undefined ? fallback : value;\n const triggerFields = (task: typeof actual) => {\n const trigger = task.Triggers.CalendarTrigger;\n return [trigger.StartBoundary, defaulted(trigger.Enabled, 'true'), trigger.ScheduleByDay.DaysInterval,\n trigger.Repetition.Interval, trigger.Repetition.Duration, defaulted(trigger.Repetition.StopAtDurationEnd, 'false')];\n };\n const values = (task: typeof actual) => [task.Actions.Exec.Command, task.Actions.Exec.Arguments,\n ...triggerFields(task), task.Principals.Principal.LogonType, defaulted(task.Principals.Principal.RunLevel, 'LeastPrivilege'),\n task.Settings.MultipleInstancesPolicy, task.Settings.ExecutionTimeLimit, defaulted(task.Settings.Enabled, 'true')];\n return JSON.stringify(values(actual)) === JSON.stringify(values(expected));\n } catch { return false; }\n}\n\n/** systemd can load linked units before enabling their timer succeeds. */\nexport function nativeScheduleCanRecover(plan: NativeSyncSchedule, readback: () => boolean): boolean {\n return plan.kind === 'systemd-user' || readback();\n}\n"],"mappings":"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","names":["createHash","join","createHash","join"]}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __caveat_createRequire } from 'node:module';
3
+ const require = __caveat_createRequire(import.meta.url);
4
+
5
+ // src/privateEvidence/candidate.ts
6
+ function planOptionalEvidence(enabled, publicBytes, exitCode, prepare) {
7
+ if (enabled !== true) return { publicBytes, exitCode, privateCandidate: null, privateStatus: "off" };
8
+ try {
9
+ return { publicBytes, exitCode, privateCandidate: prepare(), privateStatus: "prepared" };
10
+ } catch {
11
+ return { publicBytes, exitCode, privateCandidate: null, privateStatus: "unverified" };
12
+ }
13
+ }
14
+ export {
15
+ planOptionalEvidence
16
+ };
17
+ //# sourceMappingURL=candidate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/privateEvidence/candidate.ts"],"sourcesContent":["/** Isolation-only planning boundary. No CLI import, transport, filesystem or delivery integration. */\nexport function planOptionalEvidence<T>(enabled: boolean, publicBytes: Uint8Array, exitCode: number,\n prepare: () => T): { publicBytes: Uint8Array; exitCode: number; privateCandidate: T | null; privateStatus: string } {\n if (enabled !== true) return { publicBytes, exitCode, privateCandidate: null, privateStatus: 'off' };\n try { return { publicBytes, exitCode, privateCandidate: prepare(), privateStatus: 'prepared' }; }\n catch { return { publicBytes, exitCode, privateCandidate: null, privateStatus: 'unverified' }; }\n}\n"],"mappings":";;;;;AACO,SAAS,qBAAwB,SAAkB,aAAyB,UACjF,SAAoH;AACpH,MAAI,YAAY,KAAM,QAAO,EAAE,aAAa,UAAU,kBAAkB,MAAM,eAAe,MAAM;AACnG,MAAI;AAAE,WAAO,EAAE,aAAa,UAAU,kBAAkB,QAAQ,GAAG,eAAe,WAAW;AAAA,EAAG,QAC1F;AAAE,WAAO,EAAE,aAAa,UAAU,kBAAkB,MAAM,eAAe,aAAa;AAAA,EAAG;AACjG;","names":[]}
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __caveat_createRequire } from 'node:module';
3
+ const require = __caveat_createRequire(import.meta.url);
4
+
5
+ // src/privateEvidence/origin.ts
6
+ import { createHash } from "node:crypto";
7
+ var ORIGIN_ALGORITHM = "origin-descriptor-sha256-v1";
8
+ var missing = (status, reason) => ({ status, algorithm: null, digest: null, reason });
9
+ function hasKnownCaptureState(input) {
10
+ return input.complete === true && (input.status === "observed" || input.status === "not_observed" || input.status === "unverified");
11
+ }
12
+ function projectOrigin(runId, input) {
13
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(runId) || input.run_id !== runId || !hasKnownCaptureState(input) || input.status === "unverified")
14
+ return missing("unverified", "origin_capture_unverified");
15
+ if (input.status === "not_observed") return missing("not_observed", "origin_not_reached");
16
+ if (typeof input.value !== "string") return missing("unverified", "origin_capture_unverified");
17
+ const text = input.value.replace(/\r?\n$/, "");
18
+ const unsupported = () => missing("unverified", "origin_syntax_unsupported");
19
+ if (!text || text.length > 4096 || /[^\x21-\x7e]|[%\\?#]/.test(text)) return unsupported();
20
+ let form;
21
+ let scheme = null;
22
+ let host;
23
+ let port = null;
24
+ let path;
25
+ if (text.includes("://")) {
26
+ const parsed = /^(https?|ssh|git):\/\/(?:[A-Za-z0-9._-]+@)?([^/:@]+)(?::([1-9][0-9]{0,4}))?(\/.*)$/i.exec(text);
27
+ if (!parsed) return unsupported();
28
+ form = "url";
29
+ scheme = parsed[1].toLowerCase();
30
+ host = parsed[2];
31
+ port = parsed[3] ?? null;
32
+ path = parsed[4];
33
+ if (port !== null && Number(port) > 65535) return unsupported();
34
+ } else {
35
+ const parsed = /^(?:[A-Za-z0-9._-]+@)?([^/:@]+):(.*)$/.exec(text);
36
+ if (!parsed) return unsupported();
37
+ if (!parsed[2].startsWith("/")) return missing("unverified", "origin_semantics_ambiguous");
38
+ form = "scp";
39
+ host = parsed[1];
40
+ path = parsed[2];
41
+ }
42
+ const labels = host.split(".");
43
+ if (host.length > 253 || labels.every((label) => /^[0-9]+$/.test(label)) || labels.some((label) => !/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/.test(label))) return unsupported();
44
+ if (!/^\/[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*\/?$/.test(path) || path.split("/").some((segment) => segment === "." || segment === "..")) return unsupported();
45
+ const tuple = ["caveat.origin-descriptor.v1", form, scheme, host.toLowerCase(), port, "absolute", path];
46
+ return {
47
+ status: "available",
48
+ algorithm: ORIGIN_ALGORITHM,
49
+ digest: createHash("sha256").update(JSON.stringify(tuple), "utf8").digest("hex"),
50
+ reason: "origin_descriptor_observed"
51
+ };
52
+ }
53
+ function projectHead(runId, input) {
54
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(runId) || input.run_id !== runId || !hasKnownCaptureState(input) || input.status === "unverified")
55
+ return { status: "unverified", value: null, reason: "head_capture_unverified" };
56
+ if (input.status === "not_observed") return { status: "not_observed", value: null, reason: "head_not_reached" };
57
+ if (typeof input.value !== "string" || !/^[0-9a-f]{40}$/.test(input.value))
58
+ return { status: "unverified", value: null, reason: "head_format_unsupported" };
59
+ return { status: "observed", value: input.value, reason: "head_observed" };
60
+ }
61
+ function projectSync(runId, acquired, publicSync) {
62
+ const local = projectHead(runId, acquired.local), remote = projectHead(runId, acquired.remote);
63
+ return {
64
+ ...publicSync,
65
+ repo_identity: projectOrigin(runId, acquired.origin),
66
+ local_head: local,
67
+ remote_head: remote,
68
+ comparison: local.status === "observed" && remote.status === "observed" ? local.value === remote.value ? "equal" : "different" : "not_evaluated",
69
+ relation_counts: { status: "not_supported", behind: null, ahead: null }
70
+ };
71
+ }
72
+ export {
73
+ ORIGIN_ALGORITHM,
74
+ projectHead,
75
+ projectOrigin,
76
+ projectSync
77
+ };
78
+ //# sourceMappingURL=origin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/privateEvidence/origin.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nexport const ORIGIN_ALGORITHM = 'origin-descriptor-sha256-v1';\nexport type OriginIdentity = {\n status: 'available' | 'not_observed' | 'unverified';\n algorithm: typeof ORIGIN_ALGORITHM | null;\n digest: string | null;\n reason: string;\n};\nexport type AcquiredValue = {\n run_id: string;\n status: 'observed' | 'not_observed' | 'unverified';\n value: string | null;\n complete: boolean;\n};\nconst missing = (status: 'not_observed' | 'unverified', reason: string): OriginIdentity =>\n ({ status, algorithm: null, digest: null, reason });\n\nfunction hasKnownCaptureState(input: AcquiredValue): boolean {\n return input.complete === true &&\n (input.status === 'observed' || input.status === 'not_observed' || input.status === 'unverified');\n}\n\n/** Input is an already acquired value; never queries Git, config, DNS, files or state. */\nexport function projectOrigin(runId: string, input: AcquiredValue): OriginIdentity {\n if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(runId) || input.run_id !== runId || !hasKnownCaptureState(input) || input.status === 'unverified')\n return missing('unverified', 'origin_capture_unverified');\n if (input.status === 'not_observed') return missing('not_observed', 'origin_not_reached');\n if (typeof input.value !== 'string') return missing('unverified', 'origin_capture_unverified');\n const text = input.value.replace(/\\r?\\n$/, '');\n const unsupported = () => missing('unverified', 'origin_syntax_unsupported');\n if (!text || text.length > 4096 || /[^\\x21-\\x7e]|[%\\\\?#]/.test(text)) return unsupported();\n let form: 'url' | 'scp';\n let scheme: string | null = null;\n let host: string;\n let port: string | null = null;\n let path: string;\n if (text.includes('://')) {\n const parsed = /^(https?|ssh|git):\\/\\/(?:[A-Za-z0-9._-]+@)?([^/:@]+)(?::([1-9][0-9]{0,4}))?(\\/.*)$/i.exec(text);\n if (!parsed) return unsupported();\n form = 'url'; scheme = parsed[1]!.toLowerCase(); host = parsed[2]!; port = parsed[3] ?? null; path = parsed[4]!;\n if (port !== null && Number(port) > 65535) return unsupported();\n } else {\n const parsed = /^(?:[A-Za-z0-9._-]+@)?([^/:@]+):(.*)$/.exec(text);\n if (!parsed) return unsupported();\n if (!parsed[2]!.startsWith('/')) return missing('unverified', 'origin_semantics_ambiguous');\n form = 'scp'; host = parsed[1]!; path = parsed[2]!;\n }\n const labels = host.split('.');\n if (host.length > 253 || labels.every(label => /^[0-9]+$/.test(label)) ||\n labels.some(label => !/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/.test(label))) return unsupported();\n if (!/^\\/[A-Za-z0-9._-]+(?:\\/[A-Za-z0-9._-]+)*\\/?$/.test(path) ||\n path.split('/').some(segment => segment === '.' || segment === '..')) return unsupported();\n const tuple = ['caveat.origin-descriptor.v1', form, scheme, host.toLowerCase(), port, 'absolute', path];\n return { status: 'available', algorithm: ORIGIN_ALGORITHM,\n digest: createHash('sha256').update(JSON.stringify(tuple), 'utf8').digest('hex'), reason: 'origin_descriptor_observed' };\n}\n\nexport function projectHead(runId: string, input: AcquiredValue) {\n if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(runId) || input.run_id !== runId || !hasKnownCaptureState(input) || input.status === 'unverified')\n return { status: 'unverified', value: null, reason: 'head_capture_unverified' } as const;\n if (input.status === 'not_observed') return { status: 'not_observed', value: null, reason: 'head_not_reached' } as const;\n if (typeof input.value !== 'string' || !/^[0-9a-f]{40}$/.test(input.value))\n return { status: 'unverified', value: null, reason: 'head_format_unsupported' } as const;\n return { status: 'observed', value: input.value, reason: 'head_observed' } as const;\n}\n\nexport function projectSync(runId: string, acquired: {\n origin: AcquiredValue; local: AcquiredValue; remote: AcquiredValue;\n}, publicSync: { status: 'ready' | 'not_ready' | 'unverified'; reason_code: string }) {\n const local = projectHead(runId, acquired.local), remote = projectHead(runId, acquired.remote);\n return { ...publicSync, repo_identity: projectOrigin(runId, acquired.origin), local_head: local, remote_head: remote,\n comparison: local.status === 'observed' && remote.status === 'observed'\n ? local.value === remote.value ? 'equal' : 'different' : 'not_evaluated',\n relation_counts: { status: 'not_supported', behind: null, ahead: null } };\n}\n"],"mappings":"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","names":[]}