feat: productionize learning engine and classroom

This commit is contained in:
inman
2026-08-16 21:44:52 +08:00
parent 2d04197f3f
commit ba35adfbfa
124 changed files with 9071 additions and 796 deletions

View File

@@ -12,22 +12,22 @@ describe('requireOpsAccess', () => {
vi.stubEnv('NODE_ENV', 'production');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'learner');
const response = requireOpsAccess(new NextRequest('http://localhost/api/courses'));
const response = await requireOpsAccess(new NextRequest('http://localhost/api/courses'));
expect(response?.status).toBe(403);
await expect(response?.json()).resolves.toMatchObject({ errorCode: 'FORBIDDEN' });
});
it('fails closed when a production ops deployment has no access code', () => {
it('fails closed when a production ops deployment has no Works identity origin', async () => {
vi.stubEnv('NODE_ENV', 'production');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'ops');
vi.stubEnv('ACCESS_CODE', '');
const response = requireOpsAccess(new NextRequest('http://localhost/api/courses'));
const response = await requireOpsAccess(new NextRequest('http://localhost/api/courses'));
expect(response?.status).toBe(503);
});
it('accepts a valid access-code session on an ops deployment', () => {
vi.stubEnv('NODE_ENV', 'production');
it('accepts a valid access-code session only for development compatibility', async () => {
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'ops');
vi.stubEnv('ACCESS_CODE', 'test-access-code');
const token = createAccessToken('test-access-code');
@@ -35,11 +35,11 @@ describe('requireOpsAccess', () => {
headers: { cookie: `openmaic_access=${token}` },
});
expect(requireOpsAccess(request)).toBeNull();
await expect(requireOpsAccess(request)).resolves.toBeNull();
});
it('accepts a same-origin mutation with a valid ops session', () => {
vi.stubEnv('NODE_ENV', 'production');
it('accepts a same-origin mutation with a development ops session', async () => {
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'ops');
vi.stubEnv('ACCESS_CODE', 'test-access-code');
const token = createAccessToken('test-access-code');
@@ -51,17 +51,17 @@ describe('requireOpsAccess', () => {
},
});
expect(requireOpsAccess(request)).toBeNull();
await expect(requireOpsAccess(request)).resolves.toBeNull();
});
it('rejects missing or cross-origin mutation origins', async () => {
vi.stubEnv('NODE_ENV', 'production');
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'ops');
vi.stubEnv('ACCESS_CODE', 'test-access-code');
const token = createAccessToken('test-access-code');
for (const origin of [undefined, 'https://attacker.example']) {
const response = requireOpsAccess(
const response = await requireOpsAccess(
new NextRequest('https://ops.example/api/courses', {
method: 'POST',
headers: {
@@ -76,7 +76,7 @@ describe('requireOpsAccess', () => {
});
it('uses a configured public origin and never trusts forged forwarded hosts', async () => {
vi.stubEnv('NODE_ENV', 'production');
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'ops');
vi.stubEnv('ACCESS_CODE', 'test-access-code');
vi.stubEnv('ACCESS_CODE_TRUST_PROXY_HEADERS', 'true');
@@ -92,7 +92,7 @@ describe('requireOpsAccess', () => {
'x-forwarded-proto': 'https',
},
});
expect(requireOpsAccess(accepted)).toBeNull();
await expect(requireOpsAccess(accepted)).resolves.toBeNull();
const rejected = new NextRequest('http://internal:3000/api/courses', {
method: 'POST',
@@ -103,18 +103,18 @@ describe('requireOpsAccess', () => {
'x-forwarded-proto': 'https',
},
});
const response = requireOpsAccess(rejected);
const response = await requireOpsAccess(rejected);
expect(response?.status).toBe(403);
await expect(response?.json()).resolves.toMatchObject({ errorCode: 'FORBIDDEN' });
});
it('fails closed when the configured public origin is malformed', () => {
vi.stubEnv('NODE_ENV', 'production');
it('fails closed when the configured public origin is malformed', async () => {
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'ops');
vi.stubEnv('ACCESS_CODE', 'test-access-code');
vi.stubEnv('OPS_PUBLIC_ORIGIN', 'https://ops.example/path');
const token = createAccessToken('test-access-code');
const response = requireOpsAccess(
const response = await requireOpsAccess(
new NextRequest('https://ops.example/api/courses', {
method: 'POST',
headers: {
@@ -126,8 +126,8 @@ describe('requireOpsAccess', () => {
expect(response?.status).toBe(403);
});
it('keeps production role=all aligned with the ops session contract', () => {
vi.stubEnv('NODE_ENV', 'production');
it('keeps development role=all aligned with the ops session contract', async () => {
vi.stubEnv('NODE_ENV', 'development');
vi.stubEnv('OPENMAIC_DEPLOYMENT_ROLE', 'all');
vi.stubEnv('ACCESS_CODE', 'test-access-code');
const token = createAccessToken('test-access-code');
@@ -139,6 +139,6 @@ describe('requireOpsAccess', () => {
},
});
expect(requireOpsAccess(request)).toBeNull();
await expect(requireOpsAccess(request)).resolves.toBeNull();
});
});