Skip to content

Handle non-standard runner HOME and missing ~/.copilot in agent mount setup#2114

Merged
lpcox merged 5 commits intomainfrom
copilot/awf-verify-self-hosted-runner-compatibility
Apr 20, 2026
Merged

Handle non-standard runner HOME and missing ~/.copilot in agent mount setup#2114
lpcox merged 5 commits intomainfrom
copilot/awf-verify-self-hosted-runner-compatibility

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 20, 2026

AWF already derives home paths from runtime environment, but agent volume setup still assumed ~/.copilot was always present. On self-hosted runners with non-/home/runner homes (or fresh homes), this could cause bind-mount failures during startup.

  • Runtime mount hardening (src/docker-manager.ts)

    • Before adding the host ~/.copilot bind mount, AWF now checks whether the directory exists.
    • If missing, AWF attempts to create it.
    • If creation fails, AWF logs a warning and skips only that host .copilot bind mount instead of failing mount composition.
  • Targeted regression coverage (src/docker-manager.test.ts)

    • Added a focused test for non-standard HOME where .copilot does not exist.
    • Verifies AWF creates the directory and emits the expected mount path using the runtime-derived home.
  • Environment docs update (docs/environment.md)

    • Added explicit note that AWF supports self-hosted runners with non-standard home paths by deriving home from $HOME (sudo-aware), not hardcoding /home/runner.
const copilotHomeDir = path.join(effectiveHome, '.copilot');
if (!fs.existsSync(copilotHomeDir)) {
  fs.mkdirSync(copilotHomeDir, { recursive: true });
}
if (fs.existsSync(copilotHomeDir)) {
  agentVolumes.push(`${copilotHomeDir}:/host${effectiveHome}/.copilot:rw`);
}

Copilot AI changed the title [WIP] Fix self-hosted runner compatibility with non-standard HOME directory Handle non-standard runner HOME and missing ~/.copilot in agent mount setup Apr 20, 2026
Copilot AI requested a review from lpcox April 20, 2026 13:55
@lpcox lpcox marked this pull request as ready for review April 20, 2026 14:34
@lpcox lpcox requested a review from Mossaka as a code owner April 20, 2026 14:34
Copilot AI review requested due to automatic review settings April 20, 2026 14:34
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

Documentation Preview

Documentation build failed for this PR. View logs.

Built from commit 8708e3f

@github-actions
Copy link
Copy Markdown
Contributor

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

Metric Base PR Delta
Lines 84.31% 84.39% 📈 +0.08%
Statements 83.55% 83.63% 📈 +0.08%
Functions 87.46% 87.46% ➡️ +0.00%
Branches 74.72% 74.70% 📉 -0.02%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 86.8% → 87.1% (+0.29%) 86.4% → 86.7% (+0.29%)

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

@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.

@github-actions github-actions Bot mentioned this pull request Apr 20, 2026
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

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

Hardens AWF’s agent bind-mount setup to better support self-hosted runners whose $HOME differs from /home/runner and where ~/.copilot may be missing, avoiding startup failures due to missing host mount paths.

Changes:

  • Adds a ~/.copilot existence check + creation attempt before adding the host bind mount, warning and skipping that single mount on failure.
  • Adds a regression unit test for a non-standard HOME with a missing .copilot directory.
  • Updates environment documentation to clarify $HOME-derived (sudo-aware) home path handling for self-hosted runners.
Show a summary per file
File Description
src/docker-manager.ts Creates ~/.copilot if missing before adding the host bind mount; warns and skips the mount if creation fails.
src/docker-manager.test.ts Adds a test ensuring .copilot is created and mounted when HOME is non-standard and initially missing .copilot.
docs/environment.md Documents that AWF derives the effective home from $HOME (sudo-aware), supporting non-standard self-hosted runner homes.

Copilot's findings

Tip

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

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

Comment thread src/docker-manager.ts Outdated
if (!fs.existsSync(copilotHomeDir)) {
try {
fs.mkdirSync(copilotHomeDir, { recursive: true });
logger.debug(`Created missing Copilot directory for bind mount: ${copilotHomeDir}`);
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

generateDockerCompose() is creating the host ~/.copilot directory, but it doesn’t set ownership/permissions like writeConfigs() does for chroot home subdirectories (it chowns to the host UID/GID). If this runs under sudo and ~/.copilot is created as root:root, the agent user may not be able to write Copilot CLI state. Consider either (a) chowning the created directory to getSafeHostUid()/getSafeHostGid() here, or (b) moving all host-home directory creation into writeConfigs() and keeping generateDockerCompose() side-effect-free for host paths.

Suggested change
logger.debug(`Created missing Copilot directory for bind mount: ${copilotHomeDir}`);
fs.chownSync(copilotHomeDir, getSafeHostUid(), getSafeHostGid());
logger.debug(`Created missing Copilot directory for bind mount and set ownership: ${copilotHomeDir}`);

Copilot uses AI. Check for mistakes.
Comment thread src/docker-manager.ts Outdated
Comment on lines +881 to +897
it('should create missing .copilot directory and mount it when using non-standard HOME path', () => {
const fakeHome = fs.mkdtempSync(path.join(os.tmpdir(), 'awf-home-'));
const originalHome = process.env.HOME;
const originalSudoUser = process.env.SUDO_USER;
delete process.env.SUDO_USER;
process.env.HOME = fakeHome;

try {
const copilotDir = path.join(fakeHome, '.copilot');
expect(fs.existsSync(copilotDir)).toBe(false);

const result = generateDockerCompose(mockConfig, mockNetworkConfig);
const volumes = result.services.agent.volumes as string[];

expect(fs.existsSync(copilotDir)).toBe(true);
expect(volumes).toContain(`${fakeHome}/.copilot:/host${fakeHome}/.copilot:rw`);
} finally {
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

The new test covers the happy path where .copilot can be created, but it doesn’t cover the behavior added in the catch branch (mkdir failure → warn + skip mount). Consider adding a test that mocks fs.mkdirSync (or uses a read-only temp dir) to assert the warning is emitted and the .copilot bind mount is omitted, since that’s the main behavioral change for hardening startup.

Copilot uses AI. Check for mistakes.
@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented Apr 20, 2026

@copilot update the PR with this review feedback #2114 (review)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

🔥 Smoke Test Results — PASS

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

PR: Handle non-standard runner HOME and missing ~/.copilot in agent mount setup
Author: @app/copilot-swe-agent | Assignees: @lpcox, @Copilot

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results (run #24673612618)

✅ GitHub MCP: Last 2 merged PRs retrieved
✅ Playwright: github.com page title verified
✅ File Writing: Test file created at /tmp/gh-aw/agent/smoke-test-claude-24673612618.txt
✅ Bash Tool: File verified with cat command

Status: PASS

💥 [THE END] — Illustrated by Smoke Claude

@github-actions
Copy link
Copy Markdown
Contributor

🔥 Smoke Test: Copilot BYOK (Offline) Mode

Test Result
GitHub MCP (merged PR: #2113)
GitHub.com connectivity (HTTP 200)
File write/read (smoke-test-copilot-byok-24673612677.txt)
BYOK inference (agent → api-proxy → api.githubcopilot.com)

Running in BYOK offline mode (COPILOT_OFFLINE=true) via api-proxy → api.githubcopilot.com

Overall: PASS@lpcox (assignee: @lpcox, @Copilot)

PR: "Handle non-standard runner HOME and missing ~/.copilot in agent mount setup"

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test: GitHub Actions Services Connectivity ✅

All checks passed:

Service Check Result
Redis host.docker.internal:6379 PING PONG
PostgreSQL host.docker.internal:5432 pg_isready ✅ accepting connections
PostgreSQL smoketest db SELECT 1 ✅ returned 1

Note: redis-cli was not installed and could not be installed (no apt access in sandbox), so Redis was tested via a raw Python socket sending the RESP PING command — response was +PONG.

🔌 Service connectivity validated by Smoke Services

@github-actions
Copy link
Copy Markdown
Contributor

Chroot Runtime Version Comparison

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: FAILED — Python and Node.js 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 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 #2114 · ● 668.9K ·

@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented Apr 20, 2026

@copilot rebase to main and recompile

1 similar comment
@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented Apr 20, 2026

@copilot rebase to main and recompile

@lpcox lpcox merged commit aac083b into main Apr 20, 2026
59 of 66 checks passed
@lpcox lpcox deleted the copilot/awf-verify-self-hosted-runner-compatibility branch April 20, 2026 15:36
Copilot stopped work on behalf of lpcox due to an error April 20, 2026 15:37
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.

[awf] Agent container: verify self-hosted runner compatibility when HOME != /home/runner

3 participants