diff --git a/src/cli.ts b/src/cli.ts index caf480d7..fa5fa9a2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -389,10 +389,12 @@ program ) .option( '--agent-base-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( @@ -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); + } } } diff --git a/src/docker-manager.test.ts b/src/docker-manager.test.ts index 1029e036..d24651ad 100644 --- a/src/docker-manager.test.ts +++ b/src/docker-manager.test.ts @@ -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, diff --git a/src/docker-manager.ts b/src/docker-manager.ts index 5bbb7b05..2da359e3 100644 --- a/src/docker-manager.ts +++ b/src/docker-manager.ts @@ -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 = { // Pass host UID/GID to match file ownership in container diff --git a/src/types.ts b/src/types.ts index 966b195f..810f7b74 100644 --- a/src/types.ts +++ b/src/types.ts @@ -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 *