Skip to content

[Test Coverage] Improve host-iptables.ts branch coverage from 83% to 99%#1691

Open
github-actions[bot] wants to merge 1 commit intomainfrom
test-coverage/host-iptables-branch-coverage-7eaec73b4d4c6e4c
Open

[Test Coverage] Improve host-iptables.ts branch coverage from 83% to 99%#1691
github-actions[bot] wants to merge 1 commit intomainfrom
test-coverage/host-iptables-branch-coverage-7eaec73b4d4c6e4c

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot commented Apr 6, 2026

Summary

Adds 17 new tests to src/host-iptables.test.ts targeting previously uncovered branches in the security-critical host-iptables.ts module.

Coverage Improvements

host-iptables.ts

Metric Before After Change
Statements 91.6% 100% +8.4%
Branches 83.3% 98.95% +15.7%
Functions 100% 100%
Lines 91.9% 100% +8.1%

Overall Project

Metric Before After Change
Statements 84.34% 85.00% +0.66%
Branches 77.43% 78.24% +0.81%

Security-Critical Paths Now Covered

IPv6 Handling (Bypass Prevention)

  • FW_WRAPPER_V6 chain creation when IPv6 DNS servers are provided and ip6tables is available
  • Cleanup of pre-existing FW_WRAPPER_V6 chain before recreating (prevents stale rules)
  • Correct fallback when ip6tables is unavailable even with IPv6 DNS servers configured
  • Error recovery when IPv6 chain cleanup throws during setup

Docker Bridge Gateway Validation

  • getDockerBridgeGateway returns null when Docker bridge returns empty stdout — prevents empty string from being used in iptables rules
  • getDockerBridgeGateway returns null when Docker bridge returns non-IPv4 (e.g., hostname) — prevents invalid IPs from entering firewall rules

DNS Server Fallback

  • Empty dnsServers array correctly falls back to DEFAULT_DNS_SERVERS (Google DNS), preventing an open DNS channel

Port Validation

  • Empty entries from allowHostServicePorts splits (e.g., "5432,,6379") are silently skipped
  • Invalid ports in allowHostServicePorts are skipped with a warning (mirrors existing behavior for allowHostPorts)

