diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml new file mode 100644 index 00000000..92cf310a --- /dev/null +++ b/.github/workflows/test-examples.yml @@ -0,0 +1,86 @@ +name: Examples Test + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + test-examples: + name: Test Examples + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout repository + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + + - name: Setup Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build project + run: npm run build + + - name: Install awf globally + run: sudo npm link + + - name: Pre-test cleanup + run: sudo ./scripts/ci/cleanup.sh + + - name: Make examples executable + run: chmod +x examples/*.sh + + - name: Test basic-curl.sh + run: | + echo "=== Testing basic-curl.sh ===" + sudo ./examples/basic-curl.sh + + - name: Test using-domains-file.sh + run: | + echo "=== Testing using-domains-file.sh ===" + sudo ./examples/using-domains-file.sh + + - name: Test debugging.sh + run: | + echo "=== Testing debugging.sh ===" + sudo ./examples/debugging.sh + + - name: Test blocked-domains.sh + run: | + echo "=== Testing blocked-domains.sh ===" + sudo ./examples/blocked-domains.sh + + - name: Test docker-in-docker.sh + run: | + echo "=== Testing docker-in-docker.sh ===" + sudo ./examples/docker-in-docker.sh + + # Note: github-copilot.sh is skipped as it requires GITHUB_TOKEN for Copilot CLI + # To test it, you would need to set up a secret with a valid Copilot token + + - name: Post-test cleanup + if: always() + run: sudo ./scripts/ci/cleanup.sh + + - name: Upload logs on failure + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: examples-test-logs + path: | + /tmp/*-test.log + /tmp/awf-*/ + /tmp/awf-agent-logs-*/ + /tmp/squid-logs-*/ + retention-days: 7 diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..a522c2a7 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,42 @@ +# AWF Examples + +This directory contains example scripts demonstrating common ways to use the Agentic Workflow Firewall (`awf`). + +## Prerequisites + +- Docker running on your machine +- `awf` installed (see [installation instructions](../README.md#get-started-fast)) +- `sudo` access (required for iptables manipulation) + +## Examples + +| File | Description | +|------|-------------| +| [basic-curl.sh](basic-curl.sh) | Simple HTTP request through the firewall | +| [github-copilot.sh](github-copilot.sh) | Using GitHub Copilot CLI with the firewall | +| [docker-in-docker.sh](docker-in-docker.sh) | Running Docker containers inside the firewall | +| [using-domains-file.sh](using-domains-file.sh) | Using a file to specify allowed domains | +| [blocked-domains.sh](blocked-domains.sh) | Blocking specific domains with allowlist/blocklist | +| [debugging.sh](debugging.sh) | Debug mode with log inspection | +| [domains.txt](domains.txt) | Example domain allowlist file | + +## Running Examples + +Each example is a standalone shell script. Run with: + +```bash +# Make executable (if needed) +chmod +x examples/*.sh + +# Run an example +./examples/basic-curl.sh +``` + +> **Note:** Most examples require `sudo` for iptables manipulation. The scripts will prompt for sudo access if needed. + +## Domain Matching + +AWF automatically matches subdomains. For example: +- `github.com` matches `github.com`, `api.github.com`, `raw.githubusercontent.com`, etc. + +See [domains.txt](domains.txt) for domain file format examples. diff --git a/examples/basic-curl.sh b/examples/basic-curl.sh new file mode 100644 index 00000000..0fbcd460 --- /dev/null +++ b/examples/basic-curl.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Example: Basic curl request through the firewall +# +# This example demonstrates the simplest use case: making an HTTP request +# through the firewall with a specific domain allowlist. +# +# Usage: sudo ./examples/basic-curl.sh + +set -e + +echo "=== AWF Basic Curl Example ===" +echo "" +echo "Making a request to api.github.com (allowed)" +echo "" + +# Simple curl request to GitHub API +# The --allow-domains flag specifies which domains are accessible +# Subdomains are automatically included (github.com includes api.github.com) +sudo awf \ + --allow-domains github.com \ + -- curl -s https://api.github.com | head -20 + +echo "" +echo "=== Example Complete ===" diff --git a/examples/blocked-domains.sh b/examples/blocked-domains.sh new file mode 100644 index 00000000..250d335b --- /dev/null +++ b/examples/blocked-domains.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Example: Domain blocking with allowlist and blocklist +# +# This example demonstrates how to use both allow and block lists. +# Blocked domains take precedence over allowed domains, enabling +# fine-grained control over network access. +# +# Usage: sudo ./examples/blocked-domains.sh + +set -e + +echo "=== AWF Domain Blocking Example ===" +echo "" + +echo "1. Allow github.com but block a specific subdomain..." +echo "" +echo " Allowing: github.com (includes all subdomains)" +echo " Blocking: gist.github.com" +echo "" + +# Block gist.github.com specifically while allowing other github.com subdomains +# api.github.com should work, gist.github.com should be blocked +echo "Attempting to access api.github.com (should succeed):" +sudo awf \ + --allow-domains github.com \ + --block-domains gist.github.com \ + -- curl -s -o /dev/null -w "%{http_code}" https://api.github.com && echo " - OK" + +echo "" +echo "Attempting to access gist.github.com (should be blocked):" +sudo awf \ + --allow-domains github.com \ + --block-domains gist.github.com \ + -- curl -f --max-time 10 https://gist.github.com 2>&1 || echo " - Blocked (expected)" + +echo "" +echo "2. Using wildcard patterns in blocklist..." +echo "" + +# Block all subdomains matching a pattern +# Note: awf supports wildcards (*) in domain patterns +# Patterns are converted to regex internally (e.g., * becomes .*) +echo "Blocking all internal-* subdomains while allowing example.com:" +sudo awf \ + --allow-domains example.com \ + --block-domains 'internal-*.example.com' \ + -- 'echo "Firewall configured with wildcard blocklist"' + +echo "" +echo "=== Example Complete ===" diff --git a/examples/debugging.sh b/examples/debugging.sh new file mode 100644 index 00000000..d05eb81a --- /dev/null +++ b/examples/debugging.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Example: Debug mode with log inspection +# +# This example shows how to use debug logging and keep containers +# running after command execution for inspection. +# +# Usage: sudo ./examples/debugging.sh + +set -e + +echo "=== AWF Debugging Example ===" +echo "" + +echo "Running with debug logging enabled..." +echo "Use --log-level debug to see detailed output" +echo "Use --keep-containers to preserve containers after execution" +echo "" + +# Run with debug logging +# --log-level debug: Shows configuration details, iptables rules, etc. +# --keep-containers: Keeps containers running for inspection after command exits +sudo awf \ + --allow-domains github.com \ + --log-level debug \ + -- curl -s https://api.github.com/zen + +echo "" +echo "=== Inspecting Logs ===" +echo "" + +# After a run, logs are automatically preserved +# Note: These paths are based on awf's default behavior and may change in future versions +echo "Agent logs are saved to: /tmp/awf-agent-logs-" +echo "Squid logs are saved to: /tmp/squid-logs-" +echo "" + +# List preserved log directories +echo "Available log directories:" +ls -d /tmp/awf-agent-logs-* /tmp/squid-logs-* 2>/dev/null || echo " (no logs found - run a command first)" + +echo "" +echo "To view live logs from a running container (with --keep-containers):" +echo " docker logs awf-squid # View proxy logs" +echo " docker logs awf-agent # View agent logs" +echo "" +echo "To view preserved Squid access logs:" +echo " sudo cat /tmp/squid-logs-*/access.log" +echo "" +echo "To find blocked requests:" +echo " sudo grep 'TCP_DENIED' /tmp/squid-logs-*/access.log" +echo "" +echo "=== Example Complete ===" diff --git a/examples/docker-in-docker.sh b/examples/docker-in-docker.sh new file mode 100644 index 00000000..03ec2a10 --- /dev/null +++ b/examples/docker-in-docker.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Example: Running Docker containers inside the firewall (Docker-in-Docker) +# +# This example demonstrates how spawned Docker containers inherit +# the firewall restrictions. All network traffic from nested containers +# is also filtered through the domain allowlist. +# +# Usage: sudo ./examples/docker-in-docker.sh + +set -e + +echo "=== AWF Docker-in-Docker Example ===" +echo "" + +# Docker-in-Docker requires access to Docker Hub for pulling images +DOCKER_DOMAINS="registry-1.docker.io,auth.docker.io,production.cloudflare.docker.com" + +echo "1. Running curl container with api.github.com allowed..." +echo "" + +# This should succeed - api.github.com is in the allowlist +sudo awf \ + --allow-domains "api.github.com,$DOCKER_DOMAINS" \ + -- 'docker run --rm curlimages/curl -s https://api.github.com/zen' + +echo "" +echo "2. Attempting to access example.com (should be blocked)..." +echo "" + +# This should fail - example.com is NOT in the allowlist +# Capture exit code to show what a blocked request looks like +sudo awf \ + --allow-domains "$DOCKER_DOMAINS" \ + -- 'docker run --rm curlimages/curl -f --max-time 10 https://example.com' || echo "Exit code: $? (blocked as expected)" + +echo "" +echo "(The above error is expected - example.com was blocked by the firewall)" +echo "" +echo "=== Example Complete ===" diff --git a/examples/github-copilot.sh b/examples/github-copilot.sh new file mode 100644 index 00000000..8a28cc72 --- /dev/null +++ b/examples/github-copilot.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Example: Using GitHub Copilot CLI with the firewall +# +# This example shows how to run GitHub Copilot CLI through the firewall. +# Copilot requires access to several GitHub domains. +# +# Prerequisites: +# - GitHub Copilot CLI installed: npm install -g @github/copilot +# - GITHUB_TOKEN environment variable set +# +# Usage: sudo -E ./examples/github-copilot.sh + +set -e + +echo "=== AWF GitHub Copilot CLI Example ===" +echo "" + +# Check for GITHUB_TOKEN +if [ -z "$GITHUB_TOKEN" ]; then + echo "Error: GITHUB_TOKEN environment variable is not set" + echo "Set it with: export GITHUB_TOKEN='your_token'" + exit 1 +fi + +echo "Running GitHub Copilot CLI through the firewall..." +echo "" + +# Run Copilot CLI with required domains +# Use sudo -E to preserve environment variables (especially GITHUB_TOKEN) +# Required domains: +# - github.com: GitHub API access +# - api.github.com: GitHub REST API +# - api.enterprise.githubcopilot.com: Copilot API endpoint +# - registry.npmjs.org: NPM package registry (for npx) +sudo -E awf \ + --allow-domains github.com,api.github.com,api.enterprise.githubcopilot.com,registry.npmjs.org \ + -- 'npx @github/copilot --prompt "What is 2+2?" --no-mcp' + +echo "" +echo "=== Example Complete ===" diff --git a/examples/using-domains-file.sh b/examples/using-domains-file.sh new file mode 100644 index 00000000..c9008cef --- /dev/null +++ b/examples/using-domains-file.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Example: Using a domains file for allowed domains +# +# Instead of specifying domains on the command line, you can use a file +# containing the list of allowed domains. This is useful for: +# - Managing large domain lists +# - Sharing domain configurations across teams +# - Version controlling domain allowlists +# +# Usage: sudo ./examples/using-domains-file.sh + +set -e + +echo "=== AWF Using Domains File Example ===" +echo "" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DOMAINS_FILE="$SCRIPT_DIR/domains.txt" + +echo "Using domains file: $DOMAINS_FILE" +echo "" +echo "Contents of domains file:" +echo "---" +cat "$DOMAINS_FILE" +echo "---" +echo "" + +# Use --allow-domains-file to specify domains from a file +sudo awf \ + --allow-domains-file "$DOMAINS_FILE" \ + -- curl -s https://api.github.com | head -10 + +echo "" +echo "=== Example Complete ==="