50 lines
2.8 KiB
TypeScript
50 lines
2.8 KiB
TypeScript
import { expect, test } from 'bun:test';
|
|
import { readFileSync } from 'node:fs';
|
|
|
|
const workflow = readFileSync('.gitea/workflows/ci.yml', 'utf8');
|
|
const compose = readFileSync('compose.yaml', 'utf8');
|
|
const dockerfile = readFileSync('Dockerfile', 'utf8');
|
|
const dockerignore = readFileSync('.dockerignore', 'utf8');
|
|
const convexConfig = readFileSync('scripts/configure-convex.ts', 'utf8');
|
|
const chatRoute = readFileSync('src/routes/api/chat/+server.ts', 'utf8');
|
|
const syncRoute = readFileSync('src/routes/api/sync/+server.ts', 'utf8');
|
|
const layoutRoute = readFileSync('src/routes/+layout.server.ts', 'utf8');
|
|
|
|
test('Gitea workflow keeps source checks separate and holds unverified container CI', () => {
|
|
expect(workflow).toContain('pull_request:');
|
|
expect(workflow).toContain('if: ${{ false }}');
|
|
expect(workflow).toContain('GITHUB_RUN_ID is required');
|
|
expect(workflow).toContain('RELEASE_ENV=staging');
|
|
expect(workflow).toContain('bun run test:release-gates');
|
|
expect(workflow).toContain('docker compose config --quiet');
|
|
expect(workflow).toContain('docker build --build-arg APP_RELEASE_ID=fixture-ci');
|
|
expect(workflow).toContain('GITHUB_RUN_ATTEMPT');
|
|
expect(workflow).toContain('docker image rm "$image"');
|
|
expect(workflow).toContain('--network none');
|
|
});
|
|
|
|
test('Authenticated route limits remain user-keyed after rollout gates', () => {
|
|
expect(chatRoute).toContain('chat:${current.userId}');
|
|
expect(syncRoute).toContain('sync:${current.userId}');
|
|
expect(chatRoute.indexOf('protectMutation')).toBeLessThan(chatRoute.indexOf('const current = await session(event)'));
|
|
expect(syncRoute.indexOf('protectMutation')).toBeLessThan(syncRoute.indexOf('const current = await session(event)'));
|
|
expect(chatRoute.indexOf("capabilityEnabled('assistant_dispatch'")).toBeLessThan(chatRoute.indexOf('const current = await session(event)'));
|
|
expect(syncRoute.indexOf("capabilityEnabled('asset_sync'")).toBeLessThan(syncRoute.indexOf('const current = await session(event)'));
|
|
expect(layoutRoute).toContain('assistant_dispatch');
|
|
expect(layoutRoute).toContain('sessionNeeded');
|
|
});
|
|
|
|
test('Compose and Docker defaults are isolated and digest-pinned', () => {
|
|
expect(compose).toContain('CONVEX_BIND_ADDRESS:-127.0.0.1');
|
|
expect(compose).toContain('WEB_BIND_ADDRESS:-127.0.0.1');
|
|
expect(compose).toMatch(/CONVEX_IMAGE:-[^\n]*@sha256:[a-f0-9]{64}/);
|
|
expect(compose).toMatch(/CONVEX_DASHBOARD_IMAGE:-[^\n]*@sha256:[a-f0-9]{64}/);
|
|
const bases = [...dockerfile.matchAll(/^FROM\s+([^\s]+)/gim)].map((match) => match[1]);
|
|
expect(bases.length).toBeGreaterThan(0);
|
|
expect(bases.every((image) => /@sha256:[a-f0-9]{64}$/i.test(image))).toBe(true);
|
|
for (const pattern of ['*.pem', '*.key', '*.p12', '*.pfx', 'credentials*', 'secrets*', '.npmrc']) {
|
|
expect(dockerignore).toContain(pattern);
|
|
}
|
|
expect(convexConfig).toContain("'APP_CAPABILITY_ALLOWLIST'");
|
|
});
|