Skip to content

Refactor config-writer directory provisioning into a shared ensureDirectory helper#3696

Merged
lpcox merged 3 commits into
mainfrom
copilot/duplicate-code-directory-creation
May 25, 2026
Merged

Refactor config-writer directory provisioning into a shared ensureDirectory helper#3696
lpcox merged 3 commits into
mainfrom
copilot/duplicate-code-directory-creation

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 25, 2026

src/config-writer.ts repeated security-sensitive directory creation/permission logic across multiple paths, with small behavioral differences (ownership, chmod fallback, existing-dir handling). This change consolidates that logic into one helper while preserving each call site’s semantics.

  • What changed

    • Added ensureDirectory(dirPath, options) to centralize:
      • conditional creation (existsSync + mkdirSync)
      • create-time behavior (onCreate)
      • existing-dir behavior (onExists)
      • post-ensure behavior (onAfterEnsure)
    • Replaced duplicated setup blocks for:
      • workDir
      • agent-logs
      • agent-session-state
      • squid-logs
      • api-proxy-logs
      • cli-proxy-logs
      • /tmp/gh-aw/mcp-logs
  • Behavior preserved (critical paths)

    • Host-user chown attempts for agent/session directories (with non-root-safe swallow behavior).
    • Squid logs chown to proxy UID/GID with chmod 0o777 fallback on chown failure.
    • MCP logs still force 0o777 when directory already exists.
  • Targeted test coverage updates

    • Added assertions for squid chown-failure fallback mode behavior.
    • Added assertions that pre-existing MCP logs directory permissions are corrected to 0o777.
ensureDirectory(squidLogsDir, {
  mode: 0o755,
  onCreate: () => {
    try {
      fs.chownSync(squidLogsDir, SQUID_PROXY_UID, SQUID_PROXY_GID);
    } catch {
      fs.chmodSync(squidLogsDir, 0o777);
    }
  },
});

Copilot AI changed the title [WIP] Refactor duplicate directory creation logic in config-writer Refactor config-writer directory provisioning into a shared ensureDirectory helper May 25, 2026
Copilot finished work on behalf of lpcox May 25, 2026 03:00
Copilot AI requested a review from lpcox May 25, 2026 03:00
@lpcox lpcox marked this pull request as ready for review May 25, 2026 03:02
Copilot AI review requested due to automatic review settings May 25, 2026 03:02
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 25, 2026

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 96.36% 96.42% 📈 +0.06%
Statements 96.21% 96.26% 📈 +0.05%
Functions 97.96% 97.99% 📈 +0.03%
Branches 90.35% 90.50% 📈 +0.15%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/config-writer.ts 83.0% → 85.5% (+2.43%) 83.0% → 85.5% (+2.43%)

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

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

This was referenced May 25, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results

GitHub MCP — PR #3689: fix(api-proxy): generalize deprecated header stripping for any provider/header
GitHub.com connectivity — HTTP 200
File operations — Write/read verified

Status: PASS

@Copilot @lpcox

📰 BREAKING: Report filed by Smoke Copilot

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

This PR refactors src/config-writer.ts to centralize directory provisioning/permission logic into a shared ensureDirectory helper, aiming to preserve existing security-sensitive behaviors (ownership changes, chmod fallbacks, and existing-directory handling) while reducing duplicated code.

Changes:

  • Introduces ensureDirectory(dirPath, options) with hooks for create/exist/after-ensure behavior.
  • Replaces repeated directory setup blocks for workDir and multiple log/state directories with ensureDirectory calls.
  • Extends unit tests to cover squid chown-failure fallback behavior and MCP logs permission correction.
Show a summary per file
File Description
src/config-writer.ts Adds ensureDirectory helper and updates directory creation/permission logic to use it.
src/config-writer.test.ts Adds/adjusts tests around directory setup behaviors (squid fallback + MCP log perms).

Copilot's findings

Tip

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

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

Comment thread src/config-writer.ts
Comment on lines +23 to +32
function ensureDirectory(dirPath: string, options: EnsureDirectoryOptions = {}): boolean {
const { mode, onCreate, onExists, onAfterEnsure } = options;
const created = !fs.existsSync(dirPath);

if (created) {
fs.mkdirSync(dirPath, mode === undefined ? { recursive: true } : { recursive: true, mode });
onCreate?.();
} else {
onExists?.();
}
Comment thread src/config-writer.test.ts Outdated
// Clean up tempDir and the chroot-home sibling directory that writeConfigs creates.
fs.rmSync(tempDir, { recursive: true, force: true });
fs.rmSync(`${tempDir}-chroot-home`, { recursive: true, force: true });
fs.rmSync('/tmp/gh-aw/mcp-logs', { recursive: true, force: true });
Comment thread src/config-writer.test.ts
Comment on lines +128 to +148
(fs.chownSync as unknown as jest.Mock).mockImplementation((targetPath: fs.PathLike) => {
if (String(targetPath) === proxyLogsDir) {
throw new Error('chown failed');
}
});

await writeConfigs({
workDir: tempDir,
sslBump: false,
allowedDomains: [],
agentCommand: 'echo test',
logLevel: 'info',
keepContainers: false,
buildLocal: false,
imageRegistry: 'ghcr.io/github/gh-aw-firewall',
imageTag: 'latest',
proxyLogsDir,
});

const squidLogsDirMode = fs.statSync(proxyLogsDir).mode & 0o777;
expect(squidLogsDirMode).toBe(0o777);
@github-actions

This comment has been minimized.

@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented May 25, 2026

@copilot address review feedback

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 25, 2026

@copilot address review feedback

Addressed in commit 3682f20.

Implemented the review feedback by:

  • hardening ensureDirectory to reject symlink/non-directory paths after mkdir ensure,
  • removing per-test cleanup of global /tmp/gh-aw/mcp-logs to avoid cross-suite flakiness,
  • preventing fs.chownSync mock implementation leakage by resetting it to a no-op in beforeEach.

Also added a targeted test for symlink rejection and re-ran lint/build/targeted tests plus CodeQL (no alerts).

Copilot finished work on behalf of lpcox May 25, 2026 03:24
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results

✅ GitHub API (2 PR entries)
✅ Playwright check (PASS)
✅ File verification

Result: PASS

💥 [THE END] — Illustrated by Smoke Claude

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results: BYOK Offline Mode

GitHub MCP: Retrieved PR #3704 ("Reduce Documentation Maintainer workflow prompt/tool overhead")
GitHub.com HTTP: File test failed (smoke-test.txt not found)
File Write/Read: smoke-test.txt missing
BYOK Inference: Successfully responding via api-proxy → api.githubcopilot.com

Mode: COPILOT_OFFLINE=true (BYOK) via api-proxy sidecar
Author: @Copilot | Assignees: @lpcox, @Copilot

Status: ⚠️ PARTIAL (MCP + inference working, file test data missing)

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Codex: FAIL
Merged PRs: api-proxy: skip stream_options.include_usage injection on OpenAI Responses routes; fix(api-proxy): generalize deprecated header stripping for any provider/header
GitHub MCP review: ❌ tool unavailable; titles reviewed via gh
Safe Inputs GH CLI: ❌ safeinputs-gh unavailable
Playwright: ✅ GitHub title verified
Tavily: ❌ no Tavily tools advertised
File/Bash: ✅ file created and read
Discussion: ❌ github-discussion-query unavailable
Build: ✅ npm ci && npm run build

Warning

Firewall blocked 1 domain

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

  • registry.npmjs.org

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

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex

@github-actions
Copy link
Copy Markdown
Contributor

Service Connectivity Test Results ❌

Status: FAIL — Services unreachable from AWF sandbox

  • ❌ Redis (host.docker.internal:6379): Connection timeout
  • ❌ PostgreSQL (host.docker.internal:5432): No response

Neither service container is reachable via host.docker.internal from inside the AWF agent container.

🔌 Service connectivity validated by Smoke Services

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Runtime Version Comparison

Tested runtime versions between host and chroot environments:

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

Result: Chroot environment has different versions for Python and Node.js. Only Go matches between host and chroot.

Full version strings

Host:

  • Python: Python 3.12.13
  • Node.js: v24.15.0
  • Go: go version go1.22.12 linux/amd64

Chroot:

  • Python: Python 3.12.3
  • Node.js: v22.22.3
  • Go: go1.22.12

Tested by Smoke Chroot

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

All ecosystems tested successfully! ✅

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

Test Details

  • Bun: Installed successfully, both projects compiled and tested
  • C++: CMake configuration and builds completed for fmt and json libraries
  • Deno: Downloaded dependencies and ran tests for oak and std
  • .NET: Restore, build, and run succeeded for both projects
  • Go: Module downloads and tests passed for color, env, and uuid
  • Java: Maven builds and tests passed (using custom repo location to avoid permission issues)
  • Node.js: npm install and tests passed for clsx, execa, and p-limit
  • Rust: Cargo build and test passed for fd and zoxide

Generated by Build Test Suite for issue #3696 · ● 12.2M ·

@github-actions
Copy link
Copy Markdown
Contributor

Gemini Smoke Test: FAIL (Connectivity 400, MCP missing)

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 7776be5 into main May 25, 2026
63 of 68 checks passed
@lpcox lpcox deleted the copilot/duplicate-code-directory-creation branch May 25, 2026 03:42
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.

[Duplicate Code] Directory creation with permission setup repeated 8+ times

3 participants