Skip to content

refactor: decompose validateDomainOrPattern and split domain-patterns.ts by concern#5063

Merged
lpcox merged 3 commits into
mainfrom
copilot/refactor-validate-domain-or-pattern
Jun 15, 2026
Merged

refactor: decompose validateDomainOrPattern and split domain-patterns.ts by concern#5063
lpcox merged 3 commits into
mainfrom
copilot/refactor-validate-domain-or-pattern

Conversation

Copilot AI commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

src/domain-patterns.ts conflated three distinct concerns in one 417-line file, with the security-critical validateDomainOrPattern being a 106-line monolith that buried each individual injection-prevention check.

Split by concern

Module Responsibility
src/domain-patterns.ts Shared types (DomainProtocol, DomainPattern, PlainDomainEntry, ParsedDomain) + low-level utilities (parseDomainWithProtocol, isWildcardPattern, wildcardToRegex)
src/domain-validation.ts SQUID_DANGEROUS_CHARS, validateDomainOrPattern, private sub-validators
src/domain-matchers.ts parseDomainList, isDomainMatchedByPattern, parseUrlPatterns, ParsedDomainList

validateDomainOrPattern decomposed into named helpers

The 106-line function is now a readable orchestrator delegating to three private helpers:

export function validateDomainOrPattern(input: string): void {
  if (!input || input.trim() === '') throw new Error('Domain cannot be empty');
  const { domain: trimmed } = parseDomainWithProtocol(input);
  if (!trimmed) throw new Error('Domain cannot be empty');

  checkDangerousChars(trimmed);      // Squid injection prevention
  checkOverBroadPattern(trimmed);    // rejects *, *.*, wildcard-only combos
  checkStructuralValidity(trimmed);  // double dots, bare .  *.  .*, excess wildcard segments
}

Callers updated

All 7 import sites updated to the canonical source module: preflight.ts, agent-options.ts, config-writer.ts, acl-generator.ts, domain-acl.ts, policy-manifest.ts, and the corresponding test mocks.

Copilot AI changed the title [WIP] Refactor validateDomainOrPattern function to separate concerns refactor: decompose validateDomainOrPattern and split domain-patterns.ts by concern Jun 15, 2026
Copilot finished work on behalf of lpcox June 15, 2026 21:46
Copilot AI requested a review from lpcox June 15, 2026 21:46
@lpcox lpcox marked this pull request as ready for review June 15, 2026 21:47
Copilot AI review requested due to automatic review settings June 15, 2026 21:47
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 96.86% 96.93% 📈 +0.07%
Statements 96.73% 96.79% 📈 +0.06%
Functions 98.81% 98.81% ➡️ +0.00%
Branches 91.24% 91.29% 📈 +0.05%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/workdir-setup.ts 92.6% → 94.4% (+1.85%) 92.6% → 94.4% (+1.85%)
src/domain-patterns.ts 98.1% → 100.0% (+1.86%) 98.2% → 100.0% (+1.82%)
✨ New Files (2 files)
  • src/domain-matchers.ts: 98.1% lines
  • src/domain-validation.ts: 100.0% lines

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the domain allowlist/blocklist utilities by splitting the previous multi-purpose src/domain-patterns.ts into smaller modules, isolating the security-critical domain validation logic and separating matching/parsing concerns. This improves auditability of Squid-injection prevention checks while keeping matching utilities focused.

Changes:

  • Extracted validateDomainOrPattern and SQUID_DANGEROUS_CHARS into a dedicated src/domain-validation.ts module with helper sub-validators.
  • Moved domain list parsing and matching utilities (e.g. parseDomainList, isDomainMatchedByPattern, parseUrlPatterns) into src/domain-matchers.ts.
  • Updated multiple call sites and tests to import from the new canonical modules.
Show a summary per file
File Description
src/domain-validation.ts New security-focused module containing validateDomainOrPattern and Squid injection-prevention primitives.
src/domain-matchers.ts New module for domain list parsing, wildcard matching, and URL pattern parsing.
src/domain-patterns.ts Reduced to shared types and low-level wildcard/protocol parsing utilities.
src/domain-patterns.test.ts Updated tests to import validation vs matcher utilities from the new modules.
src/squid/domain-acl.ts Switched imports to domain-matchers / domain-validation after the split.
src/squid/acl-generator.ts Switched parseDomainList import to domain-matchers.
src/squid/policy-manifest.ts Switched parseDomainList import to domain-matchers.
src/config-writer.ts Switched parseUrlPatterns import to domain-matchers.
src/config-writer.test.ts Updated mocks/requireMock references to domain-matchers.
src/commands/preflight.ts Switched validateDomainOrPattern import to domain-validation.
src/commands/preflight.test.ts Updated mocks/imports to domain-validation.
src/commands/validators/agent-options.ts Switched SQUID_DANGEROUS_CHARS import to domain-validation.

