Files
eden/tests/workflow-config.test.ts

52 lines
3.0 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).toMatch(/sync-worker:\n\s+profiles: \["worker"\]/);
expect(compose).toContain('CONVEX_SYNC_WORKER_SECRET: ${CONVEX_SYNC_WORKER_SECRET:-}');
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'");
});