Add exact-image compatibility policy, experimental admission, paginated build history and shared reauthentication checks. Preserve uncertain Docker creation records, bound frontend resource waits and renew runtime sessions proactively. Lazy-load and split Monaco, add regression and opt-in live Docker fault tests, and record full race and real-browser acceptance results.
76 lines
3.9 KiB
TypeScript
76 lines
3.9 KiB
TypeScript
import { readFileSync } from 'node:fs';
|
|
import { runInNewContext } from 'node:vm';
|
|
import { expect, it, vi } from 'vitest';
|
|
const source = readFileSync(new URL('../../internal/api/runtime_session.go', import.meta.url), 'utf8').split('const runtimeSessionJS = `')[1].split('`')[0];
|
|
it.each([401, 403, 409, 500])('runtime only reloads a confirmed revoked session (%s)', async status => {
|
|
const reload = vi.fn();
|
|
let renew: (() => void) | undefined;
|
|
const fetch = vi.fn(async (path: string) => new Response('{}', {status: path === '/api/refresh' ? status : 401}));
|
|
runInNewContext(source, {
|
|
location:{pathname:'/',reload}, navigator:{}, fetch,
|
|
document:{cookie:'dsh_csrf=csrf',addEventListener() {}},
|
|
window:{addEventListener(_name: string, handler: () => void) {renew = handler;}},
|
|
setInterval() {}, setTimeout(resolve: () => void) {resolve();},
|
|
});
|
|
await renew?.();
|
|
expect(reload).toHaveBeenCalledTimes(status === 401 || status === 403 ? 1 : 0);
|
|
expect(fetch.mock.calls.filter(c => c[0] === '/api/refresh')).toHaveLength(1);
|
|
expect(fetch.mock.calls.filter(c => c[0] === '/api/me')).toHaveLength(status === 500 ? 0 : 4);
|
|
});
|
|
it.each([false, true])('renews before access expiry, with Web Locks=%s', async withLocks => {
|
|
let now = 0, expires = 300_000;
|
|
let tick!: () => Promise<void>;
|
|
const locks = {request: vi.fn(async (_name: string, run: () => Promise<void>) => run())};
|
|
const fetch = vi.fn(async (path: string) => {
|
|
if (path === '/api/refresh') expires = now + 300_000;
|
|
return new Response('{}', {status: now < expires ? 200 : 401});
|
|
});
|
|
runInNewContext(source, {
|
|
location: {pathname: '/', reload: vi.fn()}, navigator: withLocks ? {locks} : {}, fetch,
|
|
document: {cookie: 'dsh_csrf=csrf', addEventListener() {}},
|
|
window: {addEventListener() {}},
|
|
setInterval(fn: typeof tick, interval: number) {tick = fn; expect(interval).toBe(240_000);},
|
|
setTimeout,
|
|
});
|
|
for (now = 240_000; now <= 960_000; now += 240_000) {
|
|
expect(now).toBeLessThan(expires);
|
|
await tick();
|
|
expect(expires).toBe(now + 300_000);
|
|
}
|
|
expect(fetch.mock.calls.map(c => c[0])).toEqual(Array(4).fill('/api/refresh'));
|
|
expect(locks.request).toHaveBeenCalledTimes(withLocks ? 4 : 0);
|
|
});
|
|
it('coalesces renewal events and keeps a session recovered by a sibling page', async () => {
|
|
let tick!: () => Promise<void>, finish!: (response: Response) => void;
|
|
const reload = vi.fn();
|
|
const fetch = vi.fn((path: string) => path === '/api/refresh'
|
|
? new Promise<Response>(resolve => {finish = resolve;})
|
|
: Promise.resolve(new Response('{}', {status: 200})));
|
|
runInNewContext(source, {
|
|
location: {pathname: '/', reload}, navigator: {}, fetch,
|
|
document: {cookie: 'dsh_csrf=csrf', addEventListener() {}},
|
|
window: {addEventListener() {}}, setInterval(fn: typeof tick) {tick = fn;}, setTimeout,
|
|
});
|
|
const first = tick(), second = tick();
|
|
expect(fetch).toHaveBeenCalledOnce();
|
|
finish(new Response('{}', {status: 409}));
|
|
await Promise.all([first, second]);
|
|
expect(fetch.mock.calls.map(c => c[0])).toEqual(['/api/refresh', '/api/me']);
|
|
expect(reload).not.toHaveBeenCalled();
|
|
});
|
|
it('reads the latest CSRF cookie after waiting for the refresh lock', async () => {
|
|
let tick!: () => Promise<void>, enter!: () => void;
|
|
const document = {cookie: 'dsh_csrf=old', addEventListener() {}};
|
|
const fetch = vi.fn(async () => new Response('{}'));
|
|
const locks = {request: (_name: string, run: () => Promise<void>) => new Promise<void>((resolve, reject) => {enter = () => {run().then(resolve, reject);};})};
|
|
runInNewContext(source, {
|
|
location: {pathname: '/', reload: vi.fn()}, navigator: {locks}, document, fetch,
|
|
window: {addEventListener() {}}, setInterval(fn: typeof tick) {tick = fn;}, setTimeout,
|
|
});
|
|
const pending = tick();
|
|
expect(fetch).not.toHaveBeenCalled();
|
|
document.cookie = 'dsh_csrf=new';
|
|
enter(); await pending;
|
|
expect(fetch).toHaveBeenCalledWith('/api/refresh', expect.objectContaining({headers: {'X-CSRF-Token': 'new'}}));
|
|
});
|