paperclip/packages/plugins/sandbox-providers/kubernetes/src
Nicky Leach 0ccba45e4d
feat(sandbox-providers): native providers honor postUploadCommands (Daytona executes; Kubernetes executes) (#10347)
## Thinking Path

> - Paperclip is the control plane for autonomous AI companies, so
runtime handoffs have to preserve the exact behavior an agent asked for.
> - The sandbox-provider layer is where uploaded files and follow-up
commands become a real in-sandbox operation.
> - The provider-delegable sync-in seam already exists from the prior
PR; without this follow-up, native providers can still accept
command-bearing uploads and silently drop the commands.
> - That is a fail-open gap for native sandbox providers, because the
file transfer succeeds while the intended post-upload work never runs.
> - This pull request teaches Daytona and Kubernetes to execute
`postUploadCommands` in order, inside the sandbox, after the files land.
> - The benefit is consistent and safer sync semantics: native providers
either run the commands as requested or fail fast instead of pretending
the operation completed fully.

## Linked Issues or Issue Description

This PR builds on the previously merged provider-delegable sync-in seam
and closes the remaining gap for native providers that still dropped
`postUploadCommands`.

Problem:
- A sync operation could include ordered `postUploadCommands`, but a
native provider could finish the file upload and skip the commands
entirely.
- That creates fail-open behavior for command-bearing uploads,
especially when the caller relies on the provider to execute the
follow-up action in the sandbox.

Proposed fix:
- Execute `postUploadCommands` inside the sandbox after file placement.
- Preserve the provided command order.
- Fail fast on the first non-zero exit or timeout.
- Keep command execution verbatim and confine any provided `cwd` under
the workspace root.

Related public PR:
- Refs: #10340

## What Changed

- Daytona `performSyncIn` now executes ordered `postUploadCommands`
through the existing `executeCommand` seam.
- Kubernetes `performSyncIn` now executes ordered `postUploadCommands`
through its streaming pod exec path.
- Added workspace confinement for provided `cwd` values and defaulted
missing `cwd` to the remote root.
- Added tests covering the new post-upload command execution behavior in
both provider packages.

## Verification

- Latest validation recorded on the handoff branch:
`@paperclipai/plugin-sdk` and `@paperclipai/plugin-kubernetes`
typechecks passed.
- Daytona Vitest: `63/63` passing in `plugin.test.ts`.
- Kubernetes Vitest: `195/195` passing, including `file-sync.test.ts`.
- `git log --oneline origin/master..HEAD` showed a single expected
commit on the branch.

## Risks

- Command execution semantics are stricter now, so malformed commands or
a bad `cwd` will fail the sync instead of being ignored.
- The change makes provider behavior more explicit, which can surface
previously hidden failures in callers that assumed commands were
optional.
- Timeout behavior may differ slightly between providers, so the failure
mode is intentionally fail-fast.

## Model Used

OpenAI Codex, GPT-5-based coding agent with tool use enabled.

## 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
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-27 21:17:16 -07:00
..
adapter-defaults.ts Make ACP the default engine for local adapters (#9238) 2026-07-08 19:05:03 -07:00
adapter-registry.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
cilium-network-policy.ts feat(sandbox): add task-scoped egress grants (#10155) 2026-07-24 09:58:58 -05:00
file-sync.ts feat(sandbox-providers): native providers honor postUploadCommands (Daytona executes; Kubernetes executes) (#10347) 2026-07-27 21:17:16 -07:00
image-allowlist.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
index.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
job-orchestrator.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
kube-client.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
lease-lifecycle.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
manifest.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
network-policy.ts feat(sandbox): add task-scoped egress grants (#10155) 2026-07-24 09:58:58 -05:00
plugin.ts feat(sandbox): add task-scoped egress grants (#10155) 2026-07-24 09:58:58 -05:00
pod-exec.ts feat(kubernetes): native file-sync lifecycle hooks over pod exec (#10053) 2026-07-22 18:52:47 -07:00
pod-spec-builder.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
sandbox-cr-builder.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
sandbox-cr-orchestrator.ts fix(plugin-kubernetes): resolve sandbox pod by exact name (controller labels pods with sandbox-name-hash, not sandbox-name) (#7982) 2026-06-11 17:47:17 -07:00
sandbox-orchestrator.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
scoped-network-egress.ts feat(sandbox): add task-scoped egress grants (#10155) 2026-07-24 09:58:58 -05:00
secret-manager.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
tenant-orchestrator.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
types.ts feat(sandbox): add task-scoped egress grants (#10155) 2026-07-24 09:58:58 -05:00
upload-interceptor.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
utils.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00
worker.ts feat(plugin-kubernetes): self-hostable Kubernetes sandbox provider (stage 1/3: plugin package) (#5790) 2026-06-10 21:07:00 -07:00