Skip to content

fix: relax gh-aw handoff permissions after AWF exits - #9029

Merged
lpcox merged 13 commits into
mainfrom
copilot/awf-fix-cache-memory-validation
Sep 26, 2026
Merged

lpcox merged 13 commits into
mainfrom
copilot/awf-fix-cache-memory-validation

Conversation

Copilot AI commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Host-side steps that run after the AWF agent container exits (e.g. gh-aw's validateMemoryStep for tools.cache-memory) can fail with EACCES: permission denied when writing into /tmp/gh-aw (e.g. memory-validation/cache-default.ok). AWF remaps the agent's UID/GID to match the host user, but files created during the run can still end up with ownership/mode that a later host-side identity can't write into.

containers/agent/entrypoint.sh

  • Set umask 0002 for the user command so new files/dirs the agent creates under /tmp/gh-aw default to group-writable.
  • Added relax_gh_aw_shared_permissions(), run as root right after the agent command exits (both the normal exit path and the signal-driven cleanup path), which chmod -R g+w's the /tmp/gh-aw tree (/host/tmp/gh-aw in chroot mode, /tmp/gh-aw otherwise) without making it world-writable.
  • Note: this cleanup must live in run_agent_with_token_protection() rather than after the chroot ... exec capsh invocation in run_chroot_command, since exec capsh replaces the chroot shell's process image and any code placed after it there would never run.

Tests

  • tests/entrypoint-phase-functions.test.sh: added a fixture test asserting relax_gh_aw_shared_permissions() adds the group-write bit without widening to world-writable, and that it's wired into run_agent_with_token_protection().

Docs

  • docs/environment.md: documented the UID/GID remap vs. shared /tmp/gh-aw interaction, why it can still mismatch (e.g. AWF invoked as native root without sudo), and the mitigation, with guidance to prefer sudo awf when possible.

…n host-side steps

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix EACCES error for cache-memory validation marker write Fix EACCES in host-side gh-aw steps writing to /tmp/gh-aw after AWF exits Sep 26, 2026
Copilot AI requested a review from lpcox September 26, 2026 01:27
Comment thread containers/agent/entrypoint.sh Outdated
@lpcox
lpcox marked this pull request as ready for review September 26, 2026 03:01
Copilot AI balanced review requested due to automatic review settings September 26, 2026 03:01

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.

Copilot review overview

🟡 Changes recommended

Cleanup is skipped after failed commands, and permission widening can expose sensitive files beyond the intended handoff directory.

Review effort: Balanced
Findings: 1 High severity · 1 Medium severity · 1 Low severity

Open (3)
What changed in this PR

Adds post-agent permission repair for /tmp/gh-aw to prevent host-side EACCES failures.

Changes:

  • Adds group-permission cleanup and a relaxed umask.
  • Adds shell coverage for permission repair.
  • Documents UID/GID behavior and mitigation.
File Description
containers/​agent/​entrypoint.sh Adds shared-directory permission handling.
tests/​entrypoint-phase-functions.test.sh Tests the new helper and wiring.
docs/​environment.md Documents shared-path permissions.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread containers/agent/entrypoint.sh Outdated
Comment thread containers/agent/entrypoint.sh Outdated
Comment thread tests/entrypoint-phase-functions.test.sh Outdated
@lpcox

lpcox commented Sep 26, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

Copilot AI and others added 9 commits September 26, 2026 16:05
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>

Copilot AI commented Sep 26, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed the review feedback in dd6927f: narrowed permission repair to validated gh-aw handoff directories, skipped unsafe symlink/non-directory roots without recursive chmod, preserved cleanup on failed/signaled commands, and added targeted regression coverage.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Copilot review passed with no inline comments.

@copilot Add the ready-for-aw label to this PR to trigger agentic CI smoke tests.

@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Documentation Preview

Documentation has been built for this PR.

Download preview artifact

To view locally:

  1. Download the docs-preview-pr-9029 artifact from the workflow run
  2. Unzip and open index.html in your browser

Built from commit e886d19

Comment thread containers/agent/entrypoint.sh Outdated
@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

❌ Smoke Gemini reports failed. Facets need polishing...

Warning

Firewall blocked 1 domain

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

  • play.googleapis.com

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

network:
  allowed:
    - defaults
    - "play.googleapis.com"

See Network Configuration for more information.

💎 Faceted by Smoke Gemini

@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

✅ Smoke Claude passed

Warning

Firewall blocked 1 domain

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

  • api.anthropic.com

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

network:
  allowed:
    - defaults
    - "api.anthropic.com"

See Network Configuration for more information.

Generated by Smoke Claude for #9029

@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

✅ Security Guard completed successfully!

PR #9029 security review complete. Change: Added permission relaxation for gh-aw handoff directories in containers/agent/entrypoint.sh. The modification adds group-write permissions to specific whitelisted directories (/tmp/gh-aw/memory-validation) after agent exit. Security assessment: PASS. The implementation includes proper controls: symlink detection, directory validation, explicit allowlist (GH_AW_HOST_HANDOFF_DIRS), scope limitation to group-write only, and clear logging. This is a deliberate, scoped adjustment for post-agent inter-process coordination on multi-user runners, not a security regression.

Generated by Security Guard for #9029

@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

🛡️ Smoke Copilot Network Isolation confirmed the egress allowlist is enforced. ✅

Warning

Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • api.github.com
  • example.com

[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

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

network:
  allowed:
    - defaults
    - "api.github.com"
    - "example.com"

See Network Configuration for more information.

🛡️ Egress verdict from Smoke Copilot Network Isolation

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Claude Engine Validation

Check Status
API ✅ PASS
gh CLI ✅ PASS
File ✅ PASS

Overall result: PASS

Warning

Firewall blocked 1 domain

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

  • api.anthropic.com

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

network:
  allowed:
    - defaults
    - "api.anthropic.com"

See Network Configuration for more information.

Generated by Smoke Claude for #9029 · claude · haiku45 · 55.9 AIC · ⊞ 4.7K · ◷
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Cloud Hypervisor + Copilot

  1. list_pull_requests (github/gh-aw-firewall, merged, limit 1): PASS
  2. curl https://github.com: PASS (200)
  3. Write/read /tmp/gh-aw/agent/smoke-cloud-hypervisor-${GITHUB_RUN_ID}.txt: PASS
  4. curl (example.com/redacted) (should be blocked): PASS (000)

All checks passed ✅

Warning

Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • example.com
  • github.com

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

network:
  allowed:
    - defaults
    - "example.com"
    - "github.com"

See Network Configuration for more information.

Cloud Hypervisor + Copilot smoke test by Smoke Cloud Hypervisor
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

EGRESS_RESULT allow=pass deny=pass

✅ Allowed domain (github.com) reachable: allowed=200
✅ Non-allowed domain (example.com) blocked: OK: example.com was blocked

Overall: PASS

@lpcox

Warning

Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • api.github.com
  • example.com

[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

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

network:
  allowed:
    - defaults
    - "api.github.com"
    - "example.com"

See Network Configuration for more information.

🛡️ Egress verdict from Smoke Copilot Network Isolation
Add label ready-for-aw to run again

@github-actions github-actions Bot added the smoke-copilot-network-isolation Copilot network-isolation egress smoke test label Sep 26, 2026
@lpcox
lpcox deployed to aoai-model September 26, 2026 17:11 — with GitHub Actions Active
@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot Engine — @lpcox

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: GitHub Actions Services Connectivity

  • Redis PING: ✅ (PONG)
  • PostgreSQL pg_isready: ✅ (accepting connections)
  • PostgreSQL SELECT 1: ✅ (1)

Overall: PASS

🔌 Service connectivity validated by Smoke Services
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test Results: Copilot BYOK (Direct)

✅ GitHub MCP: PR connectivity verified
✅ HTTP GET github.com: HTTP 200
✅ File I/O: Write/read test passed
✅ BYOK Inference: Agent → api-proxy sidecar → api.githubcopilot.com

Status: PASS — Running in direct BYOK mode via COPILOT_PROVIDER_API_KEY

🔑 BYOK report filed by Smoke Copilot BYOK
Add label ready-for-aw to run again

@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 (run OK) ✅ PASS
.NET json-parse ✅ N/A (run OK) ✅ PASS
Go color ✅ ok ✅ PASS
Go env ✅ ok ✅ PASS
Go uuid ✅ ok ✅ 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

Note: Java (Maven) initially failed with Could not create local repository at /home/runner/.m2/repository -> Permission denied — a local filesystem permission issue on the runner (the default ~/.m2 dir is owned by root), unrelated to the AWF firewall/proxy. Retried successfully using -Dmaven.repo.local=/tmp/gh-aw/agent/m2-repo as an alternate writable local repo path; Maven proxy config (squid-proxy:3128) worked correctly for dependency resolution once the repo path was writable.

All 18 test projects across 8 language ecosystems built/installed and passed their test suites successfully.

Warning

Firewall blocked 8 domains

The following domains were blocked by the firewall during workflow execution:

  • api.nuget.org
  • bun.sh
  • dc.services.visualstudio.com
  • deno.land
  • dl.deno.land
  • github.com
  • releaseassets.githubusercontent.com
  • repo.maven.apache.org

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

network:
  allowed:
    - defaults
    - "api.nuget.org"
    - "bun.sh"
    - "dc.services.visualstudio.com"
    - "deno.land"
    - "dl.deno.land"
    - "github.com"
    - "releaseassets.githubusercontent.com"
    - "repo.maven.apache.org"

See Network Configuration for more information.

Generated by Build Test Suite for #9029 · copilot · auto · 44.1 AIC · ⊞ 11.8K · ◷
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.14 Python 3.12.14 ✅ YES
Node.js v24.21.0 v22.23.2 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: FAILED — Node.js version mismatch between host and chroot environments. Python and Go versions match correctly, but the chroot Node.js version (v22.23.2) differs from the host (v24.21.0).

Since not all tests passed, the smoke-chroot label was not added.

Tested by Smoke Chroot
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

📡 Smoke Test: API Proxy OTEL Tracing — Results

# Scenario Result
1 Module Loading (otel.js) ✅ Loaded successfully; isEnabled() → true; exports 15 functions/classes including startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown
2 Test Suite (otel*.test.js) ✅ 3 suites / 68 tests passed, 0 failed (module init, span attrs, token/budget attrs, OTLP export, fan-out, workload identity)
3 Env Var Forwarding ✅ env-passthrough.ts forwards GITHUB_AW_OTEL_TRACE_ID / GITHUB_AW_OTEL_PARENT_SPAN_ID to the agent; api-proxy-env-config.ts forwards GH_AW_OTLP_ENDPOINTS, OTEL_EXPORTER_OTLP_ENDPOINT, and the same trace context vars to the api-proxy sidecar
4 Token Tracker Integration ✅ token-tracker-http.js implements the onUsage callback (4 references) as the OTEL hook point
5 OTEL Diagnostics ⚪ No otel.jsonl span file found under api-proxy-logs/ for this run — expected graceful degradation since no OTLP endpoint was configured for the api-proxy sidecar in this smoke-test environment; token-usage.jsonl confirms 12 proxied requests were tracked normally with no errors

Overall: All scenarios pass or are expected-pending. No regression detected in the OTEL tracing integration.

Warning

Firewall blocked 1 domain

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

  • o205451.ingest.us.sentry.io

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

network:
  allowed:
    - defaults
    - "o205451.ingest.us.sentry.io"

See Network Configuration for more information.

📡 OTel tracing validated by Smoke OTel Tracing
Add label ready-for-aw to run again

@lpcox
lpcox merged commit 2c1e42b into main Sep 26, 2026
161 of 165 checks passed
@lpcox
lpcox deleted the copilot/awf-fix-cache-memory-validation branch September 26, 2026 17:21
Copilot AI added a commit that referenced this pull request Sep 26, 2026
lpcox added a commit that referenced this pull request Sep 26, 2026
* Initial plan

* docs: add B35 and D16 failure modes

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>

* docs: update runner doctor playbook for B35 D16

* docs: refresh B35 status when PR closes

* docs: mark B35 provisional pending PR merge

* docs: clarify B35 fix is not yet shipped

* docs: isolate B35 unmerged remediation details

* docs: clarify B35 status is a dated snapshot

* docs: track B35 follow-up in issue 9028

* docs: remove B35 status snapshot date

* docs: link B35 pending status to canonical entry

* docs: mark B35 proposal unverified

* docs: mark B35 fixed by merged #9029

* docs: add B35 patched-build verification probe

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
aoai-model — 52c4ad13 Deployed Sep 26, 2026 by lpcox via conclusion #1781
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 entrypoint: cache-memory validation marker write fails with EACCES due to UID remap on /tmp/gh-aw

4 participants