mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-31 19:41:37 +02:00
Cover AI and SAR proxy auth routes
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* - /api/tools/* (Sprint 1C addition)
|
||||
* - /api/wormhole/* (pre-existing, regression)
|
||||
* - /api/settings/* (pre-existing, regression)
|
||||
* - /api/layers, /api/ais/feed, /api/ai/agent-actions
|
||||
* - /api/layers, /api/ais/feed, /api/ai/*, /api/sar/mode-b/*
|
||||
*
|
||||
* Also verifies that:
|
||||
* - non-sensitive mesh paths (e.g. mesh/events) do NOT receive injected key
|
||||
@@ -344,6 +344,99 @@ describe('proxy admin-key injection coverage', () => {
|
||||
expect(capturedHeaders(fetchMock).get('X-Admin-Key')).toBe(ADMIN_KEY);
|
||||
});
|
||||
|
||||
it('GET /api/ai/pins with valid session injects X-Admin-Key', async () => {
|
||||
const cookie = await mintSession(ADMIN_KEY);
|
||||
|
||||
const fetchMock = vi.fn().mockResolvedValue(
|
||||
new Response(JSON.stringify({ ok: true, pins: [] }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const req = new NextRequest('http://localhost/api/ai/pins?limit=500', {
|
||||
method: 'GET',
|
||||
headers: { cookie },
|
||||
});
|
||||
const res = await proxyGet(req, {
|
||||
params: Promise.resolve({ path: ['ai', 'pins'] }),
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(capturedHeaders(fetchMock).get('X-Admin-Key')).toBe(ADMIN_KEY);
|
||||
});
|
||||
|
||||
it('GET /api/ai/layers with valid session injects X-Admin-Key', async () => {
|
||||
const cookie = await mintSession(ADMIN_KEY);
|
||||
|
||||
const fetchMock = vi.fn().mockResolvedValue(
|
||||
new Response(JSON.stringify({ ok: true, layers: [] }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const req = new NextRequest('http://localhost/api/ai/layers', {
|
||||
method: 'GET',
|
||||
headers: { cookie },
|
||||
});
|
||||
const res = await proxyGet(req, {
|
||||
params: Promise.resolve({ path: ['ai', 'layers'] }),
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(capturedHeaders(fetchMock).get('X-Admin-Key')).toBe(ADMIN_KEY);
|
||||
});
|
||||
|
||||
it('GET /api/ai/timemachine/config with valid session injects X-Admin-Key', async () => {
|
||||
const cookie = await mintSession(ADMIN_KEY);
|
||||
|
||||
const fetchMock = vi.fn().mockResolvedValue(
|
||||
new Response(JSON.stringify({ ok: true, config: {} }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const req = new NextRequest('http://localhost/api/ai/timemachine/config', {
|
||||
method: 'GET',
|
||||
headers: { cookie },
|
||||
});
|
||||
const res = await proxyGet(req, {
|
||||
params: Promise.resolve({ path: ['ai', 'timemachine', 'config'] }),
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(capturedHeaders(fetchMock).get('X-Admin-Key')).toBe(ADMIN_KEY);
|
||||
});
|
||||
|
||||
it('POST /api/sar/mode-b/enable with valid session injects X-Admin-Key', async () => {
|
||||
const cookie = await mintSession(ADMIN_KEY);
|
||||
|
||||
const fetchMock = vi.fn().mockResolvedValue(
|
||||
new Response(JSON.stringify({ ok: true }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const req = new NextRequest('http://localhost/api/sar/mode-b/enable', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ earthdata_user: 'operator', earthdata_token: 'token' }),
|
||||
headers: { cookie, 'Content-Type': 'application/json' },
|
||||
});
|
||||
const res = await proxyPost(req, {
|
||||
params: Promise.resolve({ path: ['sar', 'mode-b', 'enable'] }),
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(capturedHeaders(fetchMock).get('X-Admin-Key')).toBe(ADMIN_KEY);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Non-sensitive mesh paths must NOT receive injected admin key
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -66,7 +66,10 @@ function isSensitiveProxyPath(pathSegments: string[]): boolean {
|
||||
if (joined === 'system/update') return true;
|
||||
if (joined === 'layers') return true;
|
||||
if (joined === 'ais/feed') return true;
|
||||
if (joined === 'ai/agent-actions') return true;
|
||||
if (pathSegments[0] === 'ai') return true;
|
||||
if (pathSegments[0] === 'sar' && (pathSegments[1] === 'mode-b' || pathSegments[1] === 'aois')) {
|
||||
return true;
|
||||
}
|
||||
if (pathSegments[0] === 'settings') return true;
|
||||
if (joined === 'mesh/infonet/ingest') return true;
|
||||
if (joined === 'mesh/meshtastic/send') return true;
|
||||
|
||||
Reference in New Issue
Block a user