Compare commits

...

11 Commits

Author SHA1 Message Date
Bassem Dghaidi
2e9cddfa69 Use wernight/squid (permissive proxy) and fix verification tests
- Switch from ubuntu/squid to wernight/squid which allows all HTTPS CONNECT
- Fix verification tests to explicitly use -x flag to prove proxy works
- Tests now verify:
  1. Proxy accepts and forwards requests (using curl -x)
  2. Direct blob storage access is blocked by iptables
  3. Blob storage access through proxy succeeds

The cache action should now fail because it doesn't use the proxy,
not because the proxy rejects the connection.
2026-01-29 09:41:44 -08:00
Bassem Dghaidi
34472f2415 Add explicit iptables rules to block blob storage IPs
The previous firewall setup relied on a catch-all REJECT rule for blob
storage, but it wasn't blocking traffic. Now we explicitly resolve and
block the IPs for productionresultssa0-3.blob.core.windows.net using
iptables -I OUTPUT 1 to insert rules at the top of the chain.
2026-01-29 09:31:15 -08:00
Bassem Dghaidi
e0d51ac399 Switch to sameersbn/squid image and simplify verification
- Replace ubuntu/squid with sameersbn/squid:latest (more reliable)
- Remove shared volume mounts that may cause permission issues
- Simplify verification steps since we can't access service container logs
- The test validates proxy works by verifying cache operations succeed
  when direct access is blocked by iptables
2026-01-29 09:27:29 -08:00
Bassem Dghaidi
26cd8c103b Add wait loop for squid-proxy service to be resolvable 2026-01-29 09:22:42 -08:00
Bassem Dghaidi
0d4af5e74f Remove proxy env from Fetch GitHub meta step - must run before firewall setup 2026-01-29 09:20:18 -08:00
Bassem Dghaidi
61ba4b9b0a Merge branch 'Link-/fix-proxy-integration-tests' of github.com:actions/cache into Link-/fix-proxy-integration-tests 2026-01-29 09:18:24 -08:00
Bassem Dghaidi
2f8c9d682d Use shared volume between job container and squid service for log access 2026-01-29 09:17:52 -08:00
Bassem Dghaidi
56cc052f4d Use shared volume between job container and squid service for log access 2026-01-29 09:13:07 -08:00
Bassem Dghaidi
ef4c2110b5 Actually verify that the traffic and calls went through the proxy 2026-01-29 08:33:17 -08:00
Bassem Dghaidi
c5ddd32390 Fix what gets blocked and what passes through 2026-01-29 08:23:41 -08:00
Bassem Dghaidi
6bfa66432f Fix proxy integration tests 2026-01-29 07:56:38 -08:00

View File

@@ -90,45 +90,359 @@ jobs:
runs-on: ubuntu-latest
container:
image: ubuntu:latest
options: --dns 127.0.0.1
options: --privileged
services:
squid-proxy:
image: ubuntu/squid:latest
image: wernight/squid
ports:
- 3128:3128
env:
https_proxy: http://squid-proxy:3128
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Install dependencies
run: |
apt-get update
apt-get install -y iptables dnsutils curl jq ipset
- name: Fetch GitHub meta and configure firewall
run: |
# Fetch GitHub meta API to get all IP ranges
echo "Fetching GitHub meta API..."
curl -sS https://api.github.com/meta > /tmp/github-meta.json
# Wait for squid-proxy service to be resolvable and accepting connections
echo "Waiting for squid-proxy service..."
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
PROXY_IP=$(getent hosts squid-proxy | awk '{ print $1 }')
if [ -n "$PROXY_IP" ]; then
echo "squid-proxy resolved to: $PROXY_IP"
# Test that proxy is actually accepting connections
if curl --connect-timeout 2 --max-time 5 -x http://squid-proxy:3128 -sS https://api.github.com/zen 2>/dev/null; then
echo "Proxy is working!"
break
else
echo "Attempt $i: Proxy resolved but not ready yet, waiting..."
fi
else
echo "Attempt $i: squid-proxy not resolvable yet, waiting..."
fi
sleep 2
done
if [ -z "$PROXY_IP" ]; then
echo "ERROR: Could not resolve squid-proxy after 15 attempts"
exit 1
fi
# Verify proxy works before locking down firewall
echo "Final proxy connectivity test..."
if ! curl --connect-timeout 5 --max-time 10 -x http://squid-proxy:3128 -sS https://api.github.com/zen; then
echo "ERROR: Proxy is not working properly"
exit 1
fi
echo "Proxy verified working!"
# Allow established connections
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow loopback
iptables -A OUTPUT -o lo -j ACCEPT
# Allow connections to the proxy
iptables -A OUTPUT -d $PROXY_IP -p tcp --dport 3128 -j ACCEPT
# Allow DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
# Create ipset for GitHub IPs (more efficient than individual rules)
ipset create github-ips hash:net
# Add all GitHub IP ranges from meta API (hooks, web, api, git, actions, etc.)
# EXCLUDING blob storage which must go through proxy
for category in hooks web api git pages importer actions actions_macos codespaces copilot; do
echo "Adding IPs for category: $category"
jq -r ".${category}[]? // empty" /tmp/github-meta.json 2>/dev/null | while read cidr; do
# Skip IPv6 for now (iptables vs ip6tables) - use case for POSIX compatibility
case "$cidr" in
*:*) ;; # IPv6, skip
*) ipset add github-ips "$cidr" 2>/dev/null || true ;;
esac
done
done
# Allow all GitHub IPs
iptables -A OUTPUT -m set --match-set github-ips dst -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -m set --match-set github-ips dst -p tcp --dport 80 -j ACCEPT
# CRITICAL: Block direct access to blob storage and results-receiver
# These MUST go through the proxy for cache operations
echo "Blocking direct access to cache-critical endpoints..."
# Block results-receiver.actions.githubusercontent.com
for ip in $(getent ahosts "results-receiver.actions.githubusercontent.com" 2>/dev/null | awk '{print $1}' | sort -u); do
echo "Blocking direct access to results-receiver: $ip"
iptables -I OUTPUT 1 -d "$ip" -p tcp --dport 443 -j REJECT
done
# Block blob.core.windows.net (Azure blob storage used for cache)
for host in productionresultssa0.blob.core.windows.net productionresultssa1.blob.core.windows.net productionresultssa2.blob.core.windows.net productionresultssa3.blob.core.windows.net; do
for ip in $(getent ahosts "$host" 2>/dev/null | awk '{print $1}' | sort -u); do
echo "Blocking direct access to blob storage ($host): $ip"
iptables -I OUTPUT 1 -d "$ip" -p tcp --dport 443 -j REJECT
done
done
# Block all other outbound HTTP/HTTPS traffic
iptables -A OUTPUT -p tcp --dport 80 -j REJECT
iptables -A OUTPUT -p tcp --dport 443 -j REJECT
echo "iptables rules applied:"
iptables -L OUTPUT -n -v
echo ""
echo "ipset github-ips contains $(ipset list github-ips | grep -c '^[0-9]') entries"
- name: Verify proxy enforcement
run: |
echo "=== Testing proxy enforcement ==="
# Test 1: Verify proxy is working by explicitly using it
echo "Test 1: Connection through proxy (should SUCCEED)"
if curl --connect-timeout 10 --max-time 15 -x http://squid-proxy:3128 -sS -o /dev/null -w "%{http_code}" https://api.github.com/zen; then
echo ""
echo "✓ Proxy connection works"
else
echo "✗ ERROR: Proxy is not working!"
exit 1
fi
# Test 2: Direct connection to blob storage should FAIL (blocked by iptables)
echo ""
echo "Test 2: Direct connection to blob storage (should FAIL - blocked by iptables)"
if curl --connect-timeout 5 --max-time 10 --noproxy '*' -sS https://productionresultssa0.blob.core.windows.net 2>/dev/null; then
echo "✗ ERROR: Direct blob storage connection succeeded but should have been blocked!"
exit 1
else
echo "✓ Direct blob storage correctly blocked by iptables"
fi
# Test 3: Connection to blob storage THROUGH proxy should work
echo ""
echo "Test 3: Connection through proxy to blob storage (should SUCCEED)"
HTTP_CODE=$(curl --connect-timeout 10 --max-time 15 -x http://squid-proxy:3128 -sS -o /dev/null -w "%{http_code}" https://productionresultssa0.blob.core.windows.net 2>&1) || true
echo "HTTP response code: $HTTP_CODE"
if [ "$HTTP_CODE" = "400" ] || [ "$HTTP_CODE" = "409" ] || [ "$HTTP_CODE" = "200" ]; then
echo "✓ Proxy successfully forwarded request to blob storage (got HTTP $HTTP_CODE)"
else
echo "✗ ERROR: Proxy failed to forward request (got: $HTTP_CODE)"
exit 1
fi
echo ""
echo "=== All proxy enforcement tests passed ==="
echo "The proxy is working. If cache operations fail, it's because the action doesn't use the proxy."
- name: Generate files
run: __tests__/create-cache-files.sh proxy test-cache
- name: Save cache
env:
http_proxy: http://squid-proxy:3128
https_proxy: http://squid-proxy:3128
uses: ./
with:
key: test-proxy-${{ github.run_id }}
path: test-cache
- name: Verify proxy setup
run: |
echo "## 🔒 Proxy Integration Test - Cache Save" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ✅ Test Configuration" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Proxy**: squid-proxy:3128" >> $GITHUB_STEP_SUMMARY
echo "- **Firewall**: iptables blocking direct access to cache endpoints" >> $GITHUB_STEP_SUMMARY
echo "- **Test**: Cache save operation completed successfully through proxy" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "If the cache save step succeeded, it means:" >> $GITHUB_STEP_SUMMARY
echo "1. Direct access to results-receiver.actions.githubusercontent.com was blocked" >> $GITHUB_STEP_SUMMARY
echo "2. Direct access to *.blob.core.windows.net was blocked" >> $GITHUB_STEP_SUMMARY
echo "3. Cache operations were routed through the squid proxy" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ **SUCCESS**: Proxy integration test passed!" >> $GITHUB_STEP_SUMMARY
test-proxy-restore:
needs: test-proxy-save
runs-on: ubuntu-latest
container:
image: ubuntu:latest
options: --dns 127.0.0.1
options: --privileged
services:
squid-proxy:
image: ubuntu/squid:latest
image: wernight/squid
ports:
- 3128:3128
env:
https_proxy: http://squid-proxy:3128
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Install dependencies
run: |
apt-get update
apt-get install -y iptables dnsutils curl jq ipset
- name: Fetch GitHub meta and configure firewall
run: |
# Fetch GitHub meta API to get all IP ranges
echo "Fetching GitHub meta API..."
curl -sS https://api.github.com/meta > /tmp/github-meta.json
# Wait for squid-proxy service to be resolvable and accepting connections
echo "Waiting for squid-proxy service..."
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
PROXY_IP=$(getent hosts squid-proxy | awk '{ print $1 }')
if [ -n "$PROXY_IP" ]; then
echo "squid-proxy resolved to: $PROXY_IP"
# Test that proxy is actually accepting connections
if curl --connect-timeout 2 --max-time 5 -x http://squid-proxy:3128 -sS https://api.github.com/zen 2>/dev/null; then
echo "Proxy is working!"
break
else
echo "Attempt $i: Proxy resolved but not ready yet, waiting..."
fi
else
echo "Attempt $i: squid-proxy not resolvable yet, waiting..."
fi
sleep 2
done
if [ -z "$PROXY_IP" ]; then
echo "ERROR: Could not resolve squid-proxy after 15 attempts"
exit 1
fi
# Verify proxy works before locking down firewall
echo "Final proxy connectivity test..."
if ! curl --connect-timeout 5 --max-time 10 -x http://squid-proxy:3128 -sS https://api.github.com/zen; then
echo "ERROR: Proxy is not working properly"
exit 1
fi
echo "Proxy verified working!"
# Allow established connections
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow loopback
iptables -A OUTPUT -o lo -j ACCEPT
# Allow connections to the proxy
iptables -A OUTPUT -d $PROXY_IP -p tcp --dport 3128 -j ACCEPT
# Allow DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
# Create ipset for GitHub IPs (more efficient than individual rules)
ipset create github-ips hash:net
# Add all GitHub IP ranges from meta API (hooks, web, api, git, actions, etc.)
# EXCLUDING blob storage which must go through proxy
for category in hooks web api git pages importer actions actions_macos codespaces copilot; do
echo "Adding IPs for category: $category"
jq -r ".${category}[]? // empty" /tmp/github-meta.json 2>/dev/null | while read cidr; do
# Skip IPv6 for now (iptables vs ip6tables) - use case for POSIX compatibility
case "$cidr" in
*:*) ;; # IPv6, skip
*) ipset add github-ips "$cidr" 2>/dev/null || true ;;
esac
done
done
# Allow all GitHub IPs
iptables -A OUTPUT -m set --match-set github-ips dst -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -m set --match-set github-ips dst -p tcp --dport 80 -j ACCEPT
# CRITICAL: Block direct access to blob storage and results-receiver
# These MUST go through the proxy for cache operations
echo "Blocking direct access to cache-critical endpoints..."
# Block results-receiver.actions.githubusercontent.com
for ip in $(getent ahosts "results-receiver.actions.githubusercontent.com" 2>/dev/null | awk '{print $1}' | sort -u); do
echo "Blocking direct access to results-receiver: $ip"
iptables -I OUTPUT 1 -d "$ip" -p tcp --dport 443 -j REJECT
done
# Block blob.core.windows.net (Azure blob storage used for cache)
for host in productionresultssa0.blob.core.windows.net productionresultssa1.blob.core.windows.net productionresultssa2.blob.core.windows.net productionresultssa3.blob.core.windows.net; do
for ip in $(getent ahosts "$host" 2>/dev/null | awk '{print $1}' | sort -u); do
echo "Blocking direct access to blob storage ($host): $ip"
iptables -I OUTPUT 1 -d "$ip" -p tcp --dport 443 -j REJECT
done
done
# Block all other outbound HTTP/HTTPS traffic
iptables -A OUTPUT -p tcp --dport 80 -j REJECT
iptables -A OUTPUT -p tcp --dport 443 -j REJECT
echo "iptables rules applied:"
iptables -L OUTPUT -n -v
echo ""
echo "ipset github-ips contains $(ipset list github-ips | grep -c '^[0-9]') entries"
- name: Verify proxy enforcement
run: |
echo "=== Testing proxy enforcement ==="
# Test 1: Verify proxy is working by explicitly using it
echo "Test 1: Connection through proxy (should SUCCEED)"
if curl --connect-timeout 10 --max-time 15 -x http://squid-proxy:3128 -sS -o /dev/null -w "%{http_code}" https://api.github.com/zen; then
echo ""
echo "✓ Proxy connection works"
else
echo "✗ ERROR: Proxy is not working!"
exit 1
fi
# Test 2: Direct connection to blob storage should FAIL (blocked by iptables)
echo ""
echo "Test 2: Direct connection to blob storage (should FAIL - blocked by iptables)"
if curl --connect-timeout 5 --max-time 10 --noproxy '*' -sS https://productionresultssa0.blob.core.windows.net 2>/dev/null; then
echo "✗ ERROR: Direct blob storage connection succeeded but should have been blocked!"
exit 1
else
echo "✓ Direct blob storage correctly blocked by iptables"
fi
# Test 3: Connection to blob storage THROUGH proxy should work
echo ""
echo "Test 3: Connection through proxy to blob storage (should SUCCEED)"
HTTP_CODE=$(curl --connect-timeout 10 --max-time 15 -x http://squid-proxy:3128 -sS -o /dev/null -w "%{http_code}" https://productionresultssa0.blob.core.windows.net 2>&1) || true
echo "HTTP response code: $HTTP_CODE"
if [ "$HTTP_CODE" = "400" ] || [ "$HTTP_CODE" = "409" ] || [ "$HTTP_CODE" = "200" ]; then
echo "✓ Proxy successfully forwarded request to blob storage (got HTTP $HTTP_CODE)"
else
echo "✗ ERROR: Proxy failed to forward request (got: $HTTP_CODE)"
exit 1
fi
echo ""
echo "=== All proxy enforcement tests passed ==="
echo "The proxy is working. If cache operations fail, it's because the action doesn't use the proxy."
- name: Restore cache
env:
http_proxy: http://squid-proxy:3128
https_proxy: http://squid-proxy:3128
uses: ./
with:
key: test-proxy-${{ github.run_id }}
path: test-cache
- name: Verify proxy setup
run: |
echo "## 🔒 Proxy Integration Test - Cache Restore" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ✅ Test Configuration" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Proxy**: squid-proxy:3128" >> $GITHUB_STEP_SUMMARY
echo "- **Firewall**: iptables blocking direct access to cache endpoints" >> $GITHUB_STEP_SUMMARY
echo "- **Test**: Cache restore operation completed successfully through proxy" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "If the cache restore step succeeded, it means:" >> $GITHUB_STEP_SUMMARY
echo "1. Direct access to results-receiver.actions.githubusercontent.com was blocked" >> $GITHUB_STEP_SUMMARY
echo "2. Direct access to *.blob.core.windows.net was blocked" >> $GITHUB_STEP_SUMMARY
echo "3. Cache operations were routed through the squid proxy" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ **SUCCESS**: Proxy integration test passed!" >> $GITHUB_STEP_SUMMARY
- name: Verify cache
run: __tests__/verify-cache-files.sh proxy test-cache