paperclip/packages/plugins/sandbox-providers/kubernetes/src
Devin Foley c57c0f7498
fix(sandbox-providers): accept bsdtar listings in the syncOut tarball confinement check (#11289)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Sandbox providers (Daytona, Kubernetes) sync run results back to the
host with a sandbox-authored tarball
> - Before extraction, a confinement check parses the host `tar -tvf`
listing and fails closed on unparseable lines
> - The parser only understands the GNU tar listing dialect; macOS ships
bsdtar, whose ls-style listing never matches
> - Every sandbox syncOut on a macOS host therefore aborts with
"refusing tarball with an unparseable entry listing", and the run fails
at copy-back
> - This pull request teaches the parser both dialects while keeping the
fail-closed and traversal guarantees
> - The benefit is that Daytona and Kubernetes sandbox runs work on
macOS hosts, with no behavior change on Linux

## Linked Issues or Issue Description

No existing issue. Bug description:

**What happened?**

On a macOS host, every Daytona sandbox run fails at syncOut. The adapter
reports: `Daytona syncOut refusing tarball with an unparseable entry
listing: -rw-r--r-- 0 daytona daytona 7560 Aug 11 21:43 AGENTS.md`. The
Kubernetes provider has the same parser and fails the same way.

**Expected behavior**

The confinement check accepts a well-formed listing from the host tar,
whichever dialect the host tar emits. It still rejects members that
escape the extraction directory, and it still fails closed on lines it
cannot parse.

**Steps to reproduce**

1. Run Paperclip on macOS (system tar is bsdtar).
2. Configure an agent with the Daytona sandbox provider.
3. Trigger any run that syncs files back from the sandbox.
4. The run fails at syncOut with the unparseable-entry-listing error,
because bsdtar prints `<perms> <links> <user> <group> <size> <Mon> <day>
<time|year> <name>` while the parser expects the GNU `<perms>
<owner>/<group> <size> <date> <time> <name>` shape.

**Operating system**

macOS (bsdtar 3.5.3). Linux hosts with GNU tar are unaffected.

## What Changed

- Extracted the listing-line parse in both providers' `file-sync.ts`
into an exported `parseTarVerboseListingLine` that accepts the
GNU/busybox dialect and the bsdtar (libarchive) dialect.
- The GNU shape now requires the slash-joined `<owner>/<group>` field.
This keeps the two shapes mutually exclusive. Without it, a bsdtar line
with numeric uid/gid satisfies the loose GNU pattern shifted by one
field, which would hide a leading `../` from the traversal check.
- Unparseable lines still fail closed. This includes device-node
entries, whose size column is `major,minor` in both dialects.
- Made the path-traversal fixture in the Daytona suite portable: GNU
spells member renaming `--transform`, bsdtar spells it `-s`.
- Added a Daytona test that refuses a sandbox-authored tarball carrying
a symlink whose target escapes the extraction dir.
- Added parser unit tests for both dialects (file, dir, symlink,
hardlink, numeric owner, year-form dates, fail-closed lines) to both
providers' suites.

## Verification

- `pnpm test` in `packages/plugins/sandbox-providers/daytona`: 136/136
pass on a macOS host. On unpatched `master` the round-trip test fails
there with the unparseable-entry-listing error.
- `pnpm test` in `packages/plugins/sandbox-providers/kubernetes`: the
new parser tests pass; no new failures against the `master` baseline on
the same host.
- `pnpm typecheck` passes in both packages.
- CI runs the same suites on Linux/GNU tar and proves the GNU path is
unchanged.

## Risks

- Low risk. The GNU pattern is one token stricter (`<owner>/<group>`
must contain `/`). GNU and busybox tar always print the slash-joined
owner field, so accepted GNU listings are unchanged.
- The bsdtar branch only widens acceptance on hosts that were failing
100% of syncOuts before, so no working deployment changes behavior.
- The check still fails closed on anything neither pattern matches.

## Model Used

Claude Fable 5 (`claude-fable-5`, Claude Code CLI, extended thinking +
tool use).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-12 11:24:11 -07:00
..
adapter-defaults.ts
adapter-registry.ts
cilium-network-policy.ts
file-sync.ts
image-allowlist.ts
index.ts
job-orchestrator.ts
kube-client.ts
lease-lifecycle.ts
manifest.ts
network-policy.ts
plugin.ts
pod-exec.ts
pod-spec-builder.ts
sandbox-cr-builder.ts
sandbox-cr-orchestrator.ts
sandbox-orchestrator.ts
scoped-network-egress.ts
secret-manager.ts
tenant-orchestrator.ts
types.ts
upload-interceptor.ts
utils.ts
worker.ts