Skip to content

feat(cli): add predownload command to pre-pull container images#1245

Open
Mossaka wants to merge 3 commits intomainfrom
feat/103-predownload-images
Open

feat(cli): add predownload command to pre-pull container images#1245
Mossaka wants to merge 3 commits intomainfrom
feat/103-predownload-images

Conversation

@Mossaka
Copy link
Collaborator

@Mossaka Mossaka commented Mar 11, 2026

Summary

  • Adds awf predownload subcommand that pre-pulls Docker container images ahead of time
  • Supports --image-registry, --image-tag, --agent-image, and --enable-api-proxy flags
  • After predownloading, users can use --skip-pull to avoid pulling images at runtime
  • 5 unit tests for image resolution logic

Fixes #193

Test plan

  • Verify awf predownload pulls squid and agent images
  • Verify awf predownload --agent-image act pulls agent-act image
  • Verify awf predownload --enable-api-proxy also pulls api-proxy
  • Verify awf predownload --image-tag v1.0.0 uses correct tag
  • Verify awf predownload followed by awf --skip-pull ... works

🤖 Generated with Claude Code

Adds `awf predownload` subcommand that pulls Docker images ahead of time
for offline use or faster startup. Supports --image-registry, --image-tag,
--agent-image, and --enable-api-proxy flags. After predownloading, users
can use --skip-pull to avoid pulling at runtime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 11, 2026 18:51
@github-actions
Copy link
Contributor

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

Metric Base PR Delta
Lines 82.50% 82.13% 📉 -0.37%
Statements 82.50% 82.13% 📉 -0.37%
Functions 82.69% 81.60% 📉 -1.09%
Branches 74.78% 74.78% ➡️ +0.00%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/cli.ts 47.0% → 46.9% (-0.11%) 47.5% → 47.4% (-0.11%)
src/docker-manager.ts 84.0% → 84.5% (+0.54%) 83.3% → 83.8% (+0.52%)
✨ New Files (1 files)
  • src/commands/predownload.ts: 50.0% lines

Coverage comparison generated by scripts/ci/compare-coverage.ts

Add 5 tests covering the predownloadCommand async function: successful
pull of all images, api-proxy inclusion, process.exit on failure,
continued pulling after partial failure, and non-Error rejection handling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new awf predownload CLI subcommand to pre-pull the Docker images used by AWF ahead of time, enabling faster startup and supporting offline/air-gapped workflows when combined with --skip-pull.

Changes:

  • Introduces src/commands/predownload.ts with image-resolution logic and a pull loop invoking docker pull.
  • Adds unit tests for image resolution in src/commands/predownload.test.ts.
  • Wires the new predownload subcommand into src/cli.ts with flags for registry/tag/agent image selection and api-proxy inclusion.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/commands/predownload.ts Implements image list resolution + executes docker pull for each resolved image.