Error Paths

  • sysctl failure when disabling IPv6 (doesn't throw, logs warning)
  • sysctl failure when re-enabling IPv6 on cleanup (doesn't throw, logs debug)
  • iptables -N DOCKER-USER failure after chain not found (propagates error with clear message)
  • FW_WRAPPER chain flush failure during cleanup (caught, doesn't throw)

Line Parsing Edge Cases

  • DOCKER-USER lines containing the chain name but without a leading line number (e.g., table headers) are correctly skipped in both IPv4 and IPv6 cleanup paths

No Existing Tests Modified

All 3 pre-existing test failures in docker-manager.test.ts remain unchanged (unrelated to this PR).

Generated by Weekly Test Coverage Improver · ● 10.4M ·

Add 17 new tests to host-iptables.test.ts covering previously uncovered
security-critical branches:

- IPv6 DNS handling: FW_WRAPPER_V6 chain creation, existing chain cleanup,
  ip6tables unavailable fallback, IPv6 chain cleanup error recovery
- Docker bridge gateway validation: empty stdout returns null, non-IPv4
  gateway returns null (prevents invalid IPs in iptables rules)
- Default DNS servers: empty dnsServers array falls back to DEFAULT_DNS_SERVERS
- Port validation: empty entries and invalid ports in allowHostServicePorts
  are silently skipped with warning
- Error paths: sysctl failure when disabling/re-enabling IPv6, failed
  DOCKER-USER chain creation, FW_WRAPPER chain cleanup errors
- DOCKER-USER line parsing: header lines containing chain name but no
  leading line number are correctly skipped

Coverage improvements for host-iptables.ts:
  Statements:  91.6% → 100%
  Branches:    83.3% → 98.95%
  Functions:   100%  → 100%
  Lines:       91.9% → 100%

Overall project coverage improvements:
  Statements:  84.34% → 85.00%
  Branches:    77.43% → 78.24%

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Mossaka Mossaka marked this pull request as ready for review April 6, 2026 16:27
@Mossaka Mossaka self-requested a review as a code owner April 6, 2026 16:27
Copilot AI review requested due to automatic review settings April 6, 2026 16:27
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 6, 2026

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 86.20% 86.94% 📈 +0.74%
Statements 86.07% 86.82% 📈 +0.75%
Functions 87.41% 87.41% ➡️ +0.00%
Branches 78.57% 79.43% 📈 +0.86%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 86.6% → 87.0% (+0.39%) 86.1% → 86.5% (+0.38%)
src/host-iptables.ts 91.9% → 100.0% (+8.10%) 91.6% → 100.0% (+8.40%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 6, 2026

Smoke Test Results

Overall: PASS

💥 [THE END] — Illustrated by Smoke Claude

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds additional Jest unit tests to increase branch/line coverage for the security-critical host firewall setup/cleanup logic in host-iptables.ts, focusing on IPv6 handling, DOCKER-USER parsing edge cases, DNS defaults, host-access gateway validation, and error paths.

Changes:

  • Expanded setupHostIptables tests to cover IPv6 sysctl failure paths, DOCKER-USER chain creation failures, and IPv6 DNS chain setup/cleanup branches.
  • Added cleanupHostIptables tests for DOCKER-USER parsing edge cases, IPv6 cleanup error paths, and sysctl re-enable failure handling.
  • Added host-access tests for Docker bridge gateway edge cases (empty/invalid gateway) and port list parsing (empty/invalid entries).
Show a summary per file
File Description
src/host-iptables.test.ts Adds new tests targeting previously uncovered branches in host iptables setup/cleanup logic (IPv6, DNS defaults, DOCKER-USER parsing, host-access gateways/ports, error paths).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (6)

src/host-iptables.test.ts:596

  • This test uses expect(promise).resolves.not.toThrow(), but .toThrow() requires a function and will fail when the promise resolves to void. Use .resolves.toBeUndefined() (or just await setupHostIptables(...)) to assert the call completes without throwing.
      // Should not throw - error during cleanup is caught and logged
      await expect(setupHostIptables('172.30.0.10', 3128, ['8.8.8.8'])).resolves.not.toThrow();
    });

src/host-iptables.test.ts:1128

  • expect(promise).resolves.not.toThrow() is invalid here for the same reason elsewhere: .toThrow() expects a function, not a resolved void value. Replace with .resolves.toBeUndefined() or just await cleanupHostIptables().
      // Should not throw - header lines with no numbers are silently skipped
      await expect(cleanupHostIptables()).resolves.not.toThrow();

src/host-iptables.test.ts:1170

  • expect(promise).resolves.not.toThrow() will fail because the promise resolves to void and .toThrow() requires a function. Use .resolves.toBeUndefined() or just await cleanupHostIptables() to assert no throw.
      // Should not throw - enableIpv6ViaSysctl catches sysctl errors
      await expect(cleanupHostIptables()).resolves.not.toThrow();
    });

src/host-iptables.test.ts:1195

  • Same issue: expect(promise).resolves.not.toThrow() is not a valid Promise assertion in Jest (resolved value is void). Replace with .resolves.toBeUndefined() / await cleanupHostIptables().
      // Should not throw - error during IPv6 chain cleanup is caught and logged
      await expect(cleanupHostIptables()).resolves.not.toThrow();
    });

src/host-iptables.test.ts:1435

  • expect(promise).resolves.not.toThrow() is not a valid Jest assertion here (the promise resolves to void, but .toThrow() expects a function). Use .resolves.toBeUndefined() or just await setupHostIptables(...) to assert success.
      // Should not throw - the error during IPv6 chain cleanup is caught and logged
      await expect(
        setupHostIptables('172.30.0.10', 3128, ['8.8.8.8', '2001:4860:4860::8888'])
      ).resolves.not.toThrow();

