mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
Merge origin/main into fix/realtime-debug-log-hardening
# Conflicts: # CHANGELOG.md # src/tooling/localServices.test.mjs
This commit is contained in:
commit
a948274326
161 files changed
+19838
-6545
No files matched your search
@@ -279,11 +279,65 @@ test('Realtime service configuration selects compatible endpoint/model without f
|
||||
url: '/?tier=arbitrary-model&model=other',
|
||||
});
|
||||
assert.equal(response.status, 200);
|
||||
assert.deepEqual(response.json(), { value: 'short-lived-fixture' });
|
||||
assert.equal(response.headers['x-gev-voice-model'], 'configured-model');
|
||||
assert.equal(response.headers['cache-control'], 'no-store');
|
||||
assert.doesNotMatch(response.body, /server-fixture|voice\.example/);
|
||||
});
|
||||
|
||||
test('OpenAI routes answer generically when the upstream or the request fails', async (t) => {
|
||||
env(t, 'OPENAI_API_KEY', 'fixture-upstream-secret');
|
||||
env(t, 'GEV_RATELIMIT_OPENAI_PER_MIN', undefined);
|
||||
const leak =
|
||||
'fixture-upstream-secret req_fixture_1234 org-fixture quota exhausted';
|
||||
|
||||
// `data.error.message` is OpenAI's own wording — request ids, organization
|
||||
// hints, quota phrasing — and was relayed verbatim whenever upstream was not ok.
|
||||
t.mock.method(globalThis, 'fetch', async () =>
|
||||
Response.json({ error: { message: leak } }, { status: 429 }),
|
||||
);
|
||||
const summary = await request(
|
||||
install(openAiRealtimeProxy()).get('/api/openai/hud-summary'),
|
||||
{ method: 'POST', body: JSON.stringify({ context: {} }) },
|
||||
);
|
||||
assert.equal(summary.json().error, 'OpenAI HUD summary request failed');
|
||||
assert.equal(summary.body.includes('req_fixture_1234'), false);
|
||||
assert.equal(summary.body.includes('fixture-upstream-secret'), false);
|
||||
|
||||
// An HTTP error from the client-secret endpoint carries the same upstream
|
||||
// detail, while a successful response must still pass the ephemeral secret.
|
||||
t.mock.restoreAll();
|
||||
t.mock.method(globalThis, 'fetch', async () =>
|
||||
Response.json({ error: { message: leak } }, { status: 429 }),
|
||||
);
|
||||
const rejectedToken = await request(
|
||||
install(openAiRealtimeProxy()).get('/api/realtime/token'),
|
||||
);
|
||||
assert.equal(rejectedToken.status, 429);
|
||||
assert.equal(
|
||||
rejectedToken.headers['content-type'],
|
||||
'application/json; charset=utf-8',
|
||||
);
|
||||
assert.deepEqual(rejectedToken.json(), {
|
||||
error: 'Failed to create Realtime token',
|
||||
});
|
||||
assert.equal(rejectedToken.body.includes('req_fixture_1234'), false);
|
||||
assert.equal(rejectedToken.body.includes('fixture-upstream-secret'), false);
|
||||
|
||||
// A network fault surfaced a resolver message naming the upstream host.
|
||||
t.mock.restoreAll();
|
||||
t.mock.method(globalThis, 'fetch', async () => {
|
||||
throw Error(`getaddrinfo ENOTFOUND api.openai.com ${leak}`);
|
||||
});
|
||||
const token = await request(
|
||||
install(openAiRealtimeProxy()).get('/api/realtime/token'),
|
||||
);
|
||||
assert.equal(token.status, 502);
|
||||
assert.deepEqual(token.json(), { error: 'Failed to create Realtime token' });
|
||||
assert.equal(token.body.includes('api.openai.com'), false);
|
||||
assert.equal(token.body.includes('fixture-upstream-secret'), false);
|
||||
});
|
||||
|
||||
test('the debug-log sink stays bounded, rate limited, and quiet about failures', async (t) => {
|
||||
const sourceRoot = root(t);
|
||||
const handler = install(openAiRealtimeProxy({ sourceRoot })).get(
|
||||
|
||||
@@ -149,3 +149,45 @@ for (const hook of ['configureServer', 'configurePreviewServer']) {
|
||||
assert.equal(cancelled, true);
|
||||
});
|
||||
}
|
||||
|
||||
test('a failed CCTV media fetch reports a fixed health message, not the error text', async (t) => {
|
||||
isolate(t);
|
||||
const root = mkdtempSync(path.join(tmpdir(), 'gev-cctv-'));
|
||||
t.after(() => rmSync(root, { recursive: true, force: true }));
|
||||
mkdirSync(path.join(root, 'config'));
|
||||
writeFileSync(
|
||||
path.join(root, 'config/cctv_sources.austin.json'),
|
||||
JSON.stringify([
|
||||
{
|
||||
id: 'leaky',
|
||||
name: 'Leaky camera',
|
||||
lat: 30.27,
|
||||
lon: -97.74,
|
||||
feedType: 'video',
|
||||
url: 'https://cams.fixture.invalid/leaky.m3u8',
|
||||
},
|
||||
]),
|
||||
);
|
||||
const leak =
|
||||
'connect ETIMEDOUT 203.0.113.9:443 C:\fixture\secret-path\cams.json';
|
||||
t.mock.restoreAll();
|
||||
t.mock.method(globalThis, 'fetch', () => {
|
||||
throw Error(leak);
|
||||
});
|
||||
|
||||
const call = install(cctvProxy({ sourceRoot: root }));
|
||||
const media = await call('/media/leaky');
|
||||
assert.equal(media.status, 502);
|
||||
assert.equal(media.body.includes('203.0.113.9'), false);
|
||||
|
||||
// GET /health is the second door: src/layers/cctv/frames.js renders each
|
||||
// entry's `message` as the camera's status label, so a raw errno stored here
|
||||
// reaches the screen even though the response above is sanitized.
|
||||
const camera = JSON.parse((await call('/health')).body).cameras.find(
|
||||
(entry) => entry.id === 'leaky',
|
||||
);
|
||||
assert.equal(camera.status, 'degraded');
|
||||
assert.equal(camera.message, 'Media fetch failed');
|
||||
assert.equal(camera.message.includes('ETIMEDOUT'), false);
|
||||
assert.equal(camera.message.includes('secret-path'), false);
|
||||
});
|
||||
@@ -328,6 +328,7 @@ test('sensor sampler waits for postRender and reads framebuffer pixels; stopped
|
||||
globalThis.Image = previousImage;
|
||||
});
|
||||
const identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
||||
const readRows = [];
|
||||
let listener,
|
||||
reads = 0,
|
||||
render = true;
|
||||
@@ -336,6 +337,7 @@ test('sensor sampler waits for postRender and reads framebuffer pixels; stopped
|
||||
UNSIGNED_BYTE: 2,
|
||||
readPixels(x, y, w, h, format, type, buffer) {
|
||||
reads++;
|
||||
readRows.push(y);
|
||||
buffer.set([255, 255, 255, 255]);
|
||||
},
|
||||
};
|
||||
@@ -408,13 +410,70 @@ test('sensor sampler waits for postRender and reads framebuffer pixels; stopped
|
||||
},
|
||||
};
|
||||
const page = { evaluate: async (fn, ...args) => fn(...args) };
|
||||
const sampledLayer =
|
||||
window.__godsEyeView.dataManager.layers.get('transit').module;
|
||||
const originalState = sampledLayer._transitStateForTest;
|
||||
sampledLayer._transitStateForTest = () => {
|
||||
const state = originalState();
|
||||
state._vehicles.get('bus').marker.position.y = 0.0025; // Screen y = 199.5.
|
||||
return state;
|
||||
};
|
||||
const pixels = await sampleTransitPixels(page, {});
|
||||
sampledLayer._transitStateForTest = originalState;
|
||||
assert.deepEqual(
|
||||
readRows.slice(0, 9),
|
||||
[201, 200, 199, 201, 200, 199, 201, 200, 199],
|
||||
'fractional CSS coordinates must invert the floored framebuffer row',
|
||||
);
|
||||
assert.ok(
|
||||
reads >= 13,
|
||||
'centre, rings and background come from WebGL readPixels',
|
||||
);
|
||||
assert.ok(Math.abs(pixels[0].centre - 1) < 1e-6);
|
||||
assert.equal(listener, null);
|
||||
// An opaque window/panel is not a sensor core. Choose another solid patch,
|
||||
// and reject a raster with no white interior even though alpha/picking pass.
|
||||
for (let i = 0; i < raster.length; i += 4) raster.fill(0, i, i + 3);
|
||||
assert.equal((await sampleTransitPixels(page, {})).length, 0);
|
||||
raster.fill(255);
|
||||
for (let y = 6; y <= 9; y++)
|
||||
for (let x = 0; x < 16; x++) {
|
||||
const i = (y * 16 + x) * 4;
|
||||
raster.fill(0, i, i + 3);
|
||||
}
|
||||
assert.equal(
|
||||
(await sampleTransitPixels(page, {})).length,
|
||||
1,
|
||||
'a body patch away from the central panel remains eligible',
|
||||
);
|
||||
// A narrow centre can be opaque yet put the framebuffer sample on its
|
||||
// antialiased side. Prefer the wider solid band above it, before reading luma.
|
||||
raster.fill(0);
|
||||
for (let y = 0; y < 16; y++)
|
||||
for (let x = 0; x < 16; x++) {
|
||||
const wide = y >= 3 && y <= 5;
|
||||
if ((wide && x >= 3 && x <= 12) || (x >= 7 && x <= 9))
|
||||
raster.fill(255, (y * 16 + x) * 4, (y * 16 + x + 1) * 4);
|
||||
}
|
||||
const readStart = readRows.length;
|
||||
assert.equal((await sampleTransitPixels(page, {})).length, 1);
|
||||
assert.ok(
|
||||
readRows[readStart] > 204,
|
||||
'centre samples use the widest solid band',
|
||||
);
|
||||
raster.fill(255);
|
||||
sampledLayer._transitStateForTest = () => {
|
||||
const state = originalState();
|
||||
state._vehicles.get('bus').mode = 'tram';
|
||||
return state;
|
||||
};
|
||||
const tramStart = readRows.length;
|
||||
assert.equal((await sampleTransitPixels(page, {})).length, 1);
|
||||
assert.ok(
|
||||
readRows[tramStart] > 204,
|
||||
'equal-width tram bands prefer the upper solid body',
|
||||
);
|
||||
sampledLayer._transitStateForTest = originalState;
|
||||
scene.pick = () => ({ id: 'overlapping-label' });
|
||||
assert.equal(
|
||||
(await sampleTransitPixels(page, {})).length,
|
||||
|
||||
Reference in new issue
Block a user