Skip to content
Closed
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
38 changes: 24 additions & 14 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,12 @@ program
)
.option(
'--agent-base-image <image>',
'Base image for agent container when using --build-local. Options:\n' +
'Base image for agent container. Options:\n' +
' ubuntu:22.04 (default): Minimal, ~200MB\n' +
' ghcr.io/catthehacker/ubuntu:runner-22.04: Closer to GitHub Actions, ~2-5GB\n' +
' ghcr.io/catthehacker/ubuntu:full-22.04: Near-identical to GitHub Actions, ~20GB',
' act: Pre-built image with GitHub Actions parity (uses GHCR agent-act image)\n' +
' With --build-local, can also use:\n' +
' ghcr.io/catthehacker/ubuntu:runner-22.04: ~2-5GB\n' +
' ghcr.io/catthehacker/ubuntu:full-22.04: ~20GB',
'ubuntu:22.04'
)
.option(
Expand Down Expand Up @@ -683,19 +685,27 @@ program
allowedUrls,
};

// Validate and warn if using custom agent base image
// Validate and handle custom agent base image
if (options.agentBaseImage && options.agentBaseImage !== 'ubuntu:22.04') {
// Validate against approved base images for supply chain security
const validation = validateAgentBaseImage(options.agentBaseImage);
if (!validation.valid) {
logger.error(validation.error!);
process.exit(1);
}

if (options.buildLocal) {
logger.info(`Using custom agent base image: ${options.agentBaseImage}`);
// Special case: 'act' uses pre-built GHCR image (no --build-local needed)
if (options.agentBaseImage === 'act') {
config.useAgentActImage = true;
logger.info('Using pre-built agent-act image with GitHub Actions parity');
} else {
logger.warn('⚠️ --agent-base-image is only used with --build-local. Ignoring.');
// Validate against approved base images for supply chain security
const validation = validateAgentBaseImage(options.agentBaseImage);
if (!validation.valid) {
logger.error(validation.error!);
process.exit(1);
}

if (options.buildLocal) {
logger.info(`Using custom agent base image: ${options.agentBaseImage}`);
} else {
logger.warn('⚠️ --agent-base-image requires --build-local for custom images.');
logger.warn(' Use --agent-base-image act for pre-built GitHub Actions parity image.');
process.exit(1);
}
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/docker-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,21 @@ describe('docker-manager', () => {
expect(result.services.agent.build?.args?.BASE_IMAGE).toBe('ghcr.io/catthehacker/ubuntu:full-22.04@sha256:a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1');
});

it('should use agent-act image when useAgentActImage is true', () => {
const actImageConfig = { ...mockConfig, useAgentActImage: true };
const result = generateDockerCompose(actImageConfig, mockNetworkConfig);

expect(result.services.agent.image).toBe('ghcr.io/githubnext/gh-aw-firewall/agent-act:latest');
expect(result.services.agent.build).toBeUndefined();
});

it('should use default agent image when useAgentActImage is false', () => {
const defaultConfig = { ...mockConfig, useAgentActImage: false };
const result = generateDockerCompose(defaultConfig, mockNetworkConfig);

expect(result.services.agent.image).toBe('ghcr.io/githubnext/gh-aw-firewall/agent:latest');
});

it('should not pass BASE_IMAGE when agentBaseImage is explicitly set to default ubuntu:22.04', () => {
const customBaseImageConfig = {
...mockConfig,
Expand Down
4 changes: 3 additions & 1 deletion src/docker-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,9 @@ export function generateDockerCompose(

// Use GHCR image or build locally
if (useGHCR) {
agentService.image = `${registry}/agent:${tag}`;
// Use agent-act image if requested for GitHub Actions parity
const agentImageName = config.useAgentActImage ? 'agent-act' : 'agent';
agentService.image = `${registry}/${agentImageName}:${tag}`;
} else {
const buildArgs: Record<string, string> = {
// Pass host UID/GID to match file ownership in container
Expand Down
19 changes: 16 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,20 +149,33 @@ export interface WrapperConfig {

/**
* Base image for the agent container when building locally
*
*
* Allows customization of the agent container base image for closer parity
* with GitHub Actions runner environments. Only used when buildLocal is true.
*
*
* Options:
* - 'ubuntu:22.04' (default): Minimal image, smallest size (~200MB)
* - 'ghcr.io/catthehacker/ubuntu:runner-22.04': Closer to GitHub Actions runner (~2-5GB)
* - 'ghcr.io/catthehacker/ubuntu:full-22.04': Near-identical to GitHub Actions runner (~20GB compressed)
*
*
* @default 'ubuntu:22.04'
* @example 'ghcr.io/catthehacker/ubuntu:runner-22.04'
*/
agentBaseImage?: string;

/**
* Use the pre-built agent-act image from GHCR for GitHub Actions parity
*
* When true, uses ghcr.io/githubnext/gh-aw-firewall/agent-act instead of
* the default agent image. This image is built with catthehacker/ubuntu:act-24.04
* as the base for better GitHub Actions runner compatibility.
*
* Set via --agent-base-image act
*
* @default false
*/
useAgentActImage?: boolean;

/**
* Additional environment variables to pass to the agent execution container
*
Expand Down
Loading