Skip to content

Commit 750fd49

Browse files
mchwangclaude
andcommitted
Carry D2 seccomp pinning into the egress proxy
Request and require Docker's builtin seccomp profile for the vendor egress proxy too, and port D2's new regressions to the named isolation probes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent fcb7e65 commit 750fd49

2 files changed

Lines changed: 8 additions & 7 deletions

File tree

‎agents/network/network.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ const validateVendorNetwork = (network: VendorNetwork, invocation: InvocationInp
8484
if (!inspect?.State?.Running || inspect.Config?.Image !== identity.imageId || inspect.Config?.User !== '10001:10001'
8585
|| inspect.Config?.Labels?.['io.codeboost.egress'] !== identity.allocationId || !inspect.HostConfig?.ReadonlyRootfs
8686
|| inspect.HostConfig.Privileged || !inspect.HostConfig.CapDrop?.map(value => value.toUpperCase()).includes('ALL')
87-
|| (inspect.HostConfig.CapAdd?.length ?? 0) || inspect.HostConfig.SecurityOpt?.length !== 1
88-
|| !['no-new-privileges', 'no-new-privileges:true'].includes(inspect.HostConfig.SecurityOpt[0] ?? '')
87+
|| (inspect.HostConfig.CapAdd?.length ?? 0) || inspect.HostConfig.SecurityOpt?.length !== 2
88+
|| !inspect.HostConfig.SecurityOpt.some(option => ['no-new-privileges', 'no-new-privileges:true'].includes(option))
89+
|| !inspect.HostConfig.SecurityOpt.includes('seccomp=builtin')
8990
|| inspect.HostConfig.PidsLimit !== 64 || inspect.HostConfig.Memory !== 64 * 1024 * 1024
9091
|| inspect.HostConfig.MemorySwap !== 64 * 1024 * 1024 || inspect.HostConfig.NanoCpus !== 250_000_000
9192
|| inspect.HostConfig.NetworkMode !== network.name || inspect.HostConfig.PidMode !== ''
@@ -130,7 +131,7 @@ export function createVendorNetwork(invocation: InvocationInput, imageId: string
130131
'--label', `io.codeboost.egress=${allocationId}`, name], remaining());
131132
proxyPlanned = true;
132133
docker(['run', '--detach', '--name', proxyContainer, '--read-only', '--user', '10001:10001',
133-
'--cap-drop=ALL', '--security-opt=no-new-privileges', '--pids-limit=64', '--memory=64m', '--memory-swap=64m',
134+
'--cap-drop=ALL', '--security-opt=no-new-privileges', '--security-opt=seccomp=builtin', '--pids-limit=64', '--memory=64m', '--memory-swap=64m',
134135
'--cpus=.25', '--network', name, '--network-alias', 'codeboost-proxy',
135136
'--label', `io.codeboost.egress=${allocationId}`, '--env', `CODEBOOST_ALLOWED_HOSTS=${VENDOR_HOSTS[vendor].join(',')}`,
136137
'--entrypoint', 'node', imageId, '/usr/local/lib/codeboost-egress-proxy.mjs'], remaining());

‎test/agent-container.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ describe('real Docker agent isolation', () => {
278278
}, 60_000);
279279

280280
it('retains credentials when a killed create cannot be proven absent', () => {
281-
const data = fixture(), unsettled = profile(data, 'planning', ['true']);
281+
const data = fixture(), unsettled = profile(data, 'planning', 'noop');
282282
const shim = join(data.root, 'docker-shim'); mkdirSync(shim);
283283
const realDocker = execFileSync('sh', ['-c', 'command -v docker'], { encoding: 'utf8' }).trim();
284284
// The create client hangs until its deadline kills it, so the daemon outcome stays unknown.
@@ -303,7 +303,7 @@ describe('real Docker agent isolation', () => {
303303
}, 60_000);
304304

305305
it('rejects a container that relies on the daemon default seccomp profile', () => {
306-
const data = fixture(), valid = profile(data, 'planning', ['true']);
306+
const data = fixture(), valid = profile(data, 'planning', 'noop');
307307
docker(...valid.args.filter(arg => arg !== '--security-opt=seccomp=builtin')); containers.add(valid.name);
308308
expect(() => validateContainer(valid.name, valid)).toThrow('lockdown');
309309
docker('rm', '--force', valid.name); containers.delete(valid.name);
@@ -320,11 +320,11 @@ describe('real Docker agent isolation', () => {
320320
it('refuses a Codex auth path that is a link without resolving it', () => {
321321
const data = fixture(), link = join(data.root, 'auth-link.json');
322322
symlinkSync(data.fakeAuth, link);
323-
expect(() => profile(data, 'planning', ['true'], { codexAuthFile: link })).toThrow('not a link');
323+
expect(() => profile(data, 'planning', 'noop', { codexAuthFile: link })).toThrow('not a link');
324324
}, 60_000);
325325

326326
it('rejects a restart policy that could relaunch the agent after it exits', () => {
327-
const data = fixture(), valid = profile(data, 'planning', ['true']);
327+
const data = fixture(), valid = profile(data, 'planning', 'noop');
328328
const imageIndex = valid.args.indexOf(imageId);
329329
docker(...valid.args.slice(0, imageIndex), '--restart=always', ...valid.args.slice(imageIndex));
330330
containers.add(valid.name);

0 commit comments

Comments
 (0)