From 0dac6611fc1bb6501afffd9152580aca8be4cfba Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 09:22:33 +0000 Subject: [PATCH 1/2] test: add dedicated unit tests for isValidPortSpec Cover boundary values and edge cases in the isValidPortSpec helper inside host-iptables-rules.ts that were not exercised by the existing integration tests (host-iptables-setup.test.ts, host-iptables-host-access.test.ts): - Single port: minimum (1), maximum (65535), zero, out-of-range, negative, leading zeros, empty string, non-numeric, floats, whitespace - Port range: valid ranges, reversed start/end, zero bounds, out-of-range ends, leading zeros in either component, non-numeric components 28 new tests, all passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/host-iptables-rules.test.ts | 159 ++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/host-iptables-rules.test.ts diff --git a/src/host-iptables-rules.test.ts b/src/host-iptables-rules.test.ts new file mode 100644 index 00000000..2aef02a9 --- /dev/null +++ b/src/host-iptables-rules.test.ts @@ -0,0 +1,159 @@ +/** + * Unit tests for host-iptables-rules.ts internals. + * + * The integration-level behaviour (setupHostIptables full flows with hostAccess, + * cliProxy, DoH, etc.) lives in host-iptables-setup.test.ts and + * host-iptables-host-access.test.ts. This file targets the pure-logic helpers + * that those suites never exercise directly: + * + * - isValidPortSpec – boundary values, leading zeros, floats, ranges + */ + +import { iptablesRulesTestHelpers } from './host-iptables-rules.test-utils'; + +const { isValidPortSpec } = iptablesRulesTestHelpers; + +describe('isValidPortSpec – single port', () => { + it('accepts the minimum valid port (1)', () => { + expect(isValidPortSpec('1')).toBe(true); + }); + + it('accepts the maximum valid port (65535)', () => { + expect(isValidPortSpec('65535')).toBe(true); + }); + + it('accepts common HTTP / HTTPS ports', () => { + expect(isValidPortSpec('80')).toBe(true); + expect(isValidPortSpec('443')).toBe(true); + expect(isValidPortSpec('3128')).toBe(true); + }); + + it('rejects port 0 (below the valid range)', () => { + expect(isValidPortSpec('0')).toBe(false); + }); + + it('rejects port 65536 (above the valid range)', () => { + expect(isValidPortSpec('65536')).toBe(false); + }); + + it('rejects very large numbers', () => { + expect(isValidPortSpec('99999')).toBe(false); + expect(isValidPortSpec('100000')).toBe(false); + }); + + it('rejects negative numbers', () => { + expect(isValidPortSpec('-1')).toBe(false); + expect(isValidPortSpec('-80')).toBe(false); + expect(isValidPortSpec('-443')).toBe(false); + }); + + it('rejects port with leading zeros', () => { + // parseInt("080") === 80 but String(80) !== "080" + expect(isValidPortSpec('080')).toBe(false); + expect(isValidPortSpec('0080')).toBe(false); + expect(isValidPortSpec('00443')).toBe(false); + }); + + it('rejects an empty string', () => { + expect(isValidPortSpec('')).toBe(false); + }); + + it('rejects purely alphabetic strings', () => { + expect(isValidPortSpec('abc')).toBe(false); + expect(isValidPortSpec('http')).toBe(false); + expect(isValidPortSpec('NaN')).toBe(false); + }); + + it('rejects alphanumeric strings', () => { + expect(isValidPortSpec('80abc')).toBe(false); + expect(isValidPortSpec('abc80')).toBe(false); + expect(isValidPortSpec('8 0')).toBe(false); + }); + + it('rejects floating-point port numbers (integer part is valid but whole spec is not)', () => { + expect(isValidPortSpec('80.5')).toBe(false); + expect(isValidPortSpec('3000.0')).toBe(false); + }); + + it('rejects strings with leading or trailing whitespace', () => { + expect(isValidPortSpec(' 80')).toBe(false); + expect(isValidPortSpec('80 ')).toBe(false); + expect(isValidPortSpec(' 80 ')).toBe(false); + }); +}); + +describe('isValidPortSpec – port range', () => { + it('accepts a valid minimal range (1-2)', () => { + expect(isValidPortSpec('1-2')).toBe(true); + }); + + it('accepts the full valid range (1-65535)', () => { + expect(isValidPortSpec('1-65535')).toBe(true); + }); + + it('accepts a single-value range (equal start and end)', () => { + expect(isValidPortSpec('80-80')).toBe(true); + expect(isValidPortSpec('65535-65535')).toBe(true); + }); + + it('accepts typical application port ranges', () => { + expect(isValidPortSpec('3000-3010')).toBe(true); + expect(isValidPortSpec('8080-8090')).toBe(true); + expect(isValidPortSpec('10000-10003')).toBe(true); + }); + + it('rejects a reversed range (start > end)', () => { + expect(isValidPortSpec('3010-3000')).toBe(false); + expect(isValidPortSpec('65535-1')).toBe(false); + expect(isValidPortSpec('443-80')).toBe(false); + }); + + it('rejects a range whose start is 0', () => { + expect(isValidPortSpec('0-100')).toBe(false); + expect(isValidPortSpec('0-65535')).toBe(false); + }); + + it('rejects a range whose end is 0', () => { + expect(isValidPortSpec('100-0')).toBe(false); + }); + + it('rejects a range whose end exceeds 65535', () => { + expect(isValidPortSpec('1-65536')).toBe(false); + expect(isValidPortSpec('60000-70000')).toBe(false); + }); + + it('rejects a range whose start exceeds 65535', () => { + expect(isValidPortSpec('65536-65537')).toBe(false); + }); + + it('rejects a range with leading zeros in the start value', () => { + // String(parseInt("01", 10)) = "1" !== "01" + expect(isValidPortSpec('01-100')).toBe(false); + expect(isValidPortSpec('008-100')).toBe(false); + }); + + it('rejects a range with leading zeros in the end value', () => { + expect(isValidPortSpec('1-0100')).toBe(false); + expect(isValidPortSpec('80-0443')).toBe(false); + }); + + it('rejects a range with both parts having leading zeros', () => { + expect(isValidPortSpec('080-0443')).toBe(false); + }); + + it('rejects non-numeric range components', () => { + expect(isValidPortSpec('abc-def')).toBe(false); + }); + + it('rejects a single hyphen (empty range components)', () => { + // "-" has digits on neither side matching /^(\d+)-(\d+)$/ + expect(isValidPortSpec('-')).toBe(false); + }); + + it('rejects a range with whitespace', () => { + // Spaces are not digits, so the regex won't match + expect(isValidPortSpec('80 - 443')).toBe(false); + expect(isValidPortSpec('80- 443')).toBe(false); + expect(isValidPortSpec(' 80-443')).toBe(false); + }); +}); From 4cf330f69550fb94a41be91cd96508cbc9eb3859 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Tue, 9 Jun 2026 06:54:13 -0700 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/host-iptables-rules.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/host-iptables-rules.test.ts b/src/host-iptables-rules.test.ts index 2aef02a9..a0f16c7b 100644 --- a/src/host-iptables-rules.test.ts +++ b/src/host-iptables-rules.test.ts @@ -3,8 +3,8 @@ * * The integration-level behaviour (setupHostIptables full flows with hostAccess, * cliProxy, DoH, etc.) lives in host-iptables-setup.test.ts and - * host-iptables-host-access.test.ts. This file targets the pure-logic helpers - * that those suites never exercise directly: + * host-iptables-host-access.test.ts. This file adds focused unit coverage for + * pure-logic helpers that those suites only sanity-check: * * - isValidPortSpec – boundary values, leading zeros, floats, ranges */