mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 08:37:49 +00:00
* Revert "Keep same-machine folders with matching Git remotes in separate projects (#32272)"
This reverts commit 29a5f89b8a.
On a machine with several clones of one repo, #32272 moved the oldest clone
into the shared cross-host project. Shared Windows QA machines have several
orca clones, so everyone's sidebar "orca" project suddenly gained that
machine's main checkout and its worktrees. Revert until the intended
grouping is decided.
Conflicts resolved against later main: Settings files moved into
settings/repository (imports adjusted), and two test files later deleted on
main stay deleted.
* Use checked types in restored test fixtures
* Combine restored fixture type imports
138 lines
5.5 KiB
TypeScript
138 lines
5.5 KiB
TypeScript
import { mkdtempSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import nacl from 'tweetnacl'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
import { encodeDeviceProofMessage } from '../../shared/device-key-proof'
|
|
import { devicePrincipalOf } from './device-principal'
|
|
import { DeviceRegistry } from './device-registry'
|
|
import type { OrcaRuntimeService } from './orca-runtime'
|
|
import { OrcaRuntimeRpcServer } from './runtime-rpc'
|
|
import type { AuthenticatedMobileSocket } from './rpc/mobile-socket-wiring'
|
|
|
|
function keyedServer() {
|
|
const userDataPath = mkdtempSync(join(tmpdir(), 'orca-device-key-dispatch-'))
|
|
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: status.get only reads these three members.
|
|
const runtime = {
|
|
configureNotificationDismissalStore: () => {},
|
|
getRuntimeId: () => 'test-runtime',
|
|
getStatus: vi.fn().mockResolvedValue({ graphStatus: 'ok' })
|
|
} as unknown as OrcaRuntimeService
|
|
const server = new OrcaRuntimeRpcServer({ runtime, userDataPath, enableWebSocket: false })
|
|
const registry = new DeviceRegistry(userDataPath)
|
|
server['deviceRegistry'] = registry
|
|
const legacy = registry.addDevice('Laptop', 'runtime')
|
|
const keyed = registry.forkDeviceKey(
|
|
legacy.deviceId,
|
|
Buffer.alloc(32, 5).toString('base64'),
|
|
'Mac'
|
|
)
|
|
const socket: AuthenticatedMobileSocket = {
|
|
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: dispatch only uses ws as a map key for abort registration.
|
|
ws: {} as AuthenticatedMobileSocket['ws'],
|
|
connectionId: 'connection-1',
|
|
transcriptHashB64: Buffer.alloc(32).toString('base64'),
|
|
device: devicePrincipalOf(keyed),
|
|
clientCapabilities: [],
|
|
transport: { transport: 'direct' }
|
|
}
|
|
const send = async (request: Record<string, unknown>) => {
|
|
const replies: string[] = []
|
|
await server['handleWebSocketMessage'](
|
|
JSON.stringify(request),
|
|
(response) => replies.push(response),
|
|
() => {},
|
|
undefined,
|
|
undefined,
|
|
null,
|
|
socket
|
|
)
|
|
const reply: unknown = JSON.parse(replies.at(-1)!)
|
|
return reply
|
|
}
|
|
return { server, registry, keyed, legacy, send }
|
|
}
|
|
|
|
describe('requests on a key-authenticated socket', () => {
|
|
it('dispatch with the device id as client id and no token', async () => {
|
|
const { server, keyed, send } = keyedServer()
|
|
const dispatch = vi.spyOn(server['dispatcher'], 'dispatchStreaming')
|
|
const reply = await send({ id: 'r1', method: 'status.get' })
|
|
expect(reply).not.toMatchObject({ error: { code: 'unauthorized' } })
|
|
expect(dispatch.mock.calls[0]?.[2]).toMatchObject({
|
|
clientId: keyed.deviceId,
|
|
pairedDeviceId: keyed.deviceId
|
|
})
|
|
})
|
|
|
|
it('refuses a request that carries any token, and every request once the row is revoked', async () => {
|
|
const { registry, keyed, legacy, send } = keyedServer()
|
|
expect(await send({ id: 'r1', method: 'status.get', deviceToken: legacy.token })).toMatchObject(
|
|
{
|
|
ok: false,
|
|
error: { code: 'unauthorized' }
|
|
}
|
|
)
|
|
registry.removeDevice(keyed.deviceId)
|
|
expect(await send({ id: 'r2', method: 'status.get' })).toMatchObject({
|
|
ok: false,
|
|
error: { code: 'unauthorized' }
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('pairing.registerDeviceKey over the dispatcher', () => {
|
|
it.each(['runtime', 'mobile'] as const)(
|
|
'forks a %s token row bound to the calling socket',
|
|
async (scope) => {
|
|
const userDataPath = mkdtempSync(join(tmpdir(), 'orca-device-key-register-'))
|
|
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: registration never touches the runtime service.
|
|
const runtime = {
|
|
configureNotificationDismissalStore: () => {},
|
|
getRuntimeId: () => 'test-runtime'
|
|
} as unknown as OrcaRuntimeService
|
|
const server = new OrcaRuntimeRpcServer({ runtime, userDataPath, enableWebSocket: false })
|
|
const registry = new DeviceRegistry(userDataPath)
|
|
server['deviceRegistry'] = registry
|
|
const legacy = registry.addDevice('Device', scope)
|
|
const transcriptHashB64 = Buffer.alloc(32, 9).toString('base64')
|
|
const key = nacl.sign.keyPair()
|
|
const proof = nacl.sign.detached(
|
|
encodeDeviceProofMessage('register', Buffer.from(transcriptHashB64, 'base64')),
|
|
key.secretKey
|
|
)
|
|
const replies: string[] = []
|
|
await server['handleWebSocketMessage'](
|
|
JSON.stringify({
|
|
id: 'register',
|
|
method: 'pairing.registerDeviceKey',
|
|
params: {
|
|
devicePublicKeyB64: Buffer.from(key.publicKey).toString('base64'),
|
|
deviceProofB64: Buffer.from(proof).toString('base64'),
|
|
deviceLabel: 'Laptop'
|
|
}
|
|
}),
|
|
(response) => replies.push(response),
|
|
() => {},
|
|
undefined,
|
|
undefined,
|
|
legacy.token,
|
|
{
|
|
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: dispatch only uses ws as a map key for abort registration.
|
|
ws: {} as AuthenticatedMobileSocket['ws'],
|
|
connectionId: 'connection-1',
|
|
transcriptHashB64,
|
|
device: { ...devicePrincipalOf(legacy), deviceToken: legacy.token },
|
|
clientCapabilities: [],
|
|
transport: { transport: 'direct' }
|
|
}
|
|
)
|
|
const reply: unknown = JSON.parse(replies.at(-1)!)
|
|
expect(reply).toMatchObject({ id: 'register', ok: true, result: { credentialRevision: 0 } })
|
|
expect(
|
|
registry.listDevices().filter((row) => row.forkedFrom === legacy.deviceId)
|
|
).toHaveLength(1)
|
|
}
|
|
)
|
|
})
|