From 061657dd428e6362d036d26dfdabe9aca9009ec7 Mon Sep 17 00:00:00 2001 From: iceteaSA <171169159+iceteaSA@users.noreply.github.com> Date: Sat, 19 Sep 2026 11:15:41 +0200 Subject: [PATCH] test(custody): pin cross-tenant manifest isolation A co-tenant block in the shared opencode-handles.json is only unreachable by our validator because readCustodyHandles filters providers by provider/serve before parsing accounts. Nothing pinned that ordering, so a refactor that validated accounts first would silently let a foreign block reach our validator. Add reader tests: a foreign xai block carrying an unknown account key (minTtlMs) beside our block reads as ready with our accounts and no corruption, and hostile foreign entries (non-array accounts, null, a number, a provider-only object) are ignored. Add a writer round-trip test that verifies the write landed before asserting the foreign block's unknown key survives byte-identically. --- .../src/tests/custody-handle-manifest.test.ts | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/packages/opencode/src/tests/custody-handle-manifest.test.ts b/packages/opencode/src/tests/custody-handle-manifest.test.ts index b806f48a..ed259fd5 100644 --- a/packages/opencode/src/tests/custody-handle-manifest.test.ts +++ b/packages/opencode/src/tests/custody-handle-manifest.test.ts @@ -129,6 +129,93 @@ describe('CustodyHandleManifestReader', () => { }) }) + test('reads our accounts while ignoring a foreign block with unknown account keys', async () => { + const foreign = { + provider: 'xai', + serve: 'opencode-claustrum', + accounts: [ + { + label: 'main', + handle: `ckh_${'H'.repeat(43)}`, + credential_id: 'oauth:xai', + minTtlMs: 7_200_000, + }, + ], + } + await withManifest( + serialize({ + version: 1, + providers: [ + foreign, + { + provider: 'anthropic', + shape: 'oauth', + serve: 'anthropic-auth', + accounts: [ + { + label: 'work-alt', + handle: `ckh_${'A'.repeat(43)}`, + credential_id: 'oauth:anthropic:work-alt', + }, + ], + }, + ], + }), + async (path) => { + const result = await reader(path).read() + expect(result.status).toBe('ready') + if (result.status !== 'ready') + throw new Error('expected ready manifest') + expect(result.manifest.accounts).toEqual([ + { + label: 'work-alt', + handle: `ckh_${'A'.repeat(43)}`, + credentialId: 'oauth:anthropic:work-alt', + }, + ]) + expect(result.manifest.corruptLabels).toEqual(new Set()) + }, + ) + }) + + test('reads our accounts while ignoring hostile foreign provider entries', async () => { + await withManifest( + serialize({ + version: 1, + providers: [ + { + provider: 'xai', + serve: 'opencode-claustrum', + accounts: 'not-an-array', + }, + null, + 42, + { provider: 'xai' }, + { + provider: 'anthropic', + shape: 'oauth', + serve: 'anthropic-auth', + accounts: [ + { + label: 'work-alt', + handle: `ckh_${'A'.repeat(43)}`, + credential_id: 'oauth:anthropic:work-alt', + }, + ], + }, + ], + }), + async (path) => { + const result = await reader(path).read() + expect(result.status).toBe('ready') + if (result.status !== 'ready') + throw new Error('expected ready manifest') + expect(result.manifest.accounts).toHaveLength(1) + expect(result.manifest.corruptLabels).toEqual(new Set()) + }, + ) + }) + test('ignores an anthropic block with a foreign serve', async () => { await withManifest( withProvider((provider) => { @@ -543,6 +630,55 @@ describe('writeCustodyHandleManifestEntry', () => { }) }) + test('preserves a foreign block unknown key byte-identically when writing our account', async () => { + const foreign = { + provider: 'xai', + serve: 'opencode-claustrum', + accounts: [ + { + label: 'main', + handle: `ckh_${'H'.repeat(43)}`, + credential_id: 'oauth:xai', + minTtlMs: 7_200_000, + }, + ], + } + await withManifest( + serialize({ + version: 1, + providers: [ + foreign, + { + provider: 'anthropic', + shape: 'oauth', + serve: 'anthropic-auth', + accounts: [], + }, + ], + }), + async (path) => { + const result = await writeCustodyHandleManifestEntry({ + path, + entry: writerEntry, + }) + expect(result).toEqual({ status: 'written' }) + + const output = JSON.parse(await fs.readFile(path, 'utf8')) as { + providers: Array> + } + const ours = output.providers.find( + (provider) => + provider.provider === 'anthropic' && + provider.serve === 'anthropic-auth', + ) as { accounts: Array> } + expect(ours.accounts.map((account) => account.label)).toContain( + writerEntry.label, + ) + expect(serialize(output.providers[0])).toBe(serialize(foreign)) + }, + ) + }) + test('repairs a missing OAuth shape while retaining all accounts and foreign blocks', async () => { const existingAccount = { label: 'existing',