Files
orca/src/main/daemon/daemon-incarnation-evidence.test.ts
T
mirror 34fa2cd5ca
Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
source snapshot 2026-09-02
2026-09-02 02:03:16 +08:00

403 lines
13 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import {
DAEMON_GONE_PROOFS,
probeDaemonProcessIdentity,
WINDOWS_CREATION_TIME_TOLERANCE_MS,
type DaemonProcessProbeDependencies,
type ExactDaemonIncarnation
} from './daemon-incarnation-evidence'
import {
classifyDaemonAuditFailure,
recordAuthenticatedInventory,
type DaemonAuditClassifierDependencies,
type DaemonAuditContext
} from './daemon-audit-classifier'
const endpoint = { socketPath: '/runtime/daemon.sock', tokenPath: '/runtime/daemon.token' }
const exactIncarnation: ExactDaemonIncarnation = {
identity: { pid: 42, startedAtMs: 1_700_000_000_000, launchNonce: 'launch-a' },
linuxStartTicks: '4242',
bootId: 'boot-a'
}
const auditClassifierDependencies = {
probeProcessIdentity: async () => ({
state: 'unknown',
reason: 'inspection_failed',
evidenceSources: ['process_signal']
}),
inspectEndpointState: async (context) =>
context.endpointKind === 'windows-named-pipe' ? 'named-pipe' : 'missing'
} satisfies DaemonAuditClassifierDependencies
function linuxStat(state: string, startTicks: string): string {
return `42 (orca daemon with spaces) ${[state, ...Array(18).fill('0'), startTicks].join(' ')}`
}
function linuxDependencies(
overrides: DaemonProcessProbeDependencies = {}
): DaemonProcessProbeDependencies {
return {
platform: 'linux',
signalProcess: () => 'occupied',
readLinuxStat: async () => ({ status: 'present', value: linuxStat('S', '4242') }),
readBootIdentity: async () => 'boot-a',
readCommandLine: async () =>
`node daemon-entry --socket ${endpoint.socketPath} --token ${endpoint.tokenPath}`,
...overrides
}
}
describe('daemon process identity evidence', () => {
it('pins the dated conclusive-gone oracle contract', () => {
expect(DAEMON_GONE_PROOFS).toEqual({
linux: ['pid_missing', 'linux_boot_changed', 'linux_start_ticks_mismatch', 'linux_zombie'],
darwin: ['pid_missing'],
win32: [
'windows_process_missing',
'windows_creation_time_mismatch',
'windows_named_pipe_missing'
]
})
})
it('proves Linux pid reuse from native start ticks without derived milliseconds', async () => {
const readProcessStartedAtMs = vi.fn(async () => exactIncarnation.identity.startedAtMs)
await expect(
probeDaemonProcessIdentity(
exactIncarnation,
endpoint,
linuxDependencies({
readLinuxStat: async () => ({ status: 'present', value: linuxStat('S', '4243') }),
readProcessStartedAtMs
})
)
).resolves.toMatchObject({
state: 'gone',
reason: 'linux_start_ticks_mismatch'
})
expect(readProcessStartedAtMs).not.toHaveBeenCalled()
})
it('proves Linux reboot invalidated the recorded incarnation', async () => {
await expect(
probeDaemonProcessIdentity(
exactIncarnation,
endpoint,
linuxDependencies({ readBootIdentity: async () => 'boot-b' })
)
).resolves.toMatchObject({ state: 'gone', reason: 'linux_boot_changed' })
})
it('treats a matching unreaped Linux zombie as gone', async () => {
await expect(
probeDaemonProcessIdentity(
exactIncarnation,
endpoint,
linuxDependencies({
readLinuxStat: async () => ({ status: 'present', value: linuxStat('Z', '4242') })
})
)
).resolves.toMatchObject({ state: 'gone', reason: 'linux_zombie' })
})
it('keeps EPERM unknown without an independent identity match', async () => {
await expect(
probeDaemonProcessIdentity(
exactIncarnation,
endpoint,
linuxDependencies({
signalProcess: () => 'permission_denied',
readLinuxStat: async () => ({ status: 'unavailable' })
})
)
).resolves.toMatchObject({ state: 'unknown', reason: 'permission_denied' })
})
it('keeps a missing proc stat unknown when signal zero still sees the pid', async () => {
await expect(
probeDaemonProcessIdentity(
exactIncarnation,
endpoint,
linuxDependencies({
readLinuxStat: async () => ({ status: 'missing' })
})
)
).resolves.toMatchObject({ state: 'unknown', reason: 'inspection_failed' })
})
it('keeps an unreadable command line unknown even when Linux start identity matches', async () => {
await expect(
probeDaemonProcessIdentity(
exactIncarnation,
endpoint,
linuxDependencies({ readCommandLine: async () => undefined })
)
).resolves.toMatchObject({ state: 'unknown', reason: 'command_line_unavailable' })
})
it('never treats signal-zero success alone as present', async () => {
await expect(
probeDaemonProcessIdentity(
{ identity: exactIncarnation.identity },
endpoint,
linuxDependencies({
readCommandLine: async () => undefined
})
)
).resolves.toMatchObject({ state: 'unknown' })
})
it('never turns a legacy identity gap into gone', async () => {
await expect(
probeDaemonProcessIdentity(null, endpoint, linuxDependencies())
).resolves.toMatchObject({ state: 'unknown', reason: 'exact_identity_unavailable' })
})
it('uses Windows CreationDate as the primary identity regardless of command line', async () => {
const base = {
platform: 'win32' as const,
signalProcess: () => 'occupied' as const
}
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
...base,
queryWindowsProcess: async () => ({
status: 'present',
commandLine: 'unreadable',
startedAtMs:
exactIncarnation.identity.startedAtMs + WINDOWS_CREATION_TIME_TOLERANCE_MS + 1
})
})
).resolves.toMatchObject({
state: 'gone',
reason: 'windows_creation_time_mismatch'
})
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
...base,
queryWindowsProcess: async () => ({
status: 'present',
commandLine: null,
startedAtMs: exactIncarnation.identity.startedAtMs
})
})
).resolves.toMatchObject({
state: 'present',
reason: 'windows_identity_match'
})
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
...base,
queryWindowsProcess: async () => ({
status: 'present',
commandLine: 'unrelated process',
startedAtMs: exactIncarnation.identity.startedAtMs
})
})
).resolves.toMatchObject({
state: 'present',
reason: 'windows_identity_match'
})
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
...base,
queryWindowsProcess: async () => ({
status: 'present',
commandLine: 'node daemon-entry',
startedAtMs: null
})
})
).resolves.toMatchObject({
state: 'unknown',
reason: 'windows_process_start_time_unavailable'
})
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
...base,
queryWindowsProcess: async () => ({ status: 'missing' })
})
).resolves.toMatchObject({
state: 'gone',
reason: 'windows_process_missing'
})
})
it('requires Windows CIM evidence even when signal-zero reports a missing pid', async () => {
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
platform: 'win32',
signalProcess: () => 'missing',
queryWindowsProcess: async () => ({
status: 'present',
commandLine: null,
startedAtMs: exactIncarnation.identity.startedAtMs
})
})
).resolves.toMatchObject({
state: 'present',
reason: 'windows_identity_match'
})
})
it('keeps a macOS lstart mismatch unknown', async () => {
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
platform: 'darwin',
signalProcess: () => 'occupied',
readCommandLine: async () =>
`node daemon-entry --socket ${endpoint.socketPath} --token ${endpoint.tokenPath}`,
readProcessStartedAtMs: async () => exactIncarnation.identity.startedAtMs + 2_500
})
).resolves.toMatchObject({ state: 'unknown', reason: 'macos_start_time_mismatch' })
})
it('accepts ESRCH as conclusive POSIX process disappearance', async () => {
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
platform: 'darwin',
signalProcess: () => 'missing'
})
).resolves.toMatchObject({ state: 'gone', reason: 'pid_missing' })
})
it('keeps unsupported platforms indeterminate without running a Darwin probe', async () => {
const signalProcess = vi.fn(() => 'occupied' as const)
const readCommandLine = vi.fn(async () => 'node daemon-entry')
await expect(
probeDaemonProcessIdentity(exactIncarnation, endpoint, {
platform: 'freebsd',
signalProcess,
readCommandLine
})
).resolves.toMatchObject({ state: 'unknown', reason: 'inspection_failed' })
expect(signalProcess).not.toHaveBeenCalled()
expect(readCommandLine).not.toHaveBeenCalled()
})
})
describe('daemon audit availability evidence', () => {
const context: DaemonAuditContext = {
protocolGeneration: 23,
provider: 'local-daemon',
endpoint: endpoint.socketPath,
tokenPath: endpoint.tokenPath,
endpointKind: 'unix-socket',
profileScope: '/profile'
}
it('records authoritative inventory as present without endpoint identity', () => {
expect(recordAuthenticatedInventory(context, null)).toMatchObject({
state: 'present',
reason: 'authenticated_inventory',
exactIncarnation: null,
inventoryAuthority: 'authoritative'
})
})
it('represents failed legacy inventory as unknown, never an empty process list', async () => {
const observation = await classifyDaemonAuditFailure(context, 'inventory_failed', null, {
dependencies: auditClassifierDependencies
})
expect(observation).toMatchObject({
state: 'unknown',
reason: 'inventory_failed',
inventoryAuthority: 'unavailable',
processLiveness: 'unknown'
})
expect(observation.evidenceSources.length).toBeGreaterThan(0)
expect(observation).not.toHaveProperty('processes')
})
it('keeps token removal after disconnect as contributing evidence only', async () => {
const observation = await classifyDaemonAuditFailure(
context,
'token_missing_after_authenticated_disconnect',
null,
{
additionalEvidenceSources: ['token_file'],
dependencies: auditClassifierDependencies
}
)
expect(observation.state).toBe('unknown')
expect(observation.evidenceSources).toContain('token_file')
})
it('accepts Windows named-pipe absence only with exact incarnation evidence', async () => {
const windowsContext: DaemonAuditContext = {
...context,
endpoint: '\\\\?\\pipe\\orca-daemon',
endpointKind: 'windows-named-pipe'
}
const observation = await classifyDaemonAuditFailure(
windowsContext,
'inventory_failed',
exactIncarnation,
{
additionalEvidenceSources: ['windows_named_pipe'],
endpointGoneProof: 'windows_named_pipe_missing',
dependencies: auditClassifierDependencies
}
)
expect(observation).toMatchObject({
state: 'gone',
reason: 'windows_named_pipe_missing',
endpointState: 'missing',
exactIncarnation
})
})
it('keeps contradictory Windows pipe and process evidence unknown', async () => {
const windowsContext: DaemonAuditContext = {
...context,
endpoint: '\\\\?\\pipe\\orca-daemon',
endpointKind: 'windows-named-pipe'
}
const dependencies = {
...auditClassifierDependencies,
probeProcessIdentity: async () => ({
state: 'present',
reason: 'windows_identity_match',
evidenceSources: ['windows_cim', 'endpoint_identity']
})
} satisfies DaemonAuditClassifierDependencies
await expect(
classifyDaemonAuditFailure(windowsContext, 'inventory_failed', exactIncarnation, {
additionalEvidenceSources: ['windows_named_pipe'],
endpointGoneProof: 'windows_named_pipe_missing',
dependencies
})
).resolves.toMatchObject({
state: 'unknown',
reason: 'inventory_failed',
processLiveness: 'present',
processReason: 'windows_identity_match',
endpointState: 'missing'
})
})
it('rejects named-pipe disappearance as a gone proof for Unix endpoints', async () => {
const observation = await classifyDaemonAuditFailure(
context,
'inventory_failed',
exactIncarnation,
{
additionalEvidenceSources: ['windows_named_pipe'],
endpointGoneProof: 'windows_named_pipe_missing',
dependencies: auditClassifierDependencies
}
)
expect(observation).toMatchObject({
state: 'unknown',
reason: 'inventory_failed',
processLiveness: 'unknown'
})
})
})