src/commands/predownload.test.ts Tests resolveImages behavior for presets, custom images, and api-proxy inclusion.
src/cli.ts Adds the predownload subcommand and exposes relevant flags.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +22 to +26
const isPreset = agentImage === 'default' || agentImage === 'act';
if (isPreset) {
const imageName = agentImage === 'act' ? 'agent-act' : 'agent';
images.push(`${imageRegistry}/${imageName}:${imageTag}`);
} else {
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveImages re-implements the same preset-to-image mapping logic that already exists in generateDockerCompose (e.g., default→agent, act→agent-act). This duplication is likely to drift as image naming/registry/tag logic evolves (including api-proxy behavior). Consider extracting a shared image-resolution helper used by both generateDockerCompose and this command so the pulled images always match what runtime would use.

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +29
} else {
// Custom image - pull as-is
images.push(agentImage);
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom agentImage values are passed directly as the docker pull image reference. If the value contains whitespace or starts with -, Docker will treat it as invalid or as a flag (e.g. --help) rather than an image, leading to confusing behavior. Add lightweight validation (e.g., reject leading - / any whitespace, or validate against a Docker image reference regex) before adding it to the pull list.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +61
logger.error(`${failed} of ${images.length} image(s) failed to pull`);
process.exit(1);
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The failure path exits the process, but predownloadCommand itself isn’t covered by tests (only resolveImages is). Adding unit tests that mock execa and process.exit would catch regressions in pull invocation, failure counting, and exit-code behavior.

Suggested change
logger.error(`${failed} of ${images.length} image(s) failed to pull`);
process.exit(1);
const message = `${failed} of ${images.length} image(s) failed to pull`;
logger.error(message);
const error: Error & { exitCode?: number } = new Error(message);
error.exitCode = 1;
throw error;

Copilot uses AI. Check for mistakes.
src/cli.ts Outdated
Comment on lines +1294 to +1301
.option('--image-tag <tag>', 'Container image tag', 'latest')
.option(
'--agent-image <value>',
'Agent image preset (default, act) or custom image',
'default'
)
.option('--enable-api-proxy', 'Also download the API proxy image', false)
.action(async (options) => {
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--image-tag here affects squid/agent and (when --enable-api-proxy is set) also the api-proxy image. Consider updating the option help text to make that explicit, to match actual behavior and reduce confusion for users.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Contributor

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

Metric Base PR Delta
Lines 82.50% 82.82% 📈 +0.32%
Statements 82.50% 82.80% 📈 +0.30%
Functions 82.69% 82.07% 📉 -0.62%
Branches 74.78% 75.12% 📈 +0.34%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/cli.ts 47.0% → 46.9% (-0.11%) 47.5% → 47.4% (-0.11%)
src/docker-manager.ts 84.0% → 84.5% (+0.54%) 83.3% → 83.8% (+0.52%)
✨ New Files (1 files)
  • src/commands/predownload.ts: 100.0% lines

Coverage comparison generated by scripts/ci/compare-coverage.ts

Extract predownload action handler to named exported function and add
unit test to maintain function coverage levels.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Contributor

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 82.50% 82.92% 📈 +0.42%
Statements 82.50% 82.90% 📈 +0.40%
Functions 82.69% 83.01% 📈 +0.32%
Branches 74.78% 75.12% 📈 +0.34%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/cli.ts 47.0% → 47.6% (+0.54%) 47.5% → 48.0% (+0.52%)
src/docker-manager.ts 84.0% → 84.5% (+0.54%) 83.3% → 83.8% (+0.52%)
✨ New Files (1 files)
  • src/commands/predownload.ts: 100.0% lines

Coverage comparison generated by scripts/ci/compare-coverage.ts

@github-actions
Copy link
Contributor

test: expand credential hiding tests to all 14 protected paths
test(docker): verify capsh execution chain after PR #715
GitHub MCP review: ✅
safeinputs-gh pr list: ✅
playwright title check: ✅
tavily search: ❌ (tool unavailable)
file write+cat: ✅
discussion query+comment: ✅
build (npm ci && npm run build): ✅
Overall: FAIL

🔮 The oracle has spoken through Smoke Codex for issue #1245

@github-actions
Copy link
Contributor

🤖 Smoke test results for run 22969455364@Mossaka

Test Status
GitHub MCP (last 2 merged PRs) #1240 "test(docker): verify capsh execution chain after PR #715", #1232 "fix(cli): clear LD_PRELOAD after one-shot-token library loads"
Playwright (github.com title contains "GitHub")
File write /tmp/gh-aw/agent/smoke-test-copilot-22969455364.txt
Bash (cat file verify)

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot for issue #1245

@github-actions
Copy link
Contributor

Smoke Test Results — PASS

💥 [THE END] — Illustrated by Smoke Claude for issue #1245

@github-actions
Copy link
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.12 Python 3.12.3 ❌ NO
Node.js v24.14.0 v20.20.0 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Result: ❌ Not all tests passed — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot for issue #1245

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Predownload images

2 participants