Copilot's findings

Tip

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

  • Files reviewed: 12/12 changed files
  • Comments generated: 4

Comment thread src/domain-patterns.ts
Comment on lines 17 to 21
/**
* Protocol restriction for a domain
*/
type DomainProtocol = 'http' | 'https' | 'both';
export type DomainProtocol = 'http' | 'https' | 'both';

Comment thread src/domain-validation.ts
Comment on lines +1 to +7
/**
* Security validation for domain names and wildcard patterns
*
* This module is the Squid-injection prevention path for --allow-domains.
* All checks here are security-critical: they prevent malicious input from
* escaping into the generated Squid configuration.
*/
Comment thread src/domain-validation.ts Outdated
Comment on lines +65 to +83
/**
* Reject structurally invalid domain strings: double dots, lone dot, bare
* `*.` / `.*` (incomplete wildcards), and patterns with too many wildcard segments.
*/
function checkStructuralValidity(trimmed: string): void {
// Double dots are never valid in domain names
if (trimmed.includes('..')) {
throw new Error(`Invalid domain '${trimmed}': contains double dots`);
}

// A lone dot is not a valid domain
if (trimmed === '.') {
throw new Error('Invalid domain: cannot be just a dot');
}

// `*.` and `.*` are incomplete — they have no concrete label on one side
if (trimmed === '*.' || trimmed === '.*') {
throw new Error(`Invalid pattern '${trimmed}': incomplete domain`);
}
Comment thread src/domain-matchers.ts
Comment on lines +22 to +27
export interface ParsedDomainList {
/** Plain domains without wildcards */
plainDomains: PlainDomainEntry[];
/** Wildcard patterns with pre-compiled regex */
patterns: DomainPattern[];
}
@lpcox

lpcox commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

- Update jest.mock path in validate-options.test.ts from
  '../domain-patterns' to '../domain-validation' to match the
  module where SQUID_DANGEROUS_CHARS now lives
- Broaden domain-validation.ts module comment to include --allow-urls
  (SQUID_DANGEROUS_CHARS is used for both --allow-domains and --allow-urls)
- Remove unreachable *./ .* dead code in checkStructuralValidity;
  checkOverBroadPattern already rejects all patterns composed only of
  '*' and '.' before checkStructuralValidity is ever called
- Fix misleading 'pre-compiled regex' comment in domain-matchers.ts;
  DomainPattern.regex is a regex string compiled at match time

Copilot AI commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Done in commit fix: address review feedback on domain split refactor. Four items addressed:

  1. validate-options.test.ts — mock path updated from ../domain-patterns to ../domain-validation so it correctly intercepts the module where SQUID_DANGEROUS_CHARS now lives.
  2. domain-validation.ts header — broadened to mention both --allow-domains and --allow-urls.
  3. Dead code removed — the *. / .* check in checkStructuralValidity was unreachable (both are already caught by checkOverBroadPattern's all-stars-and-dots guard). Removed the branch and updated the JSDoc to reflect the five-check flow.
  4. domain-matchers.ts comment — "pre-compiled regex" changed to "compiled at match time via new RegExp(...)" to accurately describe DomainPattern.regex.

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

📡 Smoke OTel Tracing completed. All tracing scenarios validated. ✅

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Contribution Check failed. Please review the logs for details.

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK AOAI (Entra) completed. Copilot AOAI BYOK (Entra) mode operational. 🔓

Comment posted; smoke test failed, no labels added

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Build Test Suite completed successfully!

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🔌 Smoke Services — All services reachable! ✅

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation...

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK AOAI (api-key) completed. Copilot AOAI BYOK (api-key) mode operational. 🔓

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Security Guard failed. Please review the logs for details.

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🔑 Smoke Copilot PAT PAT auth validated. All systems operational. ✅

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Smoke Gemini completed. All facets verified. 💎

Smoke test completed with partial failures. File system and bash tests passed, but GitHub-related tests failed.

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded.

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Smoke Claude failed

@github-actions

Copy link
Copy Markdown
Contributor

🔥 Smoke Test Results — Auth mode: PAT (COPILOT_GITHUB_TOKEN)

Test Result
GitHub MCP connectivity
GitHub.com HTTP connectivity
File write/read smoke-test-copilot-pat-27579831040.txt confirmed

Overall: PASS

CC @lpcox @Copilot

🔑 PAT report filed by Smoke Copilot PAT

@github-actions

Copy link
Copy Markdown
Contributor

🔥 Smoke Test Results — PASS

PR: refactor: decompose validateDomainOrPattern and split domain-patterns.ts by concern
Author: @Copilot | Assignees: @lpcox @Copilot

Test Result
GitHub MCP connectivity
github.com HTTP (200)
File write/read

Overall: ✅ PASS

📰 BREAKING: Report filed by Smoke Copilot

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smoke Test: API Proxy OpenTelemetry Tracing

Scenario Result Notes
1. Module Loading otel.js loads cleanly; exports: startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown, isEnabled + private test hooks
2. Test Suite otel.test.js and otel-fanout.test.js exist with InMemorySpanExporter-based unit tests
3. Env Var Forwarding src/services/api-proxy-service-config.ts forwards GH_AW_OTLP_ENDPOINTS, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, GITHUB_AW_OTEL_TRACE_ID, GITHUB_AW_OTEL_PARENT_SPAN_ID, OTEL_SERVICE_NAME
4. Token Tracker Integration onUsage callback present in token-tracker-http.js (line 176 destructure, line 251 invocation)
5. OTEL Diagnostics No OTLP endpoint configured → graceful degradation to file fallback (/var/log/api-proxy/otel.jsonl); isEnabled() returns true as expected

All 5 scenarios passed. No unexpected failures detected.

📡 OTel tracing validated by Smoke OTel Tracing

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot BYOK (Direct) Mode — ✅ PASS

Tests:

  • ✅ GitHub MCP connectivity (verified PR data retrieval)
  • ✅ GitHub.com connectivity (HTTP 200)
  • ✅ File write/read (agent temp directory functional)
  • ✅ BYOK inference (direct api-proxy → api.githubcopilot.com)

Status: Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY via api-proxy sidecar)

CC: @lpcox

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions

Copy link
Copy Markdown
Contributor

@Copilot @lpcox
Smoke Test results:
• GitHub MCP Testing: ✅
• GitHub.com Connectivity: ✅
• File Write/Read Test: ❌
• BYOK Inference Test: ✅
Running in direct BYOK mode (AWF_AUTH_TYPE=github-oidc + AWF_AUTH_AZURE_* + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw) authenticated via Microsoft Entra
Overall status: FAIL

🪪 BYOK (AOAI Entra) report filed by Smoke Copilot BYOK AOAI (Entra)

@github-actions

Copy link
Copy Markdown
Contributor

refactor: decompose validateDomainOrPattern and split domain-patterns.ts by concern

GitHub MCP Testing: ✅
GitHub.com Connectivity: ✅
File Write/Read Test: ✅
BYOK Inference Test: ✅

Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw)

Overall status: PASS

cc @Copilot @lpcox

🔑 BYOK (AOAI api-key) report filed by Smoke Copilot BYOK AOAI (api-key)

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: GitHub Actions Services Connectivity

Check Result
Redis PING ❌ no response
PostgreSQL pg_isready ❌ no response
PostgreSQL SELECT 1 ❌ no response

Overall: FAILhost.docker.internal unreachable on ports 6379 and 5432.

🔌 Service connectivity validated by Smoke Services

@github-actions

Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ NO
Node.js v24.16.0 v22.22.3 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: ❌ Not all tests passed — Python minor patch and Node.js major versions differ between host and chroot environments.

Tested by Smoke Chroot

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ 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 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx all passed ✅ PASS
Node.js execa all passed ✅ PASS
Node.js p-limit all 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 #5063 ·

@github-actions

Copy link
Copy Markdown
Contributor

Smoke test in progress

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • localhost

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "localhost"

See Network Configuration for more information.

💎 Faceted by Smoke Gemini

@lpcox lpcox merged commit 777ee82 into main Jun 15, 2026
81 of 85 checks passed
@lpcox lpcox deleted the copilot/refactor-validate-domain-or-pattern branch June 15, 2026 22:32
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.

3 participants