From e7438743ff081b2fcd7a2cd73ffdb3513af5d024 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Sun, 25 Oct 2026 02:39:25 -0500 Subject: [PATCH] test(proxy): prepare empty-provider 404 regressions before normalization --- agents/poe/work/queue-330/BUILD.md | 32 +++++++++ .../empty-provider-prepared-MANIFEST.sha256 | 8 +++ .../empty-provider-prepared-imports.json | 34 ++++++++++ .../queue-330/empty-provider-red-run-list.txt | 2 + .../tests/proxy-page-empty-provider.test.mjs | 33 ++++++++++ packages/bus/tests/proxy-page-fixture.mjs | 6 +- .../model-proxy/tests/empty-provider.test.mjs | 66 +++++++++++++++++++ 7 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 agents/poe/work/queue-330/empty-provider-prepared-MANIFEST.sha256 create mode 100644 agents/poe/work/queue-330/empty-provider-prepared-imports.json create mode 100644 agents/poe/work/queue-330/empty-provider-red-run-list.txt create mode 100644 packages/bus/tests/proxy-page-empty-provider.test.mjs create mode 100644 packages/model-proxy/tests/empty-provider.test.mjs diff --git a/agents/poe/work/queue-330/BUILD.md b/agents/poe/work/queue-330/BUILD.md index 1f3a2d9ed..2b992bba1 100644 --- a/agents/poe/work/queue-330/BUILD.md +++ b/agents/poe/work/queue-330/BUILD.md @@ -491,3 +491,35 @@ silently turn unknown failures into empty data. Run lists/CLEAR precede tests. No product or test changed in this receipt/proposal commit. Proposed patch is review material, not a fix claim or a substitute for RED/GREEN/upgrade evidence. + +## Regression preparation — sage-4460, no Node execution + +2026-10-25T07:38Z. Authored11 cases in two new whole test files: +packages/model-proxy/tests/empty-provider.test.mjs (8): exact fixed GET404 ->[], +actual404 receipt/discarded canary body/one request; credentials404 and key-list404 +remain proxy-client-refused; provider401/403/500 remain proxy-client-refused; +providerPUT404 remains proxy-client-refused (exercises GET-only guard);200 array +passes through. Every case pins exactly one call and status receipt, no retry, +no response-body/management-key leakage into receipts or error output. +packages/bus/tests/proxy-page-empty-provider.test.mjs (3): fresh404 empty account +list followed by one first-key PUT and a public safe account; malformed200 null +and object each refuse existing proxy-down with no write/retry. + +Stand-in addition only: optional emptyProviderResponse controls the empty-route +status/body for these new cases. Existing fake baseline and every old assertion +and timeout remain unchanged. Imports are declared directly to ManagementClient +and the existing management fixture (which imports ProxyPage/client). Static +single-line import declarations are recorded in empty-provider-prepared-imports +and rooted in the prior esbuild graph; no fixture-text search selects tests. +Exact initial RED list: empty-provider-red-run-list.txt. Prepared source/test/patch +hashes: empty-provider-prepared-MANIFEST.sha256. Product files remain unmodified; +proposed-empty-provider.patch is still NOT APPLIED. + +Expected first RED: new exact404 client case rejects proxy-client-refused instead +of returning[]; new fresh account case rejects proxy-down before add. No new +refusal code; all negative cases preserve existing named refusals. Observe this +RED under the next CLEAR before applying the approved scoped source patch. +Required later GREEN should include both new whole files and the8 focused whole +files because the helper is shared; full gate and P2 key-join still wait their +separate authorized stage. No Node syntax check, test, acceptance, mutant or +proxy process ran during preparation. Slot remains with Magica331r4. diff --git a/agents/poe/work/queue-330/empty-provider-prepared-MANIFEST.sha256 b/agents/poe/work/queue-330/empty-provider-prepared-MANIFEST.sha256 new file mode 100644 index 000000000..bdf835a7e --- /dev/null +++ b/agents/poe/work/queue-330/empty-provider-prepared-MANIFEST.sha256 @@ -0,0 +1,8 @@ +ed5dfcda6db77921f90f1eb587fb0044d6472fb613ecaa98445ed42bc04d5d46 packages/model-proxy/tests/empty-provider.test.mjs +c55cc0bb47cd7716a2c31c665cd2dd426e2c54ab7b629637bdc12089dfeb40ce packages/bus/tests/proxy-page-empty-provider.test.mjs +01c18d8d09dac72bed45ce302a88cea449ed22ffde374529cf784bad38adbd72 packages/bus/tests/proxy-page-fixture.mjs +aa73c4cd454742f7745900e8481f7425341ed7d236b104589790ed254c8bd69f packages/model-proxy/src/client.mjs +14acdb4d3fdaabad508eec7378740b13c175d4bdd0c6e707a673138eff82365b packages/bus/src/proxy-page.mjs +b19292cad28bd19427fac932c6150429968e184f4a6f000d948919e76908eb05 agents/poe/work/queue-330/proposed-empty-provider.patch +ea7584f8935251baa9c32bf675343e8c8cbe19a45c4e7dc48675e14b4409bb1c agents/poe/work/queue-330/empty-provider-prepared-imports.json +5d227ae19d600c2fb0e375673045705c4f5bcc00311493a577108caddb38704a agents/poe/work/queue-330/empty-provider-red-run-list.txt diff --git a/agents/poe/work/queue-330/empty-provider-prepared-imports.json b/agents/poe/work/queue-330/empty-provider-prepared-imports.json new file mode 100644 index 000000000..e8da46f32 --- /dev/null +++ b/agents/poe/work/queue-330/empty-provider-prepared-imports.json @@ -0,0 +1,34 @@ +{ + "packages/model-proxy/tests/empty-provider.test.mjs": { + "staticImports": [ + "node:test", + "node:assert/strict", + "node:http", + "packages/model-proxy/src/client.mjs" + ], + "existingParsedClosureRoots": [ + "packages/model-proxy/src/client.mjs" + ] + }, + "packages/bus/tests/proxy-page-empty-provider.test.mjs": { + "staticImports": [ + "node:test", + "node:assert/strict", + "packages/bus/tests/proxy-page-fixture.mjs" + ], + "existingParsedClosureRoots": [ + "packages/bus/tests/proxy-page-fixture.mjs" + ] + }, + "packages/bus/tests/proxy-page-fixture.mjs": { + "staticImports": [ + "node:http", + "packages/model-proxy/src/client.mjs", + "packages/bus/src/proxy-page.mjs" + ], + "existingParsedClosureRoots": [ + "packages/model-proxy/src/client.mjs", + "packages/bus/src/proxy-page.mjs" + ] + } +} diff --git a/agents/poe/work/queue-330/empty-provider-red-run-list.txt b/agents/poe/work/queue-330/empty-provider-red-run-list.txt new file mode 100644 index 000000000..d4f455aa9 --- /dev/null +++ b/agents/poe/work/queue-330/empty-provider-red-run-list.txt @@ -0,0 +1,2 @@ +packages/model-proxy/tests/empty-provider.test.mjs +packages/bus/tests/proxy-page-empty-provider.test.mjs diff --git a/packages/bus/tests/proxy-page-empty-provider.test.mjs b/packages/bus/tests/proxy-page-empty-provider.test.mjs new file mode 100644 index 000000000..b864d3d95 --- /dev/null +++ b/packages/bus/tests/proxy-page-empty-provider.test.mjs @@ -0,0 +1,33 @@ +// P4 real client/page regression: fresh pinned proxy404 must allow the first key. +// Malformed successful bodies still fail closed with the existing refusal code. +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { fakeManagement } from './proxy-page-fixture.mjs'; +const route = '/v8/management/config/api-keys/claude'; +test('fresh404 yields no accounts, then adds the first key once with no value leakage', async t => { + const canary = 'p4-first-key'; + const s = await fakeManagement(t, { emptyProviderResponse: { status: 404, body: { error: 'p4-body-canary' } } }); + const empty = await s.call('proxy.accounts'); + assert.equal(Array.isArray(empty.accounts), true); assert.equal(empty.accounts.length, 0); + const added = await s.call('proxy.apikey.add', { provider: 'z.ai', key: canary }); + assert.equal(added.added, true); + const populated = await s.call('proxy.accounts'); + assert.equal(populated.accounts.length, 1); assert.equal(populated.accounts[0].provider, 'z.ai'); + assert.equal(s.state.receives, 1, 'one PUT, no retry'); + assert.equal(s.state.groups[0].keys[0]['api-key'] === canary, true); + assert.deepEqual(s.state.calls, ['GET /v8/management/credentials', `GET ${route}`, `GET ${route}`, `PUT ${route}`, + 'GET /v8/management/credentials', `GET ${route}`]); + assert.deepEqual(s.state.receipts.filter(r => r.call === `GET ${route}`).map(r => r.status), [404, 404, 200]); + for (const value of [canary, 'p4-body-canary', 'p4-management']) { + assert.equal(JSON.stringify([empty, added, populated]).includes(value), false); + assert.equal(JSON.stringify(s.state.receipts).includes(value), false); + } +}); +for (const [name, body] of [['null', null], ['object', { groups: [] }]]) + test(`malformed200 ${name} remains proxy-down, no retry or write`, async t => { + const s = await fakeManagement(t, { emptyProviderResponse: { status: 200, body } }); + await assert.rejects(s.call('proxy.accounts'), { code: 'proxy-down' }); + assert.deepEqual(s.state.calls, ['GET /v8/management/credentials', `GET ${route}`]); + assert.equal(s.state.receives, 0); + assert.deepEqual(s.state.receipts.map(r => r.status), [200, 200]); + }); diff --git a/packages/bus/tests/proxy-page-fixture.mjs b/packages/bus/tests/proxy-page-fixture.mjs index 11cc6b23c..d20b3c775 100644 --- a/packages/bus/tests/proxy-page-fixture.mjs +++ b/packages/bus/tests/proxy-page-fixture.mjs @@ -16,7 +16,11 @@ export async function fakeManagement(t, options = {}) { if (req.headers.authorization !== 'Bearer p4-management') return reply(401, { error: 'refused' }); if (u.pathname === '/v8/management/credentials') return reply(200, { files: state.files, observed_at: '2026-10-24T00:00:00Z' }); if (u.pathname === '/v8/management/config/api-keys/claude') { - if (req.method === 'GET') return reply(200, state.groups); + if (req.method === 'GET') { + if (state.groups.length === 0 && state.emptyProviderResponse) + return reply(state.emptyProviderResponse.status, state.emptyProviderResponse.body); + return reply(200, state.groups); + } // Stand-in treats auth_index as derived/read-only metadata. if (value.some(g => (g.keys ?? []).some(k => Object.hasOwn(k, 'auth_index')))) return reply(422, { error: 'derived field' }); state.receives++; diff --git a/packages/model-proxy/tests/empty-provider.test.mjs b/packages/model-proxy/tests/empty-provider.test.mjs new file mode 100644 index 000000000..ef5a3412d --- /dev/null +++ b/packages/model-proxy/tests/empty-provider.test.mjs @@ -0,0 +1,66 @@ +// P4 pinned8.0.42 regression: absent Claude provider config is HTTP404. +// Normalize only that fixed GET; all other methods/endpoints/statuses refuse. +import test from 'node:test'; +import assert from 'node:assert/strict'; +import http from 'node:http'; +import { ManagementClient } from '../src/client.mjs'; +const endpoint = '/v8/management/config/api-keys/claude'; +const bodyCanary = 'p4-body-canary'; +async function fixture(t, status, body = { error: bodyCanary, 'api-key': bodyCanary }) { + const requests = [], receipts = []; + const server = http.createServer(async (req, res) => { + const chunks = []; for await (const chunk of req) chunks.push(chunk); + requests.push({ method: req.method, path: req.url, body: Buffer.concat(chunks).toString('utf8') }); + res.writeHead(status, { 'content-type': 'application/json' }); res.end(JSON.stringify(body)); + }); + await new Promise(r => server.listen(0, '127.0.0.1', r)); + t.after(() => new Promise(r => server.close(r))); + const client = new ManagementClient({ baseUrl: `http://127.0.0.1:${server.address().port}`, key: 'p4-management', receipt: r => receipts.push(r) }); + return { client, requests, receipts }; +} +function evidence(s, method, path, status) { + assert.equal(s.requests.length, 1, 'one call, no retry'); + assert.deepEqual(s.requests.map(r => [r.method, r.path]), [[method, path]]); + assert.deepEqual(s.receipts, [{ call: `${method} ${path}`, status, keyIds: [] }]); + assert.equal(JSON.stringify(s.receipts).includes(bodyCanary), false); + assert.equal(JSON.stringify(s.receipts).includes('p4-management'), false); +} +async function refused(operation) { + let failure; + try { await operation(); } catch (error) { failure = error; } + assert.equal(failure?.code, 'proxy-client-refused'); + assert.equal(failure.message.includes(bodyCanary), false, 'no error-body value escapes'); + assert.equal(JSON.stringify(failure).includes(bodyCanary), false); +} +test('empty provider GET404 yields empty array, discards body and receipts actual404 once', async t => { + const s = await fixture(t, 404); + const result = await s.client.getUpstreamGroups(); + assert.equal(Array.isArray(result), true); assert.equal(result.length, 0); + assert.equal(JSON.stringify(result).includes(bodyCanary), false); + evidence(s, 'GET', endpoint, 404); +}); +for (const status of [401, 403, 500]) test(`provider GET${status} remains proxy-client-refused, no retry`, async t => { + const s = await fixture(t, status); + await refused(() => s.client.getUpstreamGroups()); + evidence(s, 'GET', endpoint, status); +}); +for (const [method, path] of [['getCredentials', '/v8/management/credentials'], ['getKeys', '/v8/management/config/access/api-keys']]) + test(`${method}404 remains proxy-client-refused, no retry`, async t => { + const s = await fixture(t, 404); + await refused(() => s.client[method]()); + evidence(s, 'GET', path, 404); + }); +test('provider PUT404 remains proxy-client-refused, never treated as empty GET', async t => { + const s = await fixture(t, 404); + await refused(() => s.client.putUpstreamGroups([{ name: 'fixture', keys: [{ 'api-key': 'p4-first-key' }] }])); + evidence(s, 'PUT', endpoint, 404); + assert.equal(s.requests[0].body.includes('p4-first-key'), true); + assert.equal(JSON.stringify(s.receipts).includes('p4-first-key'), false); +}); +test('provider GET200 array passes through, with receipt and no retry', async t => { + const s = await fixture(t, 200, [{ name: 'fixture', keys: [] }]); + const result = await s.client.getUpstreamGroups(); + assert.equal(Array.isArray(result), true); assert.equal(result.length, 1); + assert.equal(result[0].name === 'fixture' && Array.isArray(result[0].keys), true); + evidence(s, 'GET', endpoint, 200); +});