Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion service/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ ENV NODE_ENV=production
WORKDIR /app
COPY --from=install /temp/prod/node_modules ./node_modules
COPY --from=builder /app/.build-egress-gateway ./.build-egress-gateway
CMD ["bun", "run", ".build-egress-gateway/egress-gateway.js"]
CMD ["bun", "run", "--max-http-header-size=262144", ".build-egress-gateway/egress-gateway.js"]

# Development stage
FROM base AS development
Expand Down
4 changes: 2 additions & 2 deletions service/Dockerfile.egress-gateway
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ COPY packages/code/src /packages/code/src
EXPOSE 3190
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3190/health || exit 1
CMD ["bun", "run", "src/egress-gateway.ts"]
CMD ["bun", "run", "--max-http-header-size=262144", "src/egress-gateway.ts"]

FROM base AS development
ENV NODE_ENV=development
Expand All @@ -31,4 +31,4 @@ COPY service/src ./src
COPY shared /shared
COPY packages/code/src /packages/code/src
EXPOSE 3190 9230
CMD ["bun", "run", "--watch", "src/egress-gateway.ts"]
CMD ["bun", "run", "--watch", "--max-http-header-size=262144", "src/egress-gateway.ts"]
2 changes: 1 addition & 1 deletion service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"start:api:dev": "ts-node src/api-server.ts",
"start:worker": "node .build-service/src/worker-server.js",
"start:worker:dev": "ts-node src/worker-server.ts",
"start:egress-gateway": "bun run src/egress-gateway.ts",
"start:egress-gateway": "bun run --max-http-header-size=262144 src/egress-gateway.ts",
"build": "rollup -c",
"deploy": "serverless deploy",
"test": "bun test ./src/*.test.ts ./src/*.spec.ts ./src/**/*.test.ts ./src/**/*.spec.ts",
Expand Down
49 changes: 49 additions & 0 deletions service/src/egress-headers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { test, expect } from 'bun:test';
import { mkdtempSync, readFileSync, writeFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

test('deployed egress command accepts scoped grants above 16 KiB, with a finite cap', async () => {
const dockerfile = readFileSync(new URL('../Dockerfile.egress-gateway', import.meta.url), 'utf8');
const command: string[] = JSON.parse(dockerfile.match(/^CMD (.+)$/m)![1]);
const bundledDockerfile = readFileSync(new URL('../Dockerfile', import.meta.url), 'utf8');
const commands: string[][] = [...dockerfile.matchAll(/^CMD (.+)$/gm),
...bundledDockerfile.matchAll(/^CMD (.+egress-gateway.+)$/gm)]
.map(match => JSON.parse(match[1]));
const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
commands.push(packageJson.scripts['start:egress-gateway'].split(' '));
expect(commands).toHaveLength(4);
for (const entrypoint of commands) expect(entrypoint).toContain('--max-http-header-size=262144');
const probe = `
const http = require('node:http');
const server = http.createServer((req, res) => res.end('ok'));
server.listen(0, '127.0.0.1', async () => {
try {
const statuses = [];
for (const size of [32768, 280000]) {
const response = await fetch('http://127.0.0.1:' + server.address().port, {
headers: { 'X-CodeAPI-Egress-Grant': 'a'.repeat(size) },
});
statuses.push(response.status);
await response.text();
}
console.log(JSON.stringify(statuses));
} finally { server.close(); }
});`;
const directory = mkdtempSync(join(tmpdir(), 'codeapi-header-test-'));
const script = join(directory, 'probe.cjs');
writeFileSync(script, probe);
const run = async (options: string[]) => {
const child = Bun.spawn([process.execPath, ...options, script], { stdout: 'pipe', stderr: 'pipe' });
const stdout = await new Response(child.stdout).text();
const stderr = await new Response(child.stderr).text();
if (await child.exited !== 0) throw new Error(stderr);
expect(await child.exited).toBe(0);
return JSON.parse(stdout);
};
try {
expect(await run(['run'])).toEqual([431, 431]);
// Preserve the deployed command's argument order, replacing only the file.
expect(await run(command.slice(1, -1))).toEqual([200, 431]);
} finally { rmSync(directory, { recursive: true }); }
});