Skip to content

feat: add volume mount for ~/.copilot/session-state to persist events.jsonl#1469

Merged
lpcox merged 3 commits intomainfrom
copilot/add-volume-mount-for-session-state
Mar 30, 2026
Merged

feat: add volume mount for ~/.copilot/session-state to persist events.jsonl#1469
lpcox merged 3 commits intomainfrom
copilot/add-volume-mount-for-session-state

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 26, 2026

Copilot CLI writes events.jsonl to ~/.copilot/session-state/ inside the container, but AWF had no volume mount for that path — the file was discarded when the container stopped, leaving agent_outputs artifacts without the structured conversation JSONL needed for dashboards and debugging.

Changes

  • Volume mount (generateDockerCompose): adds workDir/agent-session-state → ~/.copilot/session-state alongside the existing agent-logs mount
  • Pre-run setup (writeConfigs): creates workDir/agent-session-state/ before container start
  • Cleanup preservation: moves non-empty agent-session-state/ to /tmp/awf-agent-session-state-<timestamp> after the run, matching the agent-logs pattern
  • Docs (docs/usage.md): documents the new preserved path and updates the "How it works" volume mapping list

After a Copilot CLI run, events.jsonl is available at:

/tmp/awf-agent-session-state-<timestamp>/events.jsonl

⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

Copilot AI changed the title [WIP] Add volume mount for ~/.copilot/session-state to access events.jsonl feat: add volume mount for ~/.copilot/session-state to persist events.jsonl Mar 26, 2026
Copilot AI requested a review from lpcox March 26, 2026 22:02
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 29, 2026

Documentation Preview

Documentation build failed for this PR. View logs.

Built from commit e65d54b

@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 82.72% 82.75% 📈 +0.03%
Statements 82.38% 82.42% 📈 +0.04%
Functions 81.50% 81.50% ➡️ +0.00%
Branches 76.19% 76.16% 📉 -0.03%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 86.0% → 86.1% (+0.08%) 85.5% → 85.6% (+0.08%)

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

@github-actions

This comment has been minimized.

* Initial plan

* fix: update handlebars and brace-expansion to fix npm audit vulnerabilities

Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/41a2d615-b628-46d7-bf1f-2e21f94f7f5b

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
@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 82.72% 82.77% 📈 +0.05%
Statements 82.38% 82.43% 📈 +0.05%
Functions 81.50% 81.22% 📉 -0.28%
Branches 76.19% 76.00% 📉 -0.19%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/cli.ts 61.2% → 61.1% (-0.10%) 61.6% → 61.5% (-0.10%)
src/docker-manager.ts 86.0% → 86.2% (+0.23%) 85.5% → 85.7% (+0.24%)

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

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — PASS

💥 [THE END] — Illustrated by Smoke Claude for issue #1469

@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — PASS

Test Result
GitHub MCP (last 2 merged PRs) #1498 [WIP] Fix failing GitHub Actions workflow Audit Main Package, #1495 fix: use neutral policy language in SAFE_XPIA_CONTENT...
Playwright (github.com title) ✅ Title contains "GitHub"
File write /tmp/gh-aw/agent/smoke-test-copilot-23725710545.txt created
Bash verify ✅ File read back successfully

Overall: PASS@lpcox

📰 BREAKING: Report filed by Smoke Copilot for issue #1469

@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.14.0 v20.20.1 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: Not all tests passed. Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot for issue #1469

@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 #1469 ·

@github-actions
Copy link
Copy Markdown
Contributor

Smoke test (run 23725710566)
PR titles: "[WIP] Fix failing GitHub Actions workflow Audit Main Package"; "fix: debug logging for GITHUB_PATH merge + document setup-* tool availability in chroot"

  1. GitHub MCP review last 2 merged PRs: ✅
  2. safeinputs-gh PR query: ❌ (tool unavailable in this runtime)
  3. Playwright github.com title contains "GitHub": ✅
  4. Tavily search: ❌ (Tavily MCP unavailable)
  5. File write /tmp/gh-aw/agent/smoke-test-codex-23725710566.txt: ✅
  6. Bash cat verify file: ✅
  7. Discussion query + mystical comment: ❌ (discussion-query tool unavailable)
  8. npm ci && npm run build: ✅
    Overall: FAIL

🔮 The oracle has spoken through Smoke Codex

@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented Mar 30, 2026

@copilot are there any potential security issues with persisting events.jsonl? for example, could a prompt-injected agent modify the content events.jsonl to exfiltrate sensitive information?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 30, 2026

@copilot are there any potential security issues with persisting events.jsonl? for example, could a prompt-injected agent modify the content events.jsonl to exfiltrate sensitive inf...

The short answer is: this mount doesn't create a new exfiltration path, but here's the full analysis:

Network exfiltration via events.jsonl is not possible — writing to a file inside the container stays local. All outbound network traffic is still gated by the Squid proxy and the domain allowlist, regardless of what gets written to ~/.copilot/session-state/. An agent would need to send the file over an allowed domain to exfiltrate, which is the same constraint it faces for any other data.

Content tampering is a valid (but pre-existing) concern — the rw mount does mean a prompt-injected agent could write arbitrary content to ~/.copilot/session-state/, and that content would be preserved on the host at /tmp/awf-agent-session-state-<timestamp>/. However:

  1. This is identical to the existing agent-logs mount (workDir/agent-logs → ~/.copilot/logs:rw), which has been rw since before this PR. This PR doesn't introduce a new security surface relative to what already exists.
  2. The workspace dir (workspaceDir:workspaceDir:rw) is also writable by the agent — a prompt-injected agent already has full write access to the workspace.
  3. Downstream consumers of these artifacts (CI dashboards, triage tools) should already treat agent-produced content as untrusted, since the agent could equally tamper with the workspace.

The practical mitigations already in place: the file never leaves the machine without an explicit network request through an allowed domain, and the host path is under /tmp (not the workspace), so a tampered file can't directly corrupt source code or CI artifacts unless a workflow step explicitly reads and processes it.

If there's a concern about a specific downstream consumer being vulnerable to log injection from this file, that's worth hardening at the consumer — but it's outside the scope of this mount.

@lpcox lpcox marked this pull request as ready for review March 30, 2026 03:08
@lpcox lpcox requested a review from Mossaka as a code owner March 30, 2026 03:09
Copilot AI review requested due to automatic review settings March 30, 2026 03:09
@lpcox lpcox merged commit ddfbc43 into main Mar 30, 2026
60 of 62 checks passed
@lpcox lpcox deleted the copilot/add-volume-mount-for-session-state branch March 30, 2026 03:09
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

Adds persistence for Copilot CLI’s structured session-state (events.jsonl) by introducing a new host-mounted directory and documenting where it’s preserved after runs, so dashboards/debugging can rely on the JSONL artifact.

Changes:

  • Add a new Docker volume mount for ~/.copilot/session-state backed by ${workDir}/agent-session-state.
  • Create ${workDir}/agent-session-state during pre-run config setup and preserve it to a timestamped /tmp directory on cleanup.
  • Document the new preserved session-state location in docs/usage.md.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/docker-manager.ts Adds the session-state volume mount, creates the session-state workDir, and preserves it on cleanup.
package-lock.json Updates transitive dependency versions (brace-expansion, handlebars).
docs/usage.md Documents preserved session-state output and updates volume mapping explanation.
Comments suppressed due to low confidence (2)

src/docker-manager.ts:1558

  • agent-session-state is created without setting ownership/permissions. When AWF is run via sudo, this directory will likely be root-owned; but in chroot mode the command is executed as the mapped host user (non-root), so Copilot may be unable to create events.jsonl in this bind mount. Set ownership to the host UID/GID (same as the chroot-home setup) and choose an explicit mode that matches your intended readability.
  // Create agent session-state directory for persistence (events.jsonl written by Copilot CLI)
  const agentSessionStateDir = path.join(config.workDir, 'agent-session-state');
  if (!fs.existsSync(agentSessionStateDir)) {
    fs.mkdirSync(agentSessionStateDir, { recursive: true });
  }
  logger.debug(`Agent session-state directory created at: ${agentSessionStateDir}`);

src/docker-manager.ts:2126

  • Preservation uses fs.renameSync to move agent-session-state into os.tmpdir(). rename fails with EXDEV when workDir and /tmp are on different filesystems (e.g., custom workDir on another mount), which would silently skip preservation. Add a copy+remove fallback (or handle EXDEV explicitly) so the feature works reliably across filesystems.
      // Preserve agent session-state before cleanup (contains events.jsonl from Copilot CLI)
      const agentSessionStateDir = path.join(workDir, 'agent-session-state');
      const agentSessionStateDestination = path.join(os.tmpdir(), `awf-agent-session-state-${timestamp}`);
      if (fs.existsSync(agentSessionStateDir) && fs.readdirSync(agentSessionStateDir).length > 0) {
        try {
          fs.renameSync(agentSessionStateDir, agentSessionStateDestination);
          logger.info(`Agent session state preserved at: ${agentSessionStateDestination}`);
        } catch (error) {
          logger.debug('Could not preserve agent session state:', error);
        }
      }

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

// Mount agent logs directory to workDir for persistence
`${config.workDir}/agent-logs:${effectiveHome}/.copilot/logs:rw`,
// Mount agent session-state directory to workDir for persistence (events.jsonl)
`${config.workDir}/agent-session-state:${effectiveHome}/.copilot/session-state:rw`,
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The session-state volume is mounted to ${effectiveHome}/.copilot/session-state, but when AWF runs in chroot mode the user command writes to paths under /host (see entrypoint.sh chroot execution). As a result, ~/.copilot/session-state inside the chroot won’t see this mount and events.jsonl may still be discarded. Consider mounting the same host dir to /host${effectiveHome}/.copilot/session-state (and/or ensuring Copilot is configured to write to the non-chroot path).

This issue also appears in the following locations of the same file:

  • line 1553
  • line 2116
Suggested change
`${config.workDir}/agent-session-state:${effectiveHome}/.copilot/session-state:rw`,
`${config.workDir}/agent-session-state:${effectiveHome}/.copilot/session-state:rw`,
// When running in chroot mode, the user's home is accessed under /host,
// so also mount the same session-state directory to the chrooted home path.
`${config.workDir}/agent-session-state:/host${effectiveHome}/.copilot/session-state:rw`,

Copilot uses AI. Check for mistakes.
Comment on lines +1553 to +1558
// Create agent session-state directory for persistence (events.jsonl written by Copilot CLI)
const agentSessionStateDir = path.join(config.workDir, 'agent-session-state');
if (!fs.existsSync(agentSessionStateDir)) {
fs.mkdirSync(agentSessionStateDir, { recursive: true });
}
logger.debug(`Agent session-state directory created at: ${agentSessionStateDir}`);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New behavior (creating agent-session-state, preserving it on cleanup, and the new volume mount) isn’t covered by tests. src/docker-manager.test.ts already has coverage for the analogous agent-logs preservation; please add similar assertions for session-state so regressions are caught.

Copilot uses AI. Check for mistakes.
Comment on lines 867 to +876
**How it works:**
- GitHub Copilot CLI writes to `~/.copilot/logs/`, Squid writes to `/var/log/squid/`
- Volume mounts map these to `${workDir}/agent-logs/` and `${workDir}/squid-logs/`
- Before cleanup, logs are automatically moved to `/tmp/awf-agent-logs-<timestamp>/` and `/tmp/squid-logs-<timestamp>/` (if they exist)
- GitHub Copilot CLI writes to `~/.copilot/logs/` and `~/.copilot/session-state/`; Squid writes to `/var/log/squid/`
- Volume mounts map container paths to:
- `${workDir}/agent-logs/` → `~/.copilot/logs/`
- `${workDir}/agent-session-state/` → `~/.copilot/session-state/`
- `${workDir}/squid-logs/` → `/var/log/squid/`
- Before cleanup, non-empty directories are automatically moved to timestamped `/tmp` paths:
- `/tmp/awf-agent-logs-<timestamp>/`
- `/tmp/awf-agent-session-state-<timestamp>/`
- `/tmp/squid-logs-<timestamp>/`
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The “How it works” section describes mounts for ~/.copilot/session-state, but in AWF chroot mode the agent command runs inside /host (entrypoint.sh), so the effective path being written is under /host$HOME/.... Once the mount points are corrected, please update this section to reflect the chroot behavior (or clarify that the mount targets both chroot and non-chroot paths).

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

Smoke Test Results — PASS

💥 [THE END] — Illustrated by Smoke Claude

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.

agent-container: add volume mount for ~/.copilot/session-state so events.jsonl is accessible for artifact upload

3 participants