CodeBuild Spec Sandboxes for AI Coding Agents: Ephemeral Builds Without ECS Sprawl

11 views
Your agent wants to run npm test on a PR branch before it proposes a merge. You already have ephemeral ECS Fargate sandboxes for arbitrary tool execution — and they are the right hammer for long-lived interactive shells. For CI-shaped tool calls (lint, unit tests, typecheck, build artifacts), standing up another Fargate task family per language is sprawl. The unfair advantage is a CodeBuild project as a sandbox: buildspec-driven, privilegedMode: false by default, artifacts to S3, IAM scoped to one repo bucket, billed per build-minute.
⚡ TL;DR: Use CodeBuild when the agent tool is “run this buildspec on commit SHA X.” Keep ECS Fargate for interactive / custom sandboxes covered in Secure AI Sandboxes and LLM Coding Agents Lambda Sandboxes. Gate hallucinated AWS changes with Cursor Background Agents CI Gates. Never privileged: true unless you truly need Docker-in-Docker — and even then prefer CodeBuild’s managed images carefully.

CodeBuild Spec Sandboxes for AI Coding: production guidance

Signal Prefer CodeBuild Prefer ECS Fargate
Work is lint/test/build ✅
Need interactive shell / RDP-like session ✅
Want buildspec + CloudWatch Logs groups for free ✅
Custom long-running sidecar mesh ✅
Cost for 2–10 min CI-like bursts ✅ often cheaper cold start + task overhead
Already covered Fargate patterns elsewhere Use this post See sandbox post
CodeBuild is build-centric: source in, commands, artifacts out. That matches how coding agents validate patches.

Project shape: buildspec, not a snowflake container

yaml
# buildspec.yml — checked into the repo the agent is patching
version: 0.2
env:
 variables:
 NODE_OPTIONS: "--max-old-space-size=2048"
 # ❌ Do not put SaaS tokens in plaintext env here — use Secrets Manager
 # secrets-manager:
 # GITHUB_TOKEN: agent/$TENANT/github_pr_read:token
phases:
 install:
 runtime-versions:
 nodejs: 20
 commands:
 - npm ci --ignore-scripts
 pre_build:
 commands:
 - npm run lint
 build:
 commands:
 - npm test -- --ci
 - npm run typecheck
artifacts:
 files:
 - "coverage/**/*"
 - "junit.xml"
 name: agent-build-$(date +%Y%m%d%H%M%S)
✅ Agent tool submits sourceVersion = commit SHA or PR ref; it does not invent shell scripts ad hoc when a buildspec already defines the contract.

Start builds from the agent tool (TypeScript)

typescript
import {
 CodeBuildClient,
 StartBuildCommand,
 BatchGetBuildsCommand,
} from "@aws-sdk/client-codebuild";

const cb = new CodeBuildClient({});

export async function runPrSandboxBuild(input: {
 projectName: string;
 sourceVersion: string; // commit SHA
 tenantId: string;
 idempotencyKey: string;
}) {
 // ✅ Idempotency: if you already started this key, return prior build id
 const start = await cb.send(
 new StartBuildCommand({
 projectName: input.projectName,
 sourceVersion: input.sourceVersion,
 environmentVariablesOverride: [
 { name: "TENANT_ID", value: input.tenantId, type: "PLAINTEXT" },
 {
 name: "IDEMPOTENCY_KEY",
 value: input.idempotencyKey,
 type: "PLAINTEXT",
 },
 ],
 // Optional: buildspec override only for allowlisted extra steps
 })
 );

 const buildId = start.build?.id;
 if (!buildId) throw new Error("no_build_id");

 // Poll with timeout — do not hold a Bedrock turn open forever;
 // prefer async tool + EventBridge like agent async tools pattern
 for (let i = 0; i < 60; i++) {
 await new Promise((r) => setTimeout(r, 5000));
 const got = await cb.send(
 new BatchGetBuildsCommand({ ids: [buildId] })
 );
 const build = got.builds?.[0];
 const status = build?.buildStatus;
 if (status && status !== "IN_PROGRESS") {
 return {
 buildId,
 status,
 logLink: build?.logs?.deepLink,
 artifacts: build?.artifacts?.location,
 };
 }
 }
 return { buildId, status: "TIMEOUT_WAITING", artifacts: null };
}
For multi-turn agents, prefer async: StartBuild → EventBridge rule on CodeBuild state change → resume agent session (same idea as Bedrock Agents + EventBridge async tools).

IAM role scoped to the repo bucket

