Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,9 @@ jobs:

echo "Build verification successful"
ls -la dist/

- name: Run API proxy unit tests
run: |
cd containers/api-proxy
npm ci
npm test
240 changes: 240 additions & 0 deletions .github/workflows/test-integration-suite.yml
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ reports/

# CodeQL auto-generated symlink
_codeql_detected_source_root

# Design docs (working drafts, not checked in)
design-docs/
50 changes: 50 additions & 0 deletions containers/api-proxy/logging.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Structured JSON logging for AWF API Proxy.
*
* Every log line is a single JSON object written to stdout.
* Zero external dependencies — uses Node.js built-in crypto.
*/

'use strict';

const crypto = require('crypto');

/**
* Generate a unique request ID (UUID v4).
* @returns {string}
*/
function generateRequestId() {
return crypto.randomUUID();
}

/**
* Strip control characters and limit length for safe logging.
* @param {string} str
* @param {number} [maxLen=200]
* @returns {string}
*/
function sanitizeForLog(str, maxLen = 200) {
if (typeof str !== 'string') return '';
// eslint-disable-next-line no-control-regex
return str.replace(/[\x00-\x1f\x7f]/g, '').slice(0, maxLen);
}

/**
* Write a structured JSON log line to stdout.
*
* @param {string} level - "info" | "warn" | "error"
* @param {string} event - e.g. "request_start", "request_complete", "request_error", "startup"
* @param {object} [fields] - Additional key/value pairs merged into the log line
*/
function logRequest(level, event, fields = {}) {
const line = {
timestamp: new Date().toISOString(),
level,
event,
...fields,
};
// Single JSON line to stdout — tee handles file persistence
process.stdout.write(JSON.stringify(line) + '\n');
}

module.exports = { generateRequestId, sanitizeForLog, logRequest };
Loading
Loading