mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-09 04:02:35 +00:00
Some credentials cannot be configured, only obtained: getting one means a conversation — open this page, paste that code, pick an account. The new seam owns that conversation and the one-attempt-per-key lifecycle, and never the protocol, so a second authorization protocol arrives as another flow rather than as another seam. A flow is registered under the CredentialKey it writes, which is also how the seam knows which plugin answers for the format inside that record. The flow owns the write: run() resolving means the record is already committed through ctx.credentials, and the seam confirms it. That keeps a library persisting through its own store adapter the single writer instead of being copied back out and written twice. The interaction travels with the request rather than a registry, because whoever starts an authorization is the one who can talk to the human about it. A request already withdrawn never claims the key and never starts the flow — relying on each flow to check its signal before the first await would let one that does not hang holding the key.
88 lines
3.1 KiB
TypeScript
88 lines
3.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { Context } from '@deepseek-ai/cordis'
|
|
import { credentialKey } from '@deepseek-ai/dsh-credentials'
|
|
import InvariantRegistry from '@deepseek-ai/dsh-invariants'
|
|
import AuthorizationService from '@deepseek-ai/dsh-authorization'
|
|
import * as AuthorizationInvariant from '../src/invariant.ts'
|
|
import { MemoryCredentials } from './memory.ts'
|
|
|
|
const KEY = credentialKey('llm-pi-ai', 'openai-codex')
|
|
|
|
describe('authorization invariant companion', () => {
|
|
it('accepts an attempt that released its key before settling', async () => {
|
|
const ctx = new Context()
|
|
await ctx.plugin(InvariantRegistry)
|
|
await ctx.plugin(AuthorizationInvariant)
|
|
await ctx.plugin(MemoryCredentials)
|
|
await ctx.plugin(AuthorizationService)
|
|
ctx.authorization.registerFlow({
|
|
key: KEY,
|
|
label: 'ChatGPT (Codex)',
|
|
methods: [{ id: 'oauth', label: 'Sign in' }],
|
|
run: () => ctx.credentials
|
|
.modifyRecord(KEY, () => Promise.resolve({ kind: 'grant', payload: {} }))
|
|
.then(() => undefined),
|
|
})
|
|
|
|
await expect(ctx.authorization.begin({
|
|
key: KEY,
|
|
interaction: { notify: () => {}, prompt: () => Promise.reject(new Error('unused')) },
|
|
})).resolves.toEqual({ status: 'authorized' })
|
|
})
|
|
|
|
it('fails a settlement that left its key in flight', async () => {
|
|
const ctx = new Context()
|
|
await ctx.plugin(InvariantRegistry)
|
|
await ctx.plugin(AuthorizationInvariant)
|
|
await ctx.plugin(MemoryCredentials)
|
|
await ctx.plugin(AuthorizationService)
|
|
const started = Promise.withResolvers<undefined>()
|
|
ctx.authorization.registerFlow({
|
|
key: KEY,
|
|
label: 'ChatGPT (Codex)',
|
|
methods: [{ id: 'oauth', label: 'Sign in' }],
|
|
run: () => {
|
|
started.resolve(undefined)
|
|
return new Promise(() => {})
|
|
},
|
|
})
|
|
void ctx.authorization.begin({
|
|
key: KEY,
|
|
interaction: { notify: () => {}, prompt: () => Promise.reject(new Error('unused')) },
|
|
})
|
|
await started.promise
|
|
|
|
expect(() => { ctx.emit('authorization/settled', KEY, 'authorized') })
|
|
.toThrow(/left the key in flight/)
|
|
})
|
|
|
|
it('fails a settlement emitted without a live service', async () => {
|
|
const ctx = new Context()
|
|
await ctx.plugin(InvariantRegistry)
|
|
await ctx.plugin(AuthorizationInvariant)
|
|
|
|
expect(() => { ctx.emit('authorization/settled', KEY, 'cancelled') })
|
|
.toThrow(/without a live authorization service/)
|
|
})
|
|
|
|
it('accepts a settlement whose flow left during its own attempt', async () => {
|
|
const ctx = new Context()
|
|
await ctx.plugin(InvariantRegistry)
|
|
await ctx.plugin(AuthorizationInvariant)
|
|
await ctx.plugin(MemoryCredentials)
|
|
await ctx.plugin(AuthorizationService)
|
|
|
|
expect(() => { ctx.emit('authorization/settled', KEY, 'cancelled') }).not.toThrow()
|
|
})
|
|
|
|
it('reserves the package name against duplicate registration', async () => {
|
|
const ctx = new Context()
|
|
await ctx.plugin(InvariantRegistry)
|
|
await ctx.plugin(AuthorizationInvariant)
|
|
|
|
expect(() => {
|
|
ctx.invariants.register('@deepseek-ai/dsh-authorization', () => {})
|
|
}).toThrow(/already registered/)
|
|
})
|
|
})
|