The CodeBuild service role should not be the agent runtime role.
json
{
 "Version": "2012-10-17",
 "Statement": [
 {
 "Sid": "ReadOnlySourceBucket",
 "Effect": "Allow",
 "Action": ["s3:GetObject", "s3:GetObjectVersion"],
 "Resource": "arn:aws:s3:::acme-agent-src/tenant-${tenant}/*"
 },
 {
 "Sid": "WriteArtifactsPrefix",
 "Effect": "Allow",
 "Action": ["s3:PutObject"],
 "Resource": "arn:aws:s3:::acme-agent-artifacts/tenant-${tenant}/*"
 },
 {
 "Sid": "Logs",
 "Effect": "Allow",
 "Action": [
 "logs:CreateLogGroup",
 "logs:CreateLogStream",
 "logs:PutLogEvents"
 ],
 "Resource": "arn:aws:logs:*:*:log-group:/aws/codebuild/agent-*"
 },
 {
 "Sid": "DenyPrivilegeEscalation",
 "Effect": "Deny",
 "Action": [
 "iam:PassRole",
 "sts:AssumeRole",
 "ec2:Create*",
 "lambda:Create*",
 "sagemaker:*"
 ],
 "Resource": "*"
 }
 ]
}
Agent runtime IAM may only codebuild:StartBuild / BatchGetBuilds on the specific project ARN, with tags — see IAM Condition Keys for Agent Runtimes.

Privileged false, VPC optional

typescript
// CDK-ish environment block
environment: {
 buildImage: codebuild.LinuxBuildImage.STANDARD_7_0,
 privileged: false, // ✅ default for agent sandboxes
 computeType: codebuild.ComputeType.SMALL,
 // vpc: optional — only if tests need private RDS / internal npm
}
❌ Patterns:
  • privileged: true “because npm might need Docker” — use a prebuilt image or CodeBuild’s Docker support only with a dedicated project and tighter controls
  • Agent-supplied buildspecOverride that runs curl | bash from a model-generated URL
  • Shared project across tenants without prefix isolation on source/artifact paths
✅ Allowlist buildspec overrides to a few static snippets you own; prefer repo buildspec at the commit SHA the agent is testing.

Compare briefly to ECS Fargate sandboxes

ECS Fargate sandboxes shine when the agent needs a mutable workspace, package installs outside a fixed buildspec, or binary tools you do not want in CodeBuild images. They cost more operational surface (task defs, networking, teardown watchdogs). CodeBuild gives you:
  • Managed images and log streaming
  • Native artifact export
  • Per-build isolation without a task-def zoo
Use Lambda sandboxes for tiny ephemeral snippets; CodeBuild for repo-scale CI; ECS for interactive/custom. Do not collapse all three into one “agent runner.”

Debugging agent-triggered builds

  • Always return logs.deepLink to the agent tool result (redact secrets in build logs separately).
  • On FAULT / TIMED_OUT, surface buildStatus + phase failure — models otherwise retry forever.
  • Cap concurrent builds per tenant (CodeBuild account limits + your own DynamoDB semaphore).
  • Store junit/coverage artifacts and let a second tool summarize — do not dump megabyte logs into the Bedrock context.
typescript
// ✅ Tool result stays small
return {
 status: "FAILED",
 failedPhase: "BUILD",
 summary: "3 tests failed in auth.test.ts",
 logLink,
 artifactUri,
};

Checklist

  • [ ] CI-like agent tools use CodeBuild; interactive shells stay on ECS
  • [ ] privilegedMode: false unless a dedicated hardened project requires otherwise
  • [ ] Service role scoped to tenant-prefixed source + artifact buckets
  • [ ] Agent role can StartBuild only on named projects (tag conditions)
  • [ ] No model-controlled arbitrary buildspec from untrusted URLs
  • [ ] Prefer async StartBuild + EventBridge resume over long polling in a Converse turn
  • [ ] Idempotency key per (tenant, SHA, suite) to prevent build storms
  • [ ] Tool results return status + log link + short summary, not full logs
CodeBuild will not replace every sandbox. It will replace the expensive habit of launching Fargate every time an agent only needed npm test on a SHA. Related: Day 57: Coding Agents That Only Emit Intents; Day 70: Project: Secure Coding-Agent Sandbox on ECS Fargate; Building Production AI Agents: Tool Calling, Memory, and Orchestration That Actually Work.

Watch: 100 Days of AI on YouTube

Short videos from CheatCoders, one AI engineering topic per day.

Open the playlist on YouTube · CheatCoders on YouTube

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.