From 8ed9993c6288d313103048aa6fab0619335e4ec2 Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Wed, 25 Feb 2026 20:01:15 +0000 Subject: [PATCH 1/3] fix(docker): copy logging, metrics, rate-limiter modules into api-proxy image The Dockerfile only copied server.js but server.js now requires logging.js, metrics.js, and rate-limiter.js. Without these files the container exits immediately on startup, causing all agentic workflow CI jobs to fail. Co-Authored-By: Claude Opus 4.6 (1M context) --- containers/api-proxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/api-proxy/Dockerfile b/containers/api-proxy/Dockerfile index 505ec49c..bb491982 100644 --- a/containers/api-proxy/Dockerfile +++ b/containers/api-proxy/Dockerfile @@ -15,7 +15,7 @@ COPY package*.json ./ RUN npm ci --omit=dev # Copy application files -COPY server.js ./ +COPY server.js logging.js metrics.js rate-limiter.js ./ # Create non-root user RUN addgroup -S apiproxy && adduser -S apiproxy -G apiproxy From 07969d4d03ae1bfaa608a8aa53db441e2f93585b Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Wed, 25 Feb 2026 20:12:30 +0000 Subject: [PATCH 2/3] test: add package installation integration tests Add a "Package Installation" describe block to chroot-package-managers tests that verifies actual package installation through the AWF proxy: - pip install requests with pypi.org + files.pythonhosted.org allowed - npm install chalk@4 with registry.npmjs.org allowed - cargo build with a dependency (cfg-if) with crates.io domains allowed Each test verifies the package was actually installed (import/require/build). Closes #1044 Co-Authored-By: Claude Opus 4.6 --- .../chroot-package-managers.test.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/integration/chroot-package-managers.test.ts b/tests/integration/chroot-package-managers.test.ts index 54de5c0f..2ce89d1f 100644 --- a/tests/integration/chroot-package-managers.test.ts +++ b/tests/integration/chroot-package-managers.test.ts @@ -349,4 +349,58 @@ describe('Chroot Package Manager Support', () => { expect(result.stdout).toContain('module test'); }, 120000); }); + + // ---------- Package Installation ---------- + describe('Package Installation', () => { + test('should install a Python package via pip and verify import', async () => { + const result = await runner.runWithSudo( + 'pip3 install --target /tmp/pip-test requests 2>&1 && ' + + 'PYTHONPATH=/tmp/pip-test python3 -c "import requests; print(requests.__version__)"', + { + allowDomains: ['pypi.org', 'files.pythonhosted.org'], + logLevel: 'debug', + timeout: 120000, + } + ); + + expect(result).toSucceed(); + // The last line of output should be the version string + expect(result.stdout).toMatch(/\d+\.\d+\.\d+/); + }, 180000); + + test('should install an npm package and verify require', async () => { + const result = await runner.runWithSudo( + 'cd /tmp && mkdir -p npm-test && cd npm-test && npm init -y 2>&1 && ' + + 'npm install chalk@4 2>&1 && ' + + 'node -e "require(\'/tmp/npm-test/node_modules/chalk\')" && echo "npm_install_ok"', + { + allowDomains: ['registry.npmjs.org'], + logLevel: 'debug', + timeout: 120000, + } + ); + + expect(result).toSucceed(); + expect(result.stdout).toContain('npm_install_ok'); + }, 180000); + + test('should build a Rust project with a dependency via cargo', async () => { + const result = await runner.runWithSudo( + 'TESTDIR=$(mktemp -d) && cd $TESTDIR && ' + + 'cargo init --name awftest 2>&1 && ' + + // Add a small dependency (cfg-if is tiny with no transitive deps) + 'echo \'cfg-if = "1"\' >> Cargo.toml && ' + + 'cargo build 2>&1 && echo "cargo_build_ok" && ' + + 'rm -rf $TESTDIR', + { + allowDomains: ['crates.io', 'static.crates.io', 'index.crates.io'], + logLevel: 'debug', + timeout: 120000, + } + ); + + expect(result).toSucceed(); + expect(result.stdout).toContain('cargo_build_ok'); + }, 180000); + }); }); From 1c0791d8638c29291376fcf484f17561a23f47bb Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Wed, 25 Feb 2026 20:27:04 +0000 Subject: [PATCH 3/3] fix: address review feedback for package install tests - Use mktemp dirs instead of fixed /tmp paths (avoid cross-run contamination) - Add --no-cache-dir to pip install (ensure real download) - Assert pip version on last line specifically (not just anywhere in stdout) - Use NODE_PATH for npm require instead of absolute path - Force CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse for deterministic behavior - Ensure temp dir cleanup via trap pattern (EC=$?; rm -rf; exit $EC) - Revert unrelated api-proxy Dockerfile change Co-Authored-By: Claude Opus 4.6 --- containers/api-proxy/Dockerfile | 2 +- .../chroot-package-managers.test.ts | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/containers/api-proxy/Dockerfile b/containers/api-proxy/Dockerfile index bb491982..505ec49c 100644 --- a/containers/api-proxy/Dockerfile +++ b/containers/api-proxy/Dockerfile @@ -15,7 +15,7 @@ COPY package*.json ./ RUN npm ci --omit=dev # Copy application files -COPY server.js logging.js metrics.js rate-limiter.js ./ +COPY server.js ./ # Create non-root user RUN addgroup -S apiproxy && adduser -S apiproxy -G apiproxy diff --git a/tests/integration/chroot-package-managers.test.ts b/tests/integration/chroot-package-managers.test.ts index 2ce89d1f..bed977dc 100644 --- a/tests/integration/chroot-package-managers.test.ts +++ b/tests/integration/chroot-package-managers.test.ts @@ -354,8 +354,10 @@ describe('Chroot Package Manager Support', () => { describe('Package Installation', () => { test('should install a Python package via pip and verify import', async () => { const result = await runner.runWithSudo( - 'pip3 install --target /tmp/pip-test requests 2>&1 && ' + - 'PYTHONPATH=/tmp/pip-test python3 -c "import requests; print(requests.__version__)"', + 'PIPDIR=$(mktemp -d) && ' + + 'pip3 install --no-cache-dir --target $PIPDIR requests 2>&1 && ' + + 'PYTHONPATH=$PIPDIR python3 -c "import requests; print(requests.__version__)" && ' + + 'rm -rf $PIPDIR', { allowDomains: ['pypi.org', 'files.pythonhosted.org'], logLevel: 'debug', @@ -364,15 +366,17 @@ describe('Chroot Package Manager Support', () => { ); expect(result).toSucceed(); - // The last line of output should be the version string - expect(result.stdout).toMatch(/\d+\.\d+\.\d+/); + const lines = result.stdout.split('\n').map(l => l.trim()).filter(l => l.length > 0); + const lastLine = lines[lines.length - 1] || ''; + expect(lastLine).toMatch(/^\d+\.\d+\.\d+$/); }, 180000); test('should install an npm package and verify require', async () => { const result = await runner.runWithSudo( - 'cd /tmp && mkdir -p npm-test && cd npm-test && npm init -y 2>&1 && ' + + 'NPMDIR=$(mktemp -d) && cd $NPMDIR && npm init -y 2>&1 && ' + 'npm install chalk@4 2>&1 && ' + - 'node -e "require(\'/tmp/npm-test/node_modules/chalk\')" && echo "npm_install_ok"', + 'NODE_PATH=$NPMDIR/node_modules node -e "require(\'chalk\')" && echo "npm_install_ok" && ' + + 'rm -rf $NPMDIR', { allowDomains: ['registry.npmjs.org'], logLevel: 'debug', @@ -387,11 +391,12 @@ describe('Chroot Package Manager Support', () => { test('should build a Rust project with a dependency via cargo', async () => { const result = await runner.runWithSudo( 'TESTDIR=$(mktemp -d) && cd $TESTDIR && ' + + 'CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse ' + 'cargo init --name awftest 2>&1 && ' + - // Add a small dependency (cfg-if is tiny with no transitive deps) 'echo \'cfg-if = "1"\' >> Cargo.toml && ' + - 'cargo build 2>&1 && echo "cargo_build_ok" && ' + - 'rm -rf $TESTDIR', + 'CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse ' + + 'cargo build 2>&1 && echo "cargo_build_ok"; ' + + 'EC=$?; rm -rf $TESTDIR; exit $EC', { allowDomains: ['crates.io', 'static.crates.io', 'index.crates.io'], logLevel: 'debug',