diff --git a/.github/workflows/test-integration-suite.yml b/.github/workflows/test-integration-suite.yml new file mode 100644 index 00000000..d345f797 --- /dev/null +++ b/.github/workflows/test-integration-suite.yml @@ -0,0 +1,240 @@ +name: Integration Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + test-domain-network: + name: Domain & Network Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 + + - name: Setup Node.js + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build project + run: npm run build + + - name: Build local containers + run: | + echo "=== Building local containers ===" + docker build -t ghcr.io/github/gh-aw-firewall/squid:latest containers/squid/ + docker build -t ghcr.io/github/gh-aw-firewall/agent:latest containers/agent/ + + - name: Pre-test cleanup + run: | + echo "=== Pre-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Run domain & network tests + run: | + echo "=== Running domain & network tests ===" + npm run test:integration -- \ + --testPathPatterns="(blocked-domains|dns-servers|empty-domains|wildcard-patterns|ipv6|localhost-access|network-security)" \ + --verbose + env: + JEST_TIMEOUT: 180000 + + - name: Post-test cleanup + if: always() + run: | + echo "=== Post-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Collect logs on failure + if: failure() + run: | + echo "=== Collecting failure logs ===" + docker ps -a || true + docker logs awf-squid 2>&1 || true + docker logs awf-agent 2>&1 || true + ls -la /tmp/awf-* 2>/dev/null || true + sudo cat /tmp/awf-*/squid-logs/access.log 2>/dev/null || true + + test-protocol-security: + name: Protocol & Security Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 + + - name: Setup Node.js + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build project + run: npm run build + + - name: Build local containers + run: | + echo "=== Building local containers ===" + docker build -t ghcr.io/github/gh-aw-firewall/squid:latest containers/squid/ + docker build -t ghcr.io/github/gh-aw-firewall/agent:latest containers/agent/ + + - name: Pre-test cleanup + run: | + echo "=== Pre-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Run protocol & security tests + run: | + echo "=== Running protocol & security tests ===" + npm run test:integration -- \ + --testPathPatterns="(protocol-support|credential-hiding|one-shot-tokens|token-unset|git-operations)" \ + --verbose + env: + JEST_TIMEOUT: 180000 + + - name: Post-test cleanup + if: always() + run: | + echo "=== Post-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Collect logs on failure + if: failure() + run: | + echo "=== Collecting failure logs ===" + docker ps -a || true + docker logs awf-squid 2>&1 || true + docker logs awf-agent 2>&1 || true + ls -la /tmp/awf-* 2>/dev/null || true + sudo cat /tmp/awf-*/squid-logs/access.log 2>/dev/null || true + + test-container-ops: + name: Container & Ops Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 + + - name: Setup Node.js + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build project + run: npm run build + + - name: Build local containers + run: | + echo "=== Building local containers ===" + docker build -t ghcr.io/github/gh-aw-firewall/squid:latest containers/squid/ + docker build -t ghcr.io/github/gh-aw-firewall/agent:latest containers/agent/ + + - name: Pre-test cleanup + run: | + echo "=== Pre-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Run container & ops tests + run: | + echo "=== Running container & ops tests ===" + npm run test:integration -- \ + --testPathPatterns="(container-workdir|docker-warning|environment-variables|error-handling|exit-code-propagation|log-commands|no-docker|volume-mounts)" \ + --verbose + env: + JEST_TIMEOUT: 180000 + + - name: Post-test cleanup + if: always() + run: | + echo "=== Post-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Collect logs on failure + if: failure() + run: | + echo "=== Collecting failure logs ===" + docker ps -a || true + docker logs awf-squid 2>&1 || true + docker logs awf-agent 2>&1 || true + ls -la /tmp/awf-* 2>/dev/null || true + sudo cat /tmp/awf-*/squid-logs/access.log 2>/dev/null || true + + test-api-proxy: + name: API Proxy Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 + + - name: Setup Node.js + uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build project + run: npm run build + + - name: Build local containers + run: | + echo "=== Building local containers ===" + docker build -t ghcr.io/github/gh-aw-firewall/squid:latest containers/squid/ + docker build -t ghcr.io/github/gh-aw-firewall/agent:latest containers/agent/ + + - name: Pre-test cleanup + run: | + echo "=== Pre-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Run API proxy tests + run: | + echo "=== Running API proxy tests ===" + npm run test:integration -- \ + --testPathPatterns="api-proxy" \ + --verbose + env: + JEST_TIMEOUT: 180000 + + - name: Post-test cleanup + if: always() + run: | + echo "=== Post-test cleanup ===" + ./scripts/ci/cleanup.sh || true + + - name: Collect logs on failure + if: failure() + run: | + echo "=== Collecting failure logs ===" + docker ps -a || true + docker logs awf-squid 2>&1 || true + docker logs awf-agent 2>&1 || true + ls -la /tmp/awf-* 2>/dev/null || true + sudo cat /tmp/awf-*/squid-logs/access.log 2>/dev/null || true diff --git a/tests/fixtures/awf-runner.ts b/tests/fixtures/awf-runner.ts index e137536d..aee732a0 100644 --- a/tests/fixtures/awf-runner.ts +++ b/tests/fixtures/awf-runner.ts @@ -19,12 +19,12 @@ export interface AwfOptions { dnsServers?: string[]; // DNS servers to use (e.g., ['8.8.8.8', '2001:4860:4860::8888']) allowHostPorts?: string; // Ports or port ranges to allow for host access (e.g., '3000' or '3000-8000') enableApiProxy?: boolean; // Enable API proxy sidecar for LLM credential management - envAll?: boolean; // Pass all host environment variables to container (--env-all) - cliEnv?: Record; // Explicit -e KEY=VALUE flags passed to AWF CLI rateLimitRpm?: number; // Requests per minute per provider rateLimitRph?: number; // Requests per hour per provider rateLimitBytesPm?: number; // Request bytes per minute per provider noRateLimit?: boolean; // Disable rate limiting + envAll?: boolean; // Pass all host environment variables to container (--env-all) + cliEnv?: Record; // Explicit -e KEY=VALUE flags passed to AWF CLI } export interface AwfResult { @@ -116,6 +116,20 @@ export class AwfRunner { args.push('--enable-api-proxy'); } + // Add rate limit flags + if (options.rateLimitRpm !== undefined) { + args.push('--rate-limit-rpm', String(options.rateLimitRpm)); + } + if (options.rateLimitRph !== undefined) { + args.push('--rate-limit-rph', String(options.rateLimitRph)); + } + if (options.rateLimitBytesPm !== undefined) { + args.push('--rate-limit-bytes-pm', String(options.rateLimitBytesPm)); + } + if (options.noRateLimit) { + args.push('--no-rate-limit'); + } + // Add --env-all flag if (options.envAll) { args.push('--env-all'); @@ -296,6 +310,20 @@ export class AwfRunner { args.push('--enable-api-proxy'); } + // Add rate limit flags + if (options.rateLimitRpm !== undefined) { + args.push('--rate-limit-rpm', String(options.rateLimitRpm)); + } + if (options.rateLimitRph !== undefined) { + args.push('--rate-limit-rph', String(options.rateLimitRph)); + } + if (options.rateLimitBytesPm !== undefined) { + args.push('--rate-limit-bytes-pm', String(options.rateLimitBytesPm)); + } + if (options.noRateLimit) { + args.push('--no-rate-limit'); + } + // Add --env-all flag if (options.envAll) { args.push('--env-all');