mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 16:02:56 +00:00
test: close Claude shared auth migration coverage
This commit is contained in:
@@ -8,14 +8,19 @@ import {
|
||||
migrateLegacySharedClaudeAuth
|
||||
} from './legacy-shared-claude-auth-migration'
|
||||
|
||||
const ownership = vi.hoisted(() => ({
|
||||
resolve: (_id: string, path: string): string | null => path
|
||||
}))
|
||||
|
||||
vi.mock('./managed-auth-path', () => ({
|
||||
resolveOwnedClaudeManagedAuthPath: (_id: string, path: string) => path
|
||||
resolveOwnedClaudeManagedAuthPath: (id: string, path: string) => ownership.resolve(id, path)
|
||||
}))
|
||||
|
||||
let root: string
|
||||
|
||||
beforeEach(() => {
|
||||
root = mkdtempSync(join(tmpdir(), 'orca-claude-migration-'))
|
||||
ownership.resolve = (_id, path) => path
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -98,6 +103,123 @@ describe('legacy shared Claude auth migration', () => {
|
||||
expect(writeManagedCredentials).not.toHaveBeenCalled()
|
||||
expect(fixture.marker()).toMatchObject({ outcome: 'already-present' })
|
||||
})
|
||||
|
||||
it('refuses an untrusted account home without reading or mutating the shared store', async () => {
|
||||
const fixture = createFixture()
|
||||
const readLegacyKeychain = vi.fn(async () => fixture.shared)
|
||||
const writeManagedCredentials = vi.fn(async () => {})
|
||||
ownership.resolve = () => null
|
||||
|
||||
const outcome = await fixture.migrate({ readLegacyKeychain, writeManagedCredentials })
|
||||
|
||||
expect(outcome).toBe('unavailable')
|
||||
expect(readLegacyKeychain).not.toHaveBeenCalled()
|
||||
expect(writeManagedCredentials).not.toHaveBeenCalled()
|
||||
expect(existsSync(fixture.markerPath)).toBe(false)
|
||||
})
|
||||
|
||||
it('migrates the active account even when another account home is stale or deleted', async () => {
|
||||
const fixture = createFixture()
|
||||
const stale = {
|
||||
...fixture.account,
|
||||
id: 'account-2',
|
||||
email: 'other@example.com',
|
||||
managedAuthPath: join(root, 'account-2', 'auth')
|
||||
}
|
||||
ownership.resolve = (id, path) => (id === stale.id ? null : path)
|
||||
const writeManagedCredentials = vi.fn(async () => {})
|
||||
|
||||
const outcome = await fixture.migrate({
|
||||
accounts: [fixture.account, stale],
|
||||
readLegacyOauthAccount: () => ({ emailAddress: 'user@example.com' }),
|
||||
writeManagedCredentials
|
||||
})
|
||||
|
||||
expect(outcome).toBe('migrated')
|
||||
expect(writeManagedCredentials).toHaveBeenCalledWith(fixture.account, fixture.shared)
|
||||
expect(fixture.marker()).toMatchObject({ outcome: 'migrated', accountId: fixture.account.id })
|
||||
})
|
||||
|
||||
it('keeps a deleted-home duplicate identity in the ambiguity gate', async () => {
|
||||
const fixture = createFixture()
|
||||
const duplicate = {
|
||||
...fixture.account,
|
||||
id: 'account-2',
|
||||
managedAuthPath: join(root, 'account-2', 'auth')
|
||||
}
|
||||
ownership.resolve = (id, path) => (id === duplicate.id ? null : path)
|
||||
const writeManagedCredentials = vi.fn(async () => {})
|
||||
|
||||
const outcome = await fixture.migrate({
|
||||
accounts: [fixture.account, duplicate],
|
||||
readLegacyOauthAccount: () => ({ emailAddress: 'user@example.com' }),
|
||||
writeManagedCredentials
|
||||
})
|
||||
|
||||
expect(outcome).toBe('ambiguous')
|
||||
expect(writeManagedCredentials).not.toHaveBeenCalled()
|
||||
expect(existsSync(fixture.markerPath)).toBe(false)
|
||||
})
|
||||
|
||||
it('never clobbers a newer per-account credential', async () => {
|
||||
const fixture = createFixture()
|
||||
const newer = JSON.stringify({ claudeAiOauth: { accessToken: 'newer-token' } })
|
||||
const writeManagedCredentials = vi.fn(async () => {})
|
||||
|
||||
const outcome = await fixture.migrate({
|
||||
readLegacyOauthAccount: () => ({ emailAddress: 'user@example.com' }),
|
||||
readManagedCredentials: async () => newer,
|
||||
writeManagedCredentials
|
||||
})
|
||||
|
||||
expect(outcome).toBe('already-present')
|
||||
expect(writeManagedCredentials).not.toHaveBeenCalled()
|
||||
expect(fixture.marker()).toMatchObject({
|
||||
outcome: 'already-present',
|
||||
accountId: fixture.account.id
|
||||
})
|
||||
})
|
||||
|
||||
it('is a full no-op once the generation marker is present', async () => {
|
||||
const fixture = createFixture()
|
||||
mkdirSync(join(root, 'metadata'), { recursive: true })
|
||||
writeFileSync(
|
||||
fixture.markerPath,
|
||||
`${JSON.stringify({ version: 1, completedAt: 1, outcome: 'migrated', accountId: fixture.account.id })}\n`,
|
||||
'utf-8'
|
||||
)
|
||||
const readLegacyKeychain = vi.fn(async () => fixture.shared)
|
||||
const readLegacyOauthAccount = vi.fn(() => ({ emailAddress: 'user@example.com' }))
|
||||
const readManagedCredentials = vi.fn(async () => null)
|
||||
const writeManagedCredentials = vi.fn(async () => {})
|
||||
|
||||
const outcome = await fixture.migrate({
|
||||
readLegacyKeychain,
|
||||
readLegacyOauthAccount,
|
||||
readManagedCredentials,
|
||||
writeManagedCredentials
|
||||
})
|
||||
|
||||
expect(outcome).toBe('already-present')
|
||||
expect(readLegacyKeychain).not.toHaveBeenCalled()
|
||||
expect(readLegacyOauthAccount).not.toHaveBeenCalled()
|
||||
expect(readManagedCredentials).not.toHaveBeenCalled()
|
||||
expect(writeManagedCredentials).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('never leaks the shared store to a non-matching account', async () => {
|
||||
const fixture = createFixture()
|
||||
const writeManagedCredentials = vi.fn(async () => {})
|
||||
|
||||
const outcome = await fixture.migrate({
|
||||
readLegacyOauthAccount: () => ({ emailAddress: 'other@example.com' }),
|
||||
writeManagedCredentials
|
||||
})
|
||||
|
||||
expect(outcome).toBe('ambiguous')
|
||||
expect(writeManagedCredentials).not.toHaveBeenCalled()
|
||||
expect(existsSync(fixture.markerPath)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
function createFixture() {
|
||||
|
||||
Reference in New Issue
Block a user