Files
orca/src/shared/pty-consumer-session.test.ts
T
JinjingandOrcaWin 5f7807497e feat(ssh): bound relay PTY output end to end (#11005)
* docs: design SSH relay PTY backpressure

* fix(ssh): bound relay frame decoding

* fix(relay): bound PTY output publication

* fix(ssh): bound PTY model admission

* fix(ssh): settle closed model admissions

* feat(ssh): negotiate bounded PTY consumer sessions

* fix(ssh): fence exit on renderer settlement

* feat(ssh): track PTY source credit end to end

* fix(ssh): recover bounded PTY output across reconnect

* feat(ssh): complete relay PTY output backpressure

* fix(ssh): close final PTY source credit races

* docs(ssh): record final backpressure validation

* feat(ssh): complete relay PTY source-credit lifecycle

* test(ssh): complete provider notification fixture

* fix(ssh): preserve terminal source credit across rotation

* fix(ssh): fail closed on recovery cancellation

* fix(ssh): prioritize mux control writes after drain

* fix(ssh): retire canceled relay restore deliveries

* fix(ssh): order exit cancellation cleanup

* fix(ssh): gate provisional source activation

* test(ssh): register mux drain-priority coverage

* fix(ssh): type stale owner recovery mismatches

* fix(ssh): close projection replacement races

* fix(relay): contain streaming edge failures

* fix(ssh): secure relay endpoint credentials

* docs(ssh): reconcile final backpressure lifecycle

* fix(ssh): bound main IPC output lifecycle

* fix(ssh): close recovery ownership gaps

* docs(ssh): record exact artifact validation

* fix(ssh): reject reclaimed snapshot replacements

* fix(ssh): fence model admission across reconnect

* fix(ssh): contain migration failure per PTY

* docs(ssh): record final exact-head validation

* test(ssh): align deploy fixtures with credential publication

* feat(ssh): add per-target bounded output setting

* fix(ssh): close source recovery review gaps

* fix(ssh): latch source credit environment override

* feat(ssh): make PTY source credit the default

* docs(ssh): record always-on relay validation

* docs(ssh): bind validation to current main

* test(ssh): grant source credit in IPC fixture

* test(ssh): grant source credit in fake relay

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-29 17:03:15 -07:00

282 lines
8.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
PTY_CONSUMER_STALE_OWNER_RECOVERY_ERROR,
PtyConsumerSession,
type PtyConsumerAuthentication,
type PtyConsumerSessionHello
} from './pty-consumer-session'
function auth(
connectionId: string,
overrides: Partial<PtyConsumerAuthentication> = {}
): PtyConsumerAuthentication {
return {
connectionId,
principal: 'desktop',
authenticated: true,
allowSessionOwner: true,
...overrides
}
}
function ownerHello(overrides: Partial<PtyConsumerSessionHello> = {}): PtyConsumerSessionHello {
return {
clientInstanceId: 'client-a',
requestedRole: 'session-owner',
...overrides
}
}
function createSession(options: { now?: () => number } = {}): PtyConsumerSession {
let lease = 0
return new PtyConsumerSession({
serverBuildId: 'relay-build',
createLease: () => `lease-${++lease}`,
ownerGraceMs: 30_000,
...options
})
}
describe('PtyConsumerSession', () => {
it('types a resume against a fresh relay without weakening other owner refusals', () => {
const session = createSession()
expect(() =>
session.admit(
ownerHello({ resume: { ownerGeneration: 1, ownerLease: 'stale' } }),
auth('connection-1')
)
).toThrow(
expect.objectContaining({
code: PTY_CONSUMER_STALE_OWNER_RECOVERY_ERROR,
message: expect.stringContaining('stale')
})
)
})
it('activates an authenticated owner only after its publication fence', () => {
const session = createSession()
const first = session.admit(ownerHello(), auth('connection-1'))
const competitor = session.admit(
ownerHello({ clientInstanceId: 'client-b' }),
auth('connection-2', { principal: 'other' })
)
expect(first.grant).toMatchObject({
clientGeneration: 1,
role: 'session-owner',
ownerGeneration: 1,
ownerLease: 'lease-1'
})
expect(competitor.grant).toMatchObject({ clientGeneration: 2, role: 'subscriber' })
first.commitPublication()
})
it('rolls back an unpublished owner without consuming authority', () => {
const session = createSession()
session.admit(ownerHello(), auth('failed')).rollbackPublication()
const retry = session.admit(ownerHello(), auth('retry'))
expect(retry.grant).toMatchObject({
role: 'session-owner',
ownerGeneration: 2,
ownerLease: 'lease-2'
})
})
it('returns the same generation and lease for duplicate opens on one connection', () => {
const session = createSession()
const first = session.admit(ownerHello(), auth('connection-1'))
const duplicate = session.admit(ownerHello(), auth('connection-1'))
expect(duplicate.grant).toBe(first.grant)
first.commitPublication()
duplicate.commitPublication()
})
it('rejects a second, different open on one connection', () => {
const session = createSession()
session.admit(ownerHello(), auth('connection-1'))
expect(() =>
session.admit(ownerHello({ requestedRole: 'subscriber' }), auth('connection-1'))
).toThrow('only once')
})
it('cannot self-promote an authenticated but owner-ineligible principal', () => {
const session = createSession()
const admission = session.admit(
ownerHello(),
auth('connection-1', { allowSessionOwner: false })
)
expect(admission.grant.role).toBe('subscriber')
expect(admission.grant.ownerLease).toBeUndefined()
})
it('rejects an unauthenticated transport', () => {
const session = createSession()
expect(() =>
session.admit(ownerHello(), auth('connection-1', { authenticated: false }))
).toThrow('authentication required')
})
it('rotates the lease and increments owner generation on valid recovery', () => {
const session = createSession()
const first = session.admit(ownerHello(), auth('connection-1'))
first.commitPublication()
session.close('connection-1')
const recovered = session.admit(
ownerHello({
resume: {
ownerGeneration: first.grant.ownerGeneration!,
ownerLease: first.grant.ownerLease!
}
}),
auth('connection-2')
)
recovered.commitPublication()
expect(recovered.grant).toMatchObject({
role: 'session-owner',
ownerGeneration: 2,
ownerLease: 'lease-2'
})
})
it('rejects recovery while the current owner is still active', () => {
const session = createSession()
const first = session.admit(ownerHello(), auth('connection-1'))
first.commitPublication()
expect(() =>
session.admit(
ownerHello({
resume: {
ownerGeneration: first.grant.ownerGeneration!,
ownerLease: first.grant.ownerLease!
}
}),
auth('connection-2')
)
).toThrow('Active owner')
})
it('types mismatched recovery without disturbing principal or lease ownership', () => {
const session = createSession()
const first = session.admit(ownerHello(), auth('connection-1'))
first.commitPublication()
session.close('connection-1')
expect(() =>
session.admit(
ownerHello({ resume: { ownerGeneration: 1, ownerLease: 'lease-1' } }),
auth('connection-2', { principal: 'stale-desktop' })
)
).toThrow(
expect.objectContaining({
code: PTY_CONSUMER_STALE_OWNER_RECOVERY_ERROR,
message: expect.stringContaining('principal')
})
)
expect(() =>
session.admit(
ownerHello({ resume: { ownerGeneration: 1, ownerLease: 'wrong' } }),
auth('connection-3')
)
).toThrow(expect.objectContaining({ code: PTY_CONSUMER_STALE_OWNER_RECOVERY_ERROR }))
const staleFresh = session.admit(
ownerHello(),
auth('connection-2', { principal: 'stale-desktop' })
)
expect(staleFresh.grant).toMatchObject({ role: 'subscriber' })
expect(staleFresh.grant.ownerLease).toBeUndefined()
const recovered = session.admit(
ownerHello({ resume: { ownerGeneration: 1, ownerLease: 'lease-1' } }),
auth('connection-4')
)
expect(recovered.grant).toMatchObject({
role: 'session-owner',
ownerGeneration: 2,
ownerLease: 'lease-2'
})
})
it('elects a new owner after disconnected-owner grace expires', () => {
let now = 10
const session = createSession({ now: () => now })
const first = session.admit(ownerHello(), auth('connection-1'))
first.commitPublication()
session.close('connection-1')
now += 30_000
const next = session.admit(
ownerHello({ clientInstanceId: 'client-b' }),
auth('connection-2', { principal: 'other' })
)
expect(next.grant).toMatchObject({ role: 'session-owner', ownerGeneration: 2 })
})
it('intersects V1 capability and clamps its source-unit window', () => {
const session = new PtyConsumerSession({
serverBuildId: 'relay-build',
outputFlowControl: { versions: [1], maxWindowSu: 64 },
createLease: () => 'lease'
})
const admission = session.admit(
ownerHello({
capabilities: {
outputFlowControl: { versions: [1, 2], requestedWindowSu: 128 }
}
}),
auth('connection-1')
)
expect(admission.grant.capabilities?.outputFlowControl).toEqual({
version: 1,
windowSu: 64
})
})
it('makes token-free bounded legacy an explicit capability omission', () => {
const session = createSession()
const admission = session.admit(ownerHello(), auth('connection-1'))
expect(admission.grant.capabilities).toBeUndefined()
expect(admission.grant).not.toHaveProperty('deliveryToken')
})
it('bounds capability offers before fingerprinting them', () => {
const session = createSession()
expect(() =>
session.admit(
ownerHello({
capabilities: {
outputFlowControl: {
versions: Array.from({ length: 9 }, (_, index) => index + 1),
requestedWindowSu: 64
}
}
}),
auth('connection-1')
)
).toThrow('versions')
})
it('rejects invalid server windows and owner grace', () => {
expect(
() =>
new PtyConsumerSession({
serverBuildId: 'build',
outputFlowControl: { versions: [1], maxWindowSu: 0 }
})
).toThrow('support')
expect(
() => new PtyConsumerSession({ serverBuildId: 'build', ownerGraceMs: Number.MAX_VALUE })
).toThrow('ownerGraceMs')
})
})