This commit is contained in:
Oleg Maslov
2026-09-02 10:14:22 +02:00
parent 0c3e2ead3b
commit b20b138fe4
771 changed files with 161561 additions and 9027 deletions

View File

@@ -192,35 +192,174 @@ describe('PATCH /api/tier override gate (AV-3)', () => {
describe('D1 loopback auth + session-token bootstrap', () => {
let server: FastifyInstance;
let tmpDir: string;
const originalHost = process.env.WAGGLE_HOST;
const originalInstanceId = process.env.WAGGLE_INSTANCE_ID;
const originalDesktopBootstrap = process.env.WAGGLE_DESKTOP_BOOTSTRAP_TOKEN;
const desktopBootstrap = 'desktop-bootstrap-test-1234567890';
beforeEach(async () => {
// Exercise the SECURE D1 default (the suite setup defaults trust ON).
process.env.WAGGLE_TRUST_LOCALHOST = '0';
process.env.WAGGLE_INSTANCE_ID = 'desktop-instance-test';
process.env.WAGGLE_DESKTOP_BOOTSTRAP_TOKEN = desktopBootstrap;
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-d1-'));
server = await buildLocalServer({ dataDir: tmpDir });
});
afterEach(async () => {
await server.close();
process.env.WAGGLE_TRUST_LOCALHOST = '1';
if (originalHost === undefined) delete process.env.WAGGLE_HOST;
else process.env.WAGGLE_HOST = originalHost;
if (originalInstanceId === undefined) delete process.env.WAGGLE_INSTANCE_ID;
else process.env.WAGGLE_INSTANCE_ID = originalInstanceId;
if (originalDesktopBootstrap === undefined) delete process.env.WAGGLE_DESKTOP_BOOTSTRAP_TOKEN;
else process.env.WAGGLE_DESKTOP_BOOTSTRAP_TOKEN = originalDesktopBootstrap;
await new Promise(r => setTimeout(r, 100));
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch { /* EBUSY on win32 */ }
});
it('serves the session token from the auth-exempt, same-origin bootstrap', async () => {
const res = await server.inject({ method: 'GET', url: '/api/auth/session-token' });
it('serves the session token only with the per-launch desktop bootstrap credential', async () => {
const res = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers: { 'x-waggle-desktop-bootstrap': desktopBootstrap },
});
expect(res.statusCode).toBe(200);
expect(res.headers['cache-control']).toBe('no-store');
const token = res.json().token as string;
expect(typeof token).toBe('string');
expect(token.length).toBeGreaterThan(0);
});
it('scrubs the launch credential before child processes can inherit it', () => {
expect(process.env.WAGGLE_DESKTOP_BOOTSTRAP_TOKEN).toBeUndefined();
});
it('rejects a browser-reachable Tauri origin without the IPC-only bootstrap credential', async () => {
const missing = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers: { origin: 'http://tauri.localhost' },
});
expect(missing.statusCode).toBe(403);
expect(missing.json().code).toBe('DESKTOP_BOOTSTRAP_REQUIRED');
const wrong = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers: {
origin: 'http://tauri.localhost',
'x-waggle-desktop-bootstrap': 'wrong-bootstrap-token-1234567890',
},
});
expect(wrong.statusCode).toBe(403);
expect(wrong.json().code).toBe('DESKTOP_BOOTSTRAP_REQUIRED');
});
it('binds browser-mode bootstrap to the exact request authority', async () => {
await server.close();
delete process.env.WAGGLE_INSTANCE_ID;
delete process.env.WAGGLE_DESKTOP_BOOTSTRAP_TOKEN;
server = await buildLocalServer({ dataDir: tmpDir });
const crossLoopback = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers: {
host: '127.0.0.1:3333',
origin: 'http://127.0.0.1:5174',
},
});
expect(crossLoopback.statusCode).toBe(403);
const sameOrigin = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers: {
host: '127.0.0.1:3333',
origin: 'http://127.0.0.1:3333',
},
});
expect(sameOrigin.statusCode).toBe(200);
for (const headers of [
{
host: '127.0.0.1:3333',
origin: 'http://127.0.0.1:3333',
'sec-fetch-site': 'none',
},
{
host: '127.0.0.1:3333',
referer: 'http://127.0.0.1:3333/app',
'sec-fetch-site': 'none',
},
]) {
const inconsistent = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers,
});
expect(inconsistent.statusCode).toBe(403);
expect(inconsistent.json().code).toBe('SESSION_BOOTSTRAP_ORIGIN_MISMATCH');
}
});
it('rejects originless top-level and MV3 requests at the browser-mode process-token bootstrap', async () => {
await server.close();
delete process.env.WAGGLE_INSTANCE_ID;
delete process.env.WAGGLE_DESKTOP_BOOTSTRAP_TOKEN;
server = await buildLocalServer({ dataDir: tmpDir });
for (const headers of [
{ host: '127.0.0.1:3333', 'sec-fetch-site': 'none' },
{
host: '127.0.0.1:3333',
'sec-fetch-site': 'none',
'x-waggle-extension-id': 'abcdefghijklmnopabcdefghijklmnop',
},
]) {
const res = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers,
});
expect(res.statusCode).toBe(403);
expect(res.json().code).toBe('SESSION_BOOTSTRAP_ORIGIN_MISMATCH');
}
const sameOriginFetch = await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers: {
host: '127.0.0.1:3333',
'sec-fetch-site': 'same-origin',
},
});
expect(sameOriginFetch.statusCode).toBe(200);
});
it('does not expose the process bearer when the sidecar is non-loopback-bound', async () => {
await server.close();
process.env.WAGGLE_HOST = '0.0.0.0';
server = await buildLocalServer({ dataDir: tmpDir });
const res = await server.inject({ method: 'GET', url: '/api/auth/session-token' });
expect(res.statusCode).toBe(403);
expect(res.json().code).toBe('SESSION_BOOTSTRAP_LOOPBACK_ONLY');
});
it('requires a bearer token on a normal route (loopback no longer trusted)', async () => {
const res = await server.inject({ method: 'GET', url: '/api/tier' });
expect(res.statusCode).toBe(401);
});
it('accepts a normal route when the bootstrapped token is presented', async () => {
const token = (await server.inject({ method: 'GET', url: '/api/auth/session-token' })).json().token as string;
const token = (await server.inject({
method: 'GET',
url: '/api/auth/session-token',
headers: { 'x-waggle-desktop-bootstrap': desktopBootstrap },
})).json().token as string;
const res = await server.inject({
method: 'GET', url: '/api/tier',
headers: { authorization: `Bearer ${token}` },