src/host-iptables.test.ts:1428

  • This test simulates ip6tables -F FW_WRAPPER_V6 throwing while the chain “exists” (v6ChainExists === 0), then expects setup to continue successfully. In setupHostIptables, ip6tables -N FW_WRAPPER_V6 is executed after the cleanup try/catch; if the flush throws before -X runs, the chain may still exist and -N would typically fail. To keep the test aligned with production behavior, either simulate a cleanup failure that doesn’t imply the chain still exists, or assert the expected rejection.
        if (cmd === 'ip6tables' && args[2] === '-L' && args[3] === 'FW_WRAPPER_V6') {
          // Chain exists
          return Promise.resolve({ exitCode: 0 } as any);
        }
        if (cmd === 'ip6tables' && args[2] === '-F') {
          // Flush throws an actual error (not just non-zero exit)
          return Promise.reject(new Error('ip6tables: internal error during flush'));
        }
  • Files reviewed: 1/1 changed files
  • Comments generated: 2

}) as any);

// Should not throw - disableIpv6ViaSysctl catches sysctl errors
await expect(setupHostIptables('172.30.0.10', 3128, ['8.8.8.8'])).resolves.not.toThrow();
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expect(promise).resolves.not.toThrow() is not a valid Jest assertion because .toThrow() expects a function, not the resolved value of a Promise (this Promise resolves to void). Replace with an assertion on the resolved value (e.g., .resolves.toBeUndefined()), or simply await setupHostIptables(...) with no expect if the goal is just “does not throw”.

This issue also appears in the following locations of the same file:

  • line 594
  • line 1126
  • line 1168
  • line 1193
  • line 1432
Suggested change
await expect(setupHostIptables('172.30.0.10', 3128, ['8.8.8.8'])).resolves.not.toThrow();
await setupHostIptables('172.30.0.10', 3128, ['8.8.8.8']);

Copilot uses AI. Check for mistakes.
Comment on lines +587 to +595
// Flush FW_WRAPPER - throws!
.mockRejectedValueOnce(new Error('iptables: Chain flush failed'));

// After the error in chain cleanup, the outer try-catch should handle it;
// but then creating FW_WRAPPER chain will be attempted and also succeed
mockedExeca.mockResolvedValue({ stdout: '', stderr: '', exitCode: 0 } as any);

// Should not throw - error during cleanup is caught and logged
await expect(setupHostIptables('172.30.0.10', 3128, ['8.8.8.8'])).resolves.not.toThrow();
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock simulates iptables -F FW_WRAPPER throwing, then asserts setup succeeds. In setupHostIptables, the chain is re-created unconditionally with iptables -N FW_WRAPPER outside the cleanup try/catch; if the flush throws before the chain is deleted, the chain likely still exists and -N would fail in a real run. Consider adjusting the simulated failure point (or the expected outcome) so the test matches the production control flow.

This issue also appears on line 1421 of the same file.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 6, 2026

🔥 Smoke Test Results — PASS

Test Result
GitHub MCP (list PRs) ✅ PR #1701 returned
GitHub.com connectivity ✅ HTTP 200
File write/read /tmp/gh-aw/agent/smoke-test-copilot-24040169335.txt

PR: [Test Coverage] Improve host-iptables.ts branch coverage from 83% to 99%
Author: @github-actions[bot] · No assignees

📰 BREAKING: Report filed by Smoke Copilot

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 6, 2026

Smoke Test Results (Codex)
PR titles (last 2 merged):

  • ⚡ pelis-agent-factory-advisor: pre-fetch content, restrict tools, reduce prompt tokens (~21% token savings)
  • chore: upgrade gh-aw to v0.67.0 and recompile all workflows
    GitHub MCP review: ✅
    safeinputs-gh PR query: ❌
    Playwright github.com title check: ❌
    Tavily web search: ❌
    File write + cat verify: ✅
    Build (npm ci && npm run build): ✅
    Discussion query + mystical discussion comment: ❌
    Overall status: FAIL

🔮 The oracle has spoken through Smoke Codex

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 6, 2026

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ NO
Node.js v24.14.1 v20.20.2 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: ❌ NOT all tests passed — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 6, 2026

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color passed ✅ PASS
Go env passed ✅ PASS
Go uuid passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx passed ✅ PASS
Node.js execa passed ✅ PASS
Node.js p-limit passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Generated by Build Test Suite for issue #1691 · ● 454.1K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants