Skip to content

Commit 5d2ef18

Browse files
Mossakaclaude
andauthored
fix(docker): simplify to localhost+Squid-only iptables (#1270)
* fix(security): simplify to localhost+Squid-only iptables Simplify iptables to a minimal security model: - ALLOW: localhost (127.0.0.0/8) for MCP servers + Docker DNS - ALLOW: Squid proxy IP — single egress point for HTTP/HTTPS - REJECT: everything else Remove DNS server exception rules from container and host iptables. Docker embedded DNS (127.0.0.11) handles name resolution via localhost. Squid resolves DNS internally via dns_nameservers. Remove AWF_DNS_SERVERS env var. Keep --dns-servers for Docker embedded DNS upstream forwarding and Squid config. Prevents DNS-based data exfiltration. Fixes #11 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add host-iptables coverage for uncovered paths Adds tests for untested code paths to fix coverage regression: - API proxy sidecar rule generation - Bridge name not found error path - DOCKER-USER chain creation fallback - Skip duplicate DOCKER-USER jump rule insertion - IPv6 cleanup with ip6tables available - IPv6 cleanup skip when ip6tables unavailable Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add hasRateLimitOptions test to fix function coverage regression Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: save and restore Docker DNS DNAT rules across NAT flush Docker's embedded DNS (127.0.0.11) works by redirecting port 53 queries to its internal DNS server on a random high port via iptables DNAT rules. When setup-iptables.sh flushes the NAT OUTPUT chain, these rules are destroyed, causing DNS resolution via 127.0.0.11 to fail silently. Save Docker's DNS DNAT rules before flushing and restore them after, so Docker embedded DNS continues to work. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: restore DNS forwarding rules in DOCKER-USER chain Docker's embedded DNS (127.0.0.11) forwards queries to upstream servers through the container's network interface, which traverses the Docker bridge and DOCKER-USER chain. The previous commit incorrectly assumed Docker DNS bypasses container iptables entirely, but the DNS proxy runs within the container's network namespace. Without DNS ACCEPT rules in DOCKER-USER, forwarded queries are blocked, causing SERVFAIL. Add UDP/TCP port 53 ACCEPT rules for configured upstream DNS servers in the AWF_EGRESS chain, while keeping the simplified model where containers can only use Docker embedded DNS (no direct external DNS). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add unmountSslTmpfs tests to restore function coverage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add UDP DROP rule to prevent DNS exfiltration The OUTPUT filter chain only dropped TCP traffic, leaving UDP unfiltered. This allowed direct DNS queries to external servers (e.g., dig @8.8.8.8) to succeed, defeating the DNS exfiltration prevention. Add iptables -A OUTPUT -p udp -j DROP alongside the existing TCP DROP rule. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(action): use GITHUB_TOKEN for API calls to avoid 403 The curl call to api.github.com/repos/.../releases/latest was unauthenticated, causing intermittent 403 rate limit errors in CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: restore explicit DNS ACCEPT rules for Docker DNS forwarding The blanket `iptables -A OUTPUT -p udp -j DROP` blocked Docker embedded DNS forwarding to upstream servers, causing SERVFAIL for nslookup. Changes: - Restore AWF_DNS_SERVERS env var so setup-iptables.sh knows which upstream DNS servers Docker embedded DNS forwards to - Add explicit iptables ACCEPT rules for configured upstream DNS servers (UDP/TCP port 53) before the DROP rules in the container OUTPUT chain - Fix host-iptables.ts to use ip6tables for IPv6 DNS servers instead of iptables (which rejects IPv6 addresses with exit code 2) - Update DNS exfiltration tests to use non-configured DNS servers (Quad9 9.9.9.9, OpenDNS 208.67.222.222, Cloudflare 1.1.1.1) since the default upstream (8.8.8.8) must be allowed for DNS forwarding Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve rebase conflicts with DoH support from main Merge PR #1270's simplified DNS model with DoH support from main: - DoH mode: route DNS through DoH proxy (from main) - Non-DoH mode: Docker embedded DNS with upstream forwarding only - Fix test calls to include required dnsServers parameter Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: create FW_WRAPPER_V6 chain before adding IPv6 DNS rules When IPv6 DNS servers are configured, the code tried to append rules to the FW_WRAPPER_V6 chain without creating it first, causing "No chain/target/match by that name" error from ip6tables. Create the chain lazily when IPv6 DNS servers are present and ip6tables is available. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3f0f816 commit 5d2ef18

File tree

13 files changed

+370
-550
lines changed

13 files changed

+370
-550
lines changed

action.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,20 @@ runs:
4646
shell: bash
4747
env:
4848
INPUT_VERSION: ${{ inputs.version }}
49+
GITHUB_TOKEN: ${{ github.token }}
4950
run: |
5051
set -euo pipefail
5152
5253
REPO="github/gh-aw-firewall"
5354
BINARY_NAME="awf-linux-x64"
5455
INSTALL_DIR="${RUNNER_TEMP}/awf-bin"
5556
57+
# Build auth header for GitHub API to avoid rate limits
58+
AUTH_HEADER=()
59+
if [ -n "${GITHUB_TOKEN:-}" ]; then
60+
AUTH_HEADER=(-H "Authorization: token ${GITHUB_TOKEN}")
61+
fi
62+
5663
# Create install directory
5764
mkdir -p "$INSTALL_DIR"
5865
@@ -61,9 +68,9 @@ runs:
6168
echo "Fetching latest release version..."
6269
# Use jq if available, fallback to grep/sed
6370
if command -v jq &> /dev/null; then
64-
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | jq -r '.tag_name')
71+
VERSION=$(curl -fsSL "${AUTH_HEADER[@]}" "https://api.github.com/repos/${REPO}/releases/latest" | jq -r '.tag_name')
6572
else
66-
VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
73+
VERSION=$(curl -fsSL "${AUTH_HEADER[@]}" "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
6774
fi
6875
if [ -z "$VERSION" ] || [ "$VERSION" = "null" ]; then
6976
echo "::error::Failed to fetch latest version from GitHub API"

containers/agent/entrypoint.sh

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ if [ "$CURRENT_UID" != "$HOST_UID" ] || [ "$CURRENT_GID" != "$HOST_GID" ]; then
6565
echo "[entrypoint] UID/GID adjustment complete"
6666
fi
6767

68-
# Fix DNS configuration - ensure external DNS works alongside Docker's embedded DNS
69-
# Docker's embedded DNS (127.0.0.11) is used for service name resolution (e.g., squid-proxy)
70-
# Trusted external DNS servers are used for internet domain resolution
68+
# Configure DNS to use only Docker's embedded DNS (127.0.0.11)
69+
# Docker embedded DNS handles all name resolution:
70+
# - Container names (e.g., squid-proxy) → resolved directly
71+
# - External domains → forwarded to upstream DNS servers configured via docker-compose dns: field
72+
# No external DNS servers are listed in resolv.conf to prevent DNS-based data exfiltration
7173
echo "[entrypoint] Configuring DNS..."
7274
if [ -f /etc/resolv.conf ]; then
7375
# Backup original resolv.conf
@@ -85,30 +87,17 @@ if [ -f /etc/resolv.conf ]; then
8587
} > /etc/resolv.conf
8688
echo "[entrypoint] DNS configured with Docker embedded DNS (127.0.0.11) and DoH proxy ($AWF_DOH_PROXY_IP)"
8789
else
88-
# Traditional DNS mode: use configured DNS servers
89-
# Get DNS servers from environment (default to Google DNS)
90-
DNS_SERVERS="${AWF_DNS_SERVERS:-8.8.8.8,8.8.4.4}"
91-
92-
# Create new resolv.conf with Docker embedded DNS first, then trusted external DNS servers
90+
# Simplified security model: Docker embedded DNS only
91+
# Docker embedded DNS at 127.0.0.11 handles all resolution
92+
# It forwards to upstream servers configured via docker-compose dns: field
93+
# No external DNS servers listed to prevent DNS-based data exfiltration
9394
{
9495
echo "# Generated by awf entrypoint"
95-
echo "# Docker embedded DNS for service name resolution (squid-proxy, etc.)"
96+
echo "# Docker embedded DNS handles all resolution (forwards to upstream via docker-compose dns: config)"
9697
echo "nameserver 127.0.0.11"
97-
echo "# Trusted external DNS servers for internet domain resolution"
98-
99-
# Add each trusted DNS server
100-
IFS=',' read -ra DNS_ARRAY <<< "$DNS_SERVERS"
101-
for dns_server in "${DNS_ARRAY[@]}"; do
102-
dns_server=$(echo "$dns_server" | tr -d ' ')
103-
if [ -n "$dns_server" ]; then
104-
echo "nameserver $dns_server"
105-
fi
106-
done
107-
10898
echo "options ndots:0"
10999
} > /etc/resolv.conf
110-
111-
echo "[entrypoint] DNS configured with Docker embedded DNS (127.0.0.11) and trusted servers: $DNS_SERVERS"
100+
echo "[entrypoint] DNS configured with Docker embedded DNS (127.0.0.11) only"
112101
fi
113102
fi
114103

containers/agent/setup-iptables.sh

Lines changed: 52 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,30 @@ else
6060
echo "[iptables] Squid IP resolved to: $SQUID_IP"
6161
fi
6262

63+
# Save Docker's embedded DNS DNAT rules before flushing.
64+
# Docker adds DNAT rules to redirect 127.0.0.11:53 to its internal DNS server
65+
# on a random high port. Flushing the NAT chain destroys these rules, breaking
66+
# DNS resolution via Docker embedded DNS.
67+
DOCKER_DNS_RULES=$(iptables-save -t nat 2>/dev/null | grep -- "-A OUTPUT.*127.0.0.11" || true)
68+
6369
# Clear existing NAT rules (both IPv4 and IPv6)
6470
iptables -t nat -F OUTPUT 2>/dev/null || true
6571
if [ "$IP6TABLES_AVAILABLE" = true ]; then
6672
ip6tables -t nat -F OUTPUT 2>/dev/null || true
6773
fi
6874

75+
# Restore Docker's embedded DNS DNAT rules (must come before localhost RETURN rules
76+
# so that DNS queries to 127.0.0.11:53 are properly redirected to Docker's DNS server)
77+
if [ -n "$DOCKER_DNS_RULES" ]; then
78+
echo "[iptables] Restoring Docker embedded DNS DNAT rules..."
79+
while IFS= read -r rule; do
80+
if [ -n "$rule" ]; then
81+
# iptables-save outputs rules like "-A OUTPUT -d 127.0.0.11/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:XXXXX"
82+
iptables -t nat $rule 2>/dev/null || true
83+
fi
84+
done <<< "$DOCKER_DNS_RULES"
85+
fi
86+
6987
# Allow localhost traffic (for stdio MCP servers and test frameworks)
7088
echo "[iptables] Allow localhost traffic..."
7189
iptables -t nat -A OUTPUT -o lo -j RETURN
@@ -87,9 +105,6 @@ if [ -n "$AGENT_IP" ] && is_valid_ipv4 "$AGENT_IP"; then
87105
iptables -A OUTPUT -p tcp -d "$AGENT_IP" -j ACCEPT
88106
fi
89107

90-
# Get DNS servers from environment (default to Google DNS)
91-
DNS_SERVERS="${AWF_DNS_SERVERS:-8.8.8.8,8.8.4.4}"
92-
93108
# Check if DNS-over-HTTPS mode is enabled
94109
if [ "$AWF_DOH_ENABLED" = "true" ] && [ -n "$AWF_DOH_PROXY_IP" ]; then
95110
echo "[iptables] DNS-over-HTTPS mode: routing DNS through DoH proxy at $AWF_DOH_PROXY_IP"
@@ -105,66 +120,35 @@ if [ "$AWF_DOH_ENABLED" = "true" ] && [ -n "$AWF_DOH_PROXY_IP" ]; then
105120

106121
# Allow return traffic to DoH proxy
107122
iptables -t nat -A OUTPUT -d "$AWF_DOH_PROXY_IP" -j RETURN
108-
109-
# Set variables for OUTPUT filter chain (used later)
110-
IPV4_DNS_SERVERS=()
111-
IPV6_DNS_SERVERS=()
112123
else
113-
echo "[iptables] Configuring DNS rules for trusted servers: $DNS_SERVERS"
114-
115-
# Separate IPv4 and IPv6 DNS servers
116-
IPV4_DNS_SERVERS=()
117-
IPV6_DNS_SERVERS=()
124+
# Simplified DNS model: Docker embedded DNS (127.0.0.11) handles all name resolution.
125+
# The embedded DNS forwards to upstream servers configured via docker-compose dns: field.
126+
# Docker's DNS forwarding may traverse the container's network namespace, so we must
127+
# explicitly allow UDP/TCP port 53 to the configured upstream servers.
128+
# Direct DNS queries to non-configured servers are blocked by the OUTPUT filter chain.
129+
DNS_SERVERS="${AWF_DNS_SERVERS:-8.8.8.8,8.8.4.4}"
130+
echo "[iptables] DNS: Docker embedded DNS forwards to upstream: $DNS_SERVERS"
131+
132+
# Allow DNS queries to configured upstream servers (needed for Docker DNS forwarding)
118133
IFS=',' read -ra DNS_ARRAY <<< "$DNS_SERVERS"
119134
for dns_server in "${DNS_ARRAY[@]}"; do
120135
dns_server=$(echo "$dns_server" | tr -d ' ')
121136
if [ -n "$dns_server" ]; then
122137
if is_ipv6 "$dns_server"; then
123-
IPV6_DNS_SERVERS+=("$dns_server")
138+
if [ "$IP6TABLES_AVAILABLE" = true ]; then
139+
ip6tables -t nat -A OUTPUT -p udp -d "$dns_server" --dport 53 -j RETURN
140+
ip6tables -t nat -A OUTPUT -p tcp -d "$dns_server" --dport 53 -j RETURN
141+
fi
124142
else
125-
IPV4_DNS_SERVERS+=("$dns_server")
143+
iptables -t nat -A OUTPUT -p udp -d "$dns_server" --dport 53 -j RETURN
144+
iptables -t nat -A OUTPUT -p tcp -d "$dns_server" --dport 53 -j RETURN
126145
fi
127146
fi
128147
done
129148

130-
echo "[iptables] IPv4 DNS servers: ${IPV4_DNS_SERVERS[*]:-none}"
131-
echo "[iptables] IPv6 DNS servers: ${IPV6_DNS_SERVERS[*]:-none}"
132-
133-
# Allow DNS queries ONLY to trusted IPv4 DNS servers (prevents DNS exfiltration)
134-
for dns_server in "${IPV4_DNS_SERVERS[@]}"; do
135-
echo "[iptables] Allow DNS to trusted IPv4 server: $dns_server"
136-
iptables -t nat -A OUTPUT -p udp -d "$dns_server" --dport 53 -j RETURN
137-
iptables -t nat -A OUTPUT -p tcp -d "$dns_server" --dport 53 -j RETURN
138-
done
139-
140-
# Allow DNS queries ONLY to trusted IPv6 DNS servers
141-
if [ "$IP6TABLES_AVAILABLE" = true ]; then
142-
for dns_server in "${IPV6_DNS_SERVERS[@]}"; do
143-
echo "[iptables] Allow DNS to trusted IPv6 server: $dns_server"
144-
ip6tables -t nat -A OUTPUT -p udp -d "$dns_server" --dport 53 -j RETURN
145-
ip6tables -t nat -A OUTPUT -p tcp -d "$dns_server" --dport 53 -j RETURN
146-
done
147-
elif [ ${#IPV6_DNS_SERVERS[@]} -gt 0 ]; then
148-
echo "[iptables] WARNING: IPv6 DNS servers configured but ip6tables not available"
149-
fi
150-
151-
# Allow DNS to Docker's embedded DNS server (127.0.0.11) for container name resolution
152-
echo "[iptables] Allow DNS to Docker embedded DNS (127.0.0.11)..."
149+
# Also allow DNS to Docker's embedded DNS server itself
153150
iptables -t nat -A OUTPUT -p udp -d 127.0.0.11 --dport 53 -j RETURN
154151
iptables -t nat -A OUTPUT -p tcp -d 127.0.0.11 --dport 53 -j RETURN
155-
156-
# Allow return traffic to trusted IPv4 DNS servers
157-
echo "[iptables] Allow traffic to trusted DNS servers..."
158-
for dns_server in "${IPV4_DNS_SERVERS[@]}"; do
159-
iptables -t nat -A OUTPUT -d "$dns_server" -j RETURN
160-
done
161-
162-
# Allow return traffic to trusted IPv6 DNS servers
163-
if [ "$IP6TABLES_AVAILABLE" = true ]; then
164-
for dns_server in "${IPV6_DNS_SERVERS[@]}"; do
165-
ip6tables -t nat -A OUTPUT -d "$dns_server" -j RETURN
166-
done
167-
fi
168152
fi
169153

170154
# Allow traffic to Squid proxy itself (prevent redirect loop)
@@ -298,23 +282,27 @@ fi
298282
# These rules apply AFTER NAT translation
299283
echo "[iptables] Configuring OUTPUT filter chain rules..."
300284

301-
# Allow localhost traffic
285+
# Allow localhost traffic (includes Docker embedded DNS at 127.0.0.11)
302286
iptables -A OUTPUT -o lo -j ACCEPT
303287

304-
# Allow DNS queries to trusted servers (or DoH proxy)
288+
# Allow DNS to DoH proxy or configured upstream servers
305289
if [ "$AWF_DOH_ENABLED" = "true" ] && [ -n "$AWF_DOH_PROXY_IP" ]; then
306290
iptables -A OUTPUT -p udp -d "$AWF_DOH_PROXY_IP" --dport 53 -j ACCEPT
307291
iptables -A OUTPUT -p tcp -d "$AWF_DOH_PROXY_IP" --dport 53 -j ACCEPT
308292
else
309-
for dns_server in "${IPV4_DNS_SERVERS[@]}"; do
310-
iptables -A OUTPUT -p udp -d "$dns_server" --dport 53 -j ACCEPT
311-
iptables -A OUTPUT -p tcp -d "$dns_server" --dport 53 -j ACCEPT
293+
# Allow DNS to configured upstream servers (needed for Docker DNS forwarding)
294+
for dns_server in "${DNS_ARRAY[@]}"; do
295+
dns_server=$(echo "$dns_server" | tr -d ' ')
296+
if [ -n "$dns_server" ] && ! is_ipv6 "$dns_server"; then
297+
iptables -A OUTPUT -p udp -d "$dns_server" --dport 53 -j ACCEPT
298+
iptables -A OUTPUT -p tcp -d "$dns_server" --dport 53 -j ACCEPT
299+
fi
312300
done
313-
fi
314301

315-
# Allow DNS to Docker's embedded DNS server
316-
iptables -A OUTPUT -p udp -d 127.0.0.11 --dport 53 -j ACCEPT
317-
iptables -A OUTPUT -p tcp -d 127.0.0.11 --dport 53 -j ACCEPT
302+
# Allow DNS to Docker's embedded DNS server
303+
iptables -A OUTPUT -p udp -d 127.0.0.11 --dport 53 -j ACCEPT
304+
iptables -A OUTPUT -p tcp -d 127.0.0.11 --dport 53 -j ACCEPT
305+
fi
318306

319307
# Allow traffic to Squid proxy (after NAT redirection)
320308
iptables -A OUTPUT -p tcp -d "$SQUID_IP" -j ACCEPT
@@ -324,10 +312,12 @@ if [ -n "$AWF_API_PROXY_IP" ]; then
324312
iptables -A OUTPUT -p tcp -d "$AWF_API_PROXY_IP" -j ACCEPT
325313
fi
326314

327-
# Drop all other TCP traffic (default deny policy)
328-
# This ensures that only explicitly allowed ports can be accessed
329-
echo "[iptables] Drop all non-redirected TCP traffic (default deny)..."
315+
# Drop all other TCP and UDP traffic (default deny policy)
316+
# TCP: ensures only explicitly allowed ports can be accessed
317+
# UDP: prevents DNS exfiltration by blocking direct queries to non-configured DNS servers
318+
echo "[iptables] Drop all non-allowed TCP and UDP traffic (default deny)..."
330319
iptables -A OUTPUT -p tcp -j DROP
320+
iptables -A OUTPUT -p udp -j DROP
331321

332322
echo "[iptables] NAT rules applied successfully"
333323
echo "[iptables] Current IPv4 NAT OUTPUT rules:"

src/cli-workflow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ export async function runMainWorkflow(
4343
// Step 0: Setup host-level network and iptables
4444
logger.info('Setting up host-level firewall network and iptables rules...');
4545
const networkConfig = await dependencies.ensureFirewallNetwork();
46-
const dnsServers = config.dnsServers || ['8.8.8.8', '8.8.4.4'];
4746
// When API proxy is enabled, allow agent→sidecar traffic at the host level.
4847
// The sidecar itself routes through Squid, so domain whitelisting is still enforced.
48+
const dnsServers = config.dnsServers || ['8.8.8.8', '8.8.4.4'];
4949
const apiProxyIp = config.enableApiProxy ? networkConfig.proxyIp : undefined;
5050
// When DoH is enabled, the DoH proxy needs direct HTTPS access to the resolver
5151
const dohProxyIp = config.dnsOverHttps ? '172.30.0.40' : undefined;

src/cli.test.ts

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,6 @@ describe('cli', () => {
347347
program
348348
.option('--log-level <level>', 'Log level', 'info')
349349
.option('--keep-containers', 'Keep containers', false)
350-
.option('--skip-cleanup', 'Skip all cleanup', false)
351350
.option('--build-local', 'Build locally', false)
352351
.option('--env-all', 'Pass all env vars', false);
353352

@@ -357,22 +356,9 @@ describe('cli', () => {
357356

358357
expect(opts.logLevel).toBe('info');
359358
expect(opts.keepContainers).toBe(false);
360-
expect(opts.skipCleanup).toBe(false);
361359
expect(opts.buildLocal).toBe(false);
362360
expect(opts.envAll).toBe(false);
363361
});
364-
365-
it('should parse --skip-cleanup flag when provided', () => {
366-
const program = new Command();
367-
368-
program
369-
.option('--skip-cleanup', 'Skip all cleanup', false);
370-
371-
program.parse(['node', 'awf', '--skip-cleanup'], { from: 'node' });
372-
const opts = program.opts();
373-
374-
expect(opts.skipCleanup).toBe(true);
375-
});
376362
});
377363

378364
describe('argument parsing with variadic args', () => {
@@ -1334,32 +1320,6 @@ describe('cli', () => {
13341320
});
13351321
});
13361322

1337-
describe('hasRateLimitOptions', () => {
1338-
it('should return false when no rate limit options are set', () => {
1339-
expect(hasRateLimitOptions({})).toBe(false);
1340-
});
1341-
1342-
it('should return true when rateLimitRpm is set', () => {
1343-
expect(hasRateLimitOptions({ rateLimitRpm: '100' })).toBe(true);
1344-
});
1345-
1346-
it('should return true when rateLimitRph is set', () => {
1347-
expect(hasRateLimitOptions({ rateLimitRph: '1000' })).toBe(true);
1348-
});
1349-
1350-
it('should return true when rateLimitBytesPm is set', () => {
1351-
expect(hasRateLimitOptions({ rateLimitBytesPm: '50000000' })).toBe(true);
1352-
});
1353-
1354-
it('should return true when rateLimit is explicitly false', () => {
1355-
expect(hasRateLimitOptions({ rateLimit: false })).toBe(true);
1356-
});
1357-
1358-
it('should return false when rateLimit is true (default enabling)', () => {
1359-
expect(hasRateLimitOptions({ rateLimit: true })).toBe(false);
1360-
});
1361-
});
1362-
13631323
describe('validateSkipPullWithBuildLocal', () => {
13641324
it('should return valid when both flags are false', () => {
13651325
const result = validateSkipPullWithBuildLocal(false, false);
@@ -2060,4 +2020,30 @@ describe('cli', () => {
20602020
});
20612021
});
20622022
});
2023+
2024+
describe('hasRateLimitOptions', () => {
2025+
it('returns false when no rate limit options are set', () => {
2026+
expect(hasRateLimitOptions({})).toBe(false);
2027+
});
2028+
2029+
it('returns true when rateLimitRpm is set', () => {
2030+
expect(hasRateLimitOptions({ rateLimitRpm: '100' })).toBe(true);
2031+
});
2032+
2033+
it('returns true when rateLimitRph is set', () => {
2034+
expect(hasRateLimitOptions({ rateLimitRph: '1000' })).toBe(true);
2035+
});
2036+
2037+
it('returns true when rateLimitBytesPm is set', () => {
2038+
expect(hasRateLimitOptions({ rateLimitBytesPm: '1048576' })).toBe(true);
2039+
});
2040+
2041+
it('returns true when rateLimit is explicitly false', () => {
2042+
expect(hasRateLimitOptions({ rateLimit: false })).toBe(true);
2043+
});
2044+
2045+
it('returns false when rateLimit is true', () => {
2046+
expect(hasRateLimitOptions({ rateLimit: true })).toBe(false);
2047+
});
2048+
});
20632049
});

src/docker-manager.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,7 @@ describe('docker-manager', () => {
15201520
});
15211521

15221522
describe('dnsServers option', () => {
1523-
it('should use custom DNS servers when specified', () => {
1523+
it('should use custom DNS servers for Docker embedded DNS forwarding', () => {
15241524
const config: WrapperConfig = {
15251525
...mockConfig,
15261526
dnsServers: ['1.1.1.1', '1.0.0.1'],
@@ -1530,6 +1530,7 @@ describe('docker-manager', () => {
15301530
const env = agent.environment as Record<string, string>;
15311531

15321532
expect(agent.dns).toEqual(['1.1.1.1', '1.0.0.1']);
1533+
// AWF_DNS_SERVERS env var should be set for setup-iptables.sh DNS ACCEPT rules
15331534
expect(env.AWF_DNS_SERVERS).toBe('1.1.1.1,1.0.0.1');
15341535
});
15351536

@@ -1539,6 +1540,7 @@ describe('docker-manager', () => {
15391540
const env = agent.environment as Record<string, string>;
15401541

15411542
expect(agent.dns).toEqual(['8.8.8.8', '8.8.4.4']);
1543+
// AWF_DNS_SERVERS env var should be set for setup-iptables.sh DNS ACCEPT rules
15421544
expect(env.AWF_DNS_SERVERS).toBe('8.8.8.8,8.8.4.4');
15431545
});
15441546
});

0 commit comments

Comments
 (0)