Skip to content

[Duplicate Code] Duplicated blocked-domain reporting logic in container-lifecycle.ts #2553

@github-actions

Description

@github-actions

Duplicate Code Opportunity

Summary

  • Pattern: Identical domain-blocked analysis loop (classify domain vs port vs other, emit diagnostic messages, suggest --allow-domains fix) copy-pasted between two error-handling paths with only the log level differing (logger.error vs logger.warn).
  • Locations: src/container-lifecycle.ts lines 524–564 (startup error path) and 644–680 (post-run warning path)
  • Impact: ~37 duplicated lines; any fix to the diagnostic format or allowlist-check logic must be made in two places

Evidence

Copy 1 — handleContainerStartError() (lines 524–564), uses logger.error:

const missingDomains: string[] = [];
const portIssues: BlockedTarget[] = [];

blockedTargets.forEach(blocked => {
  const isAllowed = allowedDomains.some(allowed =>
    blocked.domain === allowed || blocked.domain.endsWith('.' + allowed)
  );

  if (!isAllowed) {
    logger.error(`  - Blocked: \$\{blocked.target} (domain not in allowlist)`);
    missingDomains.push(blocked.domain);
  } else if (blocked.port && blocked.port !== '80' && blocked.port !== '443') {
    logger.error(`  - Blocked: \$\{blocked.target} (port \$\{blocked.port} not allowed, only 80 and 443 are permitted)`);
    portIssues.push(blocked);
  } else {
    logger.error(`  - Blocked: \$\{blocked.target}`);
  }
});

logger.error('Allowed domains:');
allowedDomains.forEach(domain => { logger.error(`  - Allowed: \$\{domain}`); });

if (missingDomains.length > 0) {
  logger.error(`To fix domain issues: --allow-domains "\$\{[...allowedDomains, ...missingDomains].join(',')}"`);
}
if (portIssues.length > 0) {
  logger.error('To fix port issues: Use standard ports 80 (HTTP) or 443 (HTTPS)');
}

Copy 2 — runAgentCommand() (lines 644–680), uses logger.warn:

Structurally identical; only differences are logger.warn instead of logger.error and the absence of the final throw.

Suggested Refactoring

Extract a reportBlockedDomains helper in src/container-lifecycle.ts (or a new src/blocked-domain-reporter.ts):

interface BlockedDomainReport {
  missingDomains: string[];
  portIssues: BlockedTarget[];
}

function reportBlockedDomains(
  blockedTargets: BlockedTarget[],
  allowedDomains: string[],
  log: (msg: string) => void,   // pass logger.error or logger.warn
): BlockedDomainReport {
  const missingDomains: string[] = [];
  const portIssues: BlockedTarget[] = [];

  blockedTargets.forEach(blocked => {
    const isAllowed = allowedDomains.some(
      a => blocked.domain === a || blocked.domain.endsWith('.' + a)
    );
    if (!isAllowed) {
      log(`  - Blocked: \$\{blocked.target} (domain not in allowlist)`);
      missingDomains.push(blocked.domain);
    } else if (blocked.port && blocked.port !== '80' && blocked.port !== '443') {
      log(`  - Blocked: \$\{blocked.target} (port \$\{blocked.port} not allowed, only 80 and 443 are permitted)`);
      portIssues.push(blocked);
    } else {
      log(`  - Blocked: \$\{blocked.target}`);
    }
  });

  log('Allowed domains:');
  allowedDomains.forEach(d => log(`  - Allowed: \$\{d}`));
  if (missingDomains.length > 0)
    log(`To fix domain issues: --allow-domains "\$\{[...allowedDomains, ...missingDomains].join(',')}"`);
  if (portIssues.length > 0)
    log('To fix port issues: Use standard ports 80 (HTTP) or 443 (HTTPS)');

  return { missingDomains, portIssues };
}

Both call sites then become a single reportBlockedDomains(blockedTargets, allowedDomains, logger.error) / logger.warn call.

Affected Files

  • src/container-lifecycle.ts — lines 524–564 and 644–680

Effort Estimate

Low


Detected by Duplicate Code Detector workflow. Run date: 2026-05-05

Generated by Duplicate Code Detector · ● 594.5K ·

  • expires on Jun 4, 2026, 1:04 PM UTC

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions