Skip to content

fix(api): resolve zip-namespace collisions when merging drive mounts - #5524

Merged
bekossy merged 7 commits into
release/v0.106.1from
api-fix/drive-download-agent-files
Jul 29, 2026
Merged

fix(api): resolve zip-namespace collisions when merging drive mounts#5524
bekossy merged 7 commits into
release/v0.106.1from
api-fix/drive-download-agent-files

Conversation

@ardaerzin

@ardaerzin ardaerzin commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Context

"Download all" in the Files drawer produced a zip missing the agent-files content (#5482).

The archive merges several mounts into ONE zip: the session cwd at the root, and the artifact's agent mount folded in under agent-files/. A zip carries no directory entries — a member a/b implies the directory a — so a member that is a FILE named a blocks that directory and everything under a/ is lost on extraction. An object store holds a and a/b side by side happily, so the merged namespace can contain a pair a zip cannot represent.

That is the shape of this bug. The runner symlinks the agent mount into the cwd as agent-files/; geesefs degrades that symlink to a plain object named agent-files in the cwd store ("geesefs silently degrades symlinks to empty files across remounts"). Archived as a file, it shadowed the agent-files/ directory the agent-mount source contributes, and the agent's files never landed.

Changes

  • build_archive_work_list runs the merged work list through a new _resolve_zip_namespace: a member shadowed by a directory is dropped, and a duplicate path keeps the first source. This fixes the bug by the invariant rather than by name — whatever the degraded object is called and whatever its size — and closes the whole collision class, which is reachable across sources for any pair of mounts.
  • The degraded link is also skipped up front, scoped to the cwd mount root — the one path the runner reserves (it unlinks whatever else sits there on every attach). A real agent-files file anywhere else, including at the agent mount's own root (presented as agent-files/agent-files), still ships. Without this, an empty agent mount would leave the marker in the zip as a phantom file the drive itself hides.

Before (zip entries): agent-files (degraded object), agent-files/plan.md, … → a file-vs-directory collision.
After: agent-files/plan.md, … — the shadowing member is dropped.

Tests

TestArchiveZipNamespace, against the in-memory fake store, models the real two-source shape (cwd mount + folded agent mount) rather than one synthetic mount:

  • the degraded link does not block the folded mount (the reported bug) — passes under either rule alone, so the fix survives a cwd mount the identity check doesn't recognize;
  • the link is still dropped when the agent mount is empty (only the cwd-root rule can catch it);
  • agent-files is not a reserved name outside the cwd root (docs/agent-files and the agent mount's own agent-files both ship);
  • a file shadowing a directory is dropped whatever its name (report vs report/q1.csv);
  • a duplicate zip path keeps the first source.

Each rule is independently covered: disabling either one fails only its own tests. Full api unit suite green (1475 passed). ruff format + ruff check clean.

What to QA

  • On a session with agent files, open the Files drawer and "Download all". Unzip: the agent-files/ folder and its files are present.
  • Regression: a normal cwd file archive still contains all files, and nested folders still extract.
  • A session whose agent folder is empty: the zip has no stray agent-files entry.

Fixes #5482

The drive folds the artifact's agent mount into the session drive under an
`agent-files/` symlink the runner creates in the cwd. geesefs degrades that
symlink to a 0-byte OBJECT named `agent-files` in the cwd store (runner
comment: "geesefs silently degrades symlinks to empty files across remounts").

"Download all" archives the cwd mount and the folded agent mount as separate
sources. The cwd `agent-files` object was archived as a FILE, colliding with
the `agent-files/` DIRECTORY the agent-mount source contributes. On extraction
the file blocks the directory, so the agent's files were dropped from the zip.

`build_archive_work_list` now skips the bare `agent-files` fold marker, the
same entry the frontend display already filters (`isAgentFilesFold`). The real
content ships from the agent-mount source under `agent-files/`. Added a unit
test.

Fixes #5482
@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jul 29, 2026 3:25pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f33292c9-cd9c-4676-a126-666c625c12a4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Archive generation now filters the degraded session agent-files marker and normalizes merged mount entries to remove file-directory conflicts and duplicate ZIP paths. Unit tests cover marker handling, root-only reservation, directory precedence, and deterministic duplicate retention.

Changes

Archive namespace handling

Layer / File(s) Summary
Normalize archive member paths
api/oss/src/core/mounts/service.py
Identifies the session cwd mount, excludes its degraded root agent-files marker, and resolves file-directory conflicts and duplicate ZIP paths across archive sources.
Validate namespace rules
api/oss/tests/pytest/unit/test_mounts_file_ops.py
Adds multi-mount test helpers and verifies marker filtering, preservation of user content, directory precedence, and first-entry retention for duplicate paths.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • Agenta-AI/agenta#5411: Also changes archive work-list generation in MountsService and relates to ZIP namespace handling.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: fixing archive zip namespace collisions when merging drive mounts.
Description check ✅ Passed The description is directly about the archive bug and the fix, with relevant context, implementation details, and tests.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch api-fix/drive-download-agent-files

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ardaerzin
ardaerzin marked this pull request as ready for review July 29, 2026 07:08
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. Backend labels Jul 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ffc47d5-da40-47d3-8b1c-0b958a0b9a5a

📥 Commits

Reviewing files that changed from the base of the PR and between a3e7fdf and 99d7026.

📒 Files selected for processing (2)
  • api/oss/src/core/mounts/service.py
  • api/oss/tests/pytest/unit/test_mounts_file_ops.py

Comment thread api/oss/src/core/mounts/service.py Outdated
Comment thread api/oss/tests/pytest/unit/test_mounts_file_ops.py Outdated
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-production-b9f1.up.railway.app/w
Project agenta-oss-pr-5524
Image tag pr-5524-9f9ce40
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-07-29T15:39:33.399Z

"Download all" merges several mounts into ONE zip (cwd at the root, the agent
mount under `agent-files/`). A zip carries no directory entries — `a/b` implies
the directory `a` — so a FILE member named `a` blocks it and everything under
`a/` is lost on extraction. An object store holds `a` and `a/b` side by side
happily, so the merged namespace can contain a pair a zip cannot represent.

That is the shape of #5482: geesefs degrades the runner's `agent-files` symlink
into a plain object in the cwd store, which archived as a file shadowed the
`agent-files/` directory the folded agent mount contributes.

`build_archive_work_list` now runs the merged list through
`_resolve_zip_namespace`: a member shadowed by a directory is dropped, and a
duplicate path keeps the first source. This fixes the reported bug by the
invariant rather than by name, whatever the degraded object's size, and guards
the whole collision class.

The degraded link is also skipped up front, scoped to the cwd mount root — the
one path the runner reserves (it unlinks whatever else sits there on attach), so
a real `agent-files` file anywhere else, including at the agent mount's own
root, still ships. Without that, an empty agent mount would leave the marker in
the zip as a phantom file the drive itself hides.

Fixes #5482
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:S This PR changes 10-29 lines, ignoring generated files. labels Jul 29, 2026
@ardaerzin ardaerzin changed the title fix(api): exclude degraded agent-files symlink marker from drive archive fix(api): resolve zip-namespace collisions when merging drive mounts Jul 29, 2026
@ardaerzin
ardaerzin requested a review from ashrafchowdury July 29, 2026 08:23
@bekossy
bekossy changed the base branch from main to release/v0.106.1 July 29, 2026 11:23
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 29, 2026
@bekossy
bekossy merged commit 0bbdd95 into release/v0.106.1 Jul 29, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backend lgtm This PR has been approved by a maintainer size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Download all in the file drawer does not include the simlink content of the agent-files

3 participants