ta
TanStack
GitHub
ai
Workspace
GitHub
CI Pipeline Executions
Filtered
Runs
Demo
Insights
Compare tasks
Analytics
Sign in
Toggle sidebar
Overview
⌘K
ai
Loading workspace stats
Loading workspace insights...
Statistics interval
7 days
30 days
Latest CI Pipeline Executions
Status
Fix filter
Filter
Fuzzy
Filter range
Sort by
Sort by
Start time
Sort ascending
Sort descending
Succeeded
main
8498be8a feat(ai-sandbox-upstash-box): add Upstash Box sandbox provider (#899) * feat(ai-sandbox-upstash-box): add Upstash Box sandbox provider Add @tanstack/ai-sandbox-upstash-box, a provider that runs harness adapters inside isolated Upstash Box cloud sandboxes through the uniform SandboxHandle: - fs via Box's native file API (read/write/list) + shell for mkdir/remove/ rename/exists; paths normalized between the virtual /workspace root and Box's /workspace/home session home - exec/spawn shell-wrap cwd + env (exports before `cd` so a failed cd is &&-gated); spawn streams stdout over exec.stream with abort-driven kill() - ports.connect via getPublicURL (bearer/basic auth -> channel headers) - native snapshots (box.snapshot / Box.fromSnapshot) and restoreSnapshot - backgroundProcesses: true / writableStdin: false (Daytona parity); fork unsupported Includes unit tests (mocked Box) and gated integration tests (UPSTASH_BOX_API_KEY), README, changeset, and the central provider-list row. * feat(ai-sandbox-upstash-box): session-backed spawn, tombstone-safe resume Rebuild the provider on `@upstash/box` 0.7.1, which adds `exec.session` and the filesystem metadata operations. - spawn() runs on `exec.session` instead of `exec.stream`: real in-box pid, writable stdin, separate stdout/stderr, and `kill()` that signals the process tree server-side. cwd and env are passed natively, so spawned commands are no longer shell-wrapped. - exec() reports stdout and stderr separately. - fs uses the native file API throughout; `exists` is a `stat` probe. - capabilities: `writableStdin` and `killableProcesses` are now true, and `killableProcesses` (a required field added since this branch was written) is declared for the first time. - resume() probes `getStatus()`. `Box.get` resolves for a DELETED box and returns the tombstone record, so without the probe a destroyed sandbox came back as a handle that threw on first use and `ensure()` reused it. Tests: provider unit tests covering the tombstone path with a mocked Box, plus the shared journal conformance suite, so `killableProcesses: true` is falsifiable rather than asserted. The gated suite measures stdin and the tree kill against a real box. Docs: provider page entry, capability rows, and a changeset. * feat(ai-sandbox-upstash-box): fork, network policy, bounded streams Address review and implement the two capabilities the provider had been declaring false. - resume()/destroy() swallowed every BoxError as "gone". Measured against the API, a missing and a deleted box both answer 404 while a bad key answers 401, so a transport or auth failure reported the sandbox as gone and `ensure()` created a duplicate billed box. Only 404 is swallowed now; everything else propagates. - spawn()'s eagerly created exit promise is marked handled, so a fire-and-forget background process whose session drops no longer raises an unhandled rejection. wait() still surfaces the rejection. - fork() is supported, built on snapshot() + Box.fromSnapshot() (the shape docker uses for commit + create). It costs a full snapshot round trip, roughly 25s, which the docs call out. - networkPolicy is supported: `policy.capabilities.network: 'deny'` maps to Box's deny-all egress mode. The contract's gate is coarse, so Box's domain and CIDR allowlists stay unreachable through it. - Spawned stdout/stderr are capped at 8 MiB each. Overflow announces the truncation and signals the process rather than silently dropping output. - An abort that lands while Box.create is in flight now deletes the box it created instead of stranding a billed sandbox with no owner. Both new capabilities are measured live: fork carries state and then diverges, and a deny policy blocks curl that succeeds on a default box. * fix(ai-sandbox-upstash-box): carry the policy through restoreSnapshot Address the second review pass. - restoreSnapshot dropped `input.policy`. `SandboxRestoreInput` carries one, so restoring a snapshot under `network: 'deny'` produced a box with default egress. Daytona threads the policy through both create and restore; this now matches. - The gated egress test gains a positive control. Asserting only that the denied box fails to reach the network passes just as well when the probe fails for an unrelated reason (DNS, routing, TLS, the host being down) while egress is in fact open. An unrestricted box must now reach the same URL first. - Gated cleanup uses Promise.allSettled. Sequential awaits stranded the second box whenever the first destroy rejected, which destroy() can now do since it rethrows anything that is not a 404. * test(ai-sandbox-upstash-box): do not strand a box when a sibling create fails The egress test created its deny-policy box and its control box with Promise.all. That rejects before either handle is assigned, so a failure in one create left the box the other had already made undestroyed by the finally block. Settle both, assign every fulfilled handle so cleanup can reach it, then rethrow. This is the same leak the previous commit fixed in teardown, reintroduced in setup by the concurrent creation it added. * fix(ai-sandbox-upstash-box): validate env names, stop swallowing real errors Address the fourth review pass. - withEnv() interpolated env NAMES straight into `export <key>=...`. Values were quoted, keys were not, so a caller-supplied key containing `;` injected a command ahead of the requested one. Both env paths now reject anything that is not a valid shell identifier. - exists() reported every failure as "absent", so a 401 or a transport error made a caller believe a file it could not read was missing. Only 404 means absent now, matching resume() and destroy(). - A stream that overflowed while the exec.session handshake was still settling killed nothing, because there was no session yet, and nothing rechecked once there was. The streams closed while the process kept running. - spawn() signalled the process on an abort raised during the handshake but still returned a handle for the cancelled operation. It now rejects, as the pre-flight path does. - The overflow test bounded stdout at 9 MiB, which would pass a regression past the declared 8 MiB cap. It measures the payload apart from the truncation notice and asserts the cap itself. The 404 predicate lived in both handle.ts and provider.ts; it is now one function so the two cannot drift. * ci: apply automated fixes * ci: apply automated fixes (attempt 2/3) * fix(ai-sandbox-upstash-box): add fs.lstat and drop restating comments Portable snapshots throw SANDBOX_SNAPSHOT_LSTAT_REQUIRED without lstat. Use the same POSIX stat protocol as the other cloud providers so mode bits are available. Docs now list Sprites on the writableStdin false row and construct Upstash Box in the chooser snippet. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Alem Tuzlak <t.zlak@hotmail.com>
by Ali Tarık ...
A
Succeeded
main
8498be8a feat(ai-sandbox-upstash-box): add Upstash Box sandbox provider (#899) * feat(ai-sandbox-upstash-box): add Upstash Box sandbox provider Add @tanstack/ai-sandbox-upstash-box, a provider that runs harness adapters inside isolated Upstash Box cloud sandboxes through the uniform SandboxHandle: - fs via Box's native file API (read/write/list) + shell for mkdir/remove/ rename/exists; paths normalized between the virtual /workspace root and Box's /workspace/home session home - exec/spawn shell-wrap cwd + env (exports before `cd` so a failed cd is &&-gated); spawn streams stdout over exec.stream with abort-driven kill() - ports.connect via getPublicURL (bearer/basic auth -> channel headers) - native snapshots (box.snapshot / Box.fromSnapshot) and restoreSnapshot - backgroundProcesses: true / writableStdin: false (Daytona parity); fork unsupported Includes unit tests (mocked Box) and gated integration tests (UPSTASH_BOX_API_KEY), README, changeset, and the central provider-list row. * feat(ai-sandbox-upstash-box): session-backed spawn, tombstone-safe resume Rebuild the provider on `@upstash/box` 0.7.1, which adds `exec.session` and the filesystem metadata operations. - spawn() runs on `exec.session` instead of `exec.stream`: real in-box pid, writable stdin, separate stdout/stderr, and `kill()` that signals the process tree server-side. cwd and env are passed natively, so spawned commands are no longer shell-wrapped. - exec() reports stdout and stderr separately. - fs uses the native file API throughout; `exists` is a `stat` probe. - capabilities: `writableStdin` and `killableProcesses` are now true, and `killableProcesses` (a required field added since this branch was written) is declared for the first time. - resume() probes `getStatus()`. `Box.get` resolves for a DELETED box and returns the tombstone record, so without the probe a destroyed sandbox came back as a handle that threw on first use and `ensure()` reused it. Tests: provider unit tests covering the tombstone path with a mocked Box, plus the shared journal conformance suite, so `killableProcesses: true` is falsifiable rather than asserted. The gated suite measures stdin and the tree kill against a real box. Docs: provider page entry, capability rows, and a changeset. * feat(ai-sandbox-upstash-box): fork, network policy, bounded streams Address review and implement the two capabilities the provider had been declaring false. - resume()/destroy() swallowed every BoxError as "gone". Measured against the API, a missing and a deleted box both answer 404 while a bad key answers 401, so a transport or auth failure reported the sandbox as gone and `ensure()` created a duplicate billed box. Only 404 is swallowed now; everything else propagates. - spawn()'s eagerly created exit promise is marked handled, so a fire-and-forget background process whose session drops no longer raises an unhandled rejection. wait() still surfaces the rejection. - fork() is supported, built on snapshot() + Box.fromSnapshot() (the shape docker uses for commit + create). It costs a full snapshot round trip, roughly 25s, which the docs call out. - networkPolicy is supported: `policy.capabilities.network: 'deny'` maps to Box's deny-all egress mode. The contract's gate is coarse, so Box's domain and CIDR allowlists stay unreachable through it. - Spawned stdout/stderr are capped at 8 MiB each. Overflow announces the truncation and signals the process rather than silently dropping output. - An abort that lands while Box.create is in flight now deletes the box it created instead of stranding a billed sandbox with no owner. Both new capabilities are measured live: fork carries state and then diverges, and a deny policy blocks curl that succeeds on a default box. * fix(ai-sandbox-upstash-box): carry the policy through restoreSnapshot Address the second review pass. - restoreSnapshot dropped `input.policy`. `SandboxRestoreInput` carries one, so restoring a snapshot under `network: 'deny'` produced a box with default egress. Daytona threads the policy through both create and restore; this now matches. - The gated egress test gains a positive control. Asserting only that the denied box fails to reach the network passes just as well when the probe fails for an unrelated reason (DNS, routing, TLS, the host being down) while egress is in fact open. An unrestricted box must now reach the same URL first. - Gated cleanup uses Promise.allSettled. Sequential awaits stranded the second box whenever the first destroy rejected, which destroy() can now do since it rethrows anything that is not a 404. * test(ai-sandbox-upstash-box): do not strand a box when a sibling create fails The egress test created its deny-policy box and its control box with Promise.all. That rejects before either handle is assigned, so a failure in one create left the box the other had already made undestroyed by the finally block. Settle both, assign every fulfilled handle so cleanup can reach it, then rethrow. This is the same leak the previous commit fixed in teardown, reintroduced in setup by the concurrent creation it added. * fix(ai-sandbox-upstash-box): validate env names, stop swallowing real errors Address the fourth review pass. - withEnv() interpolated env NAMES straight into `export <key>=...`. Values were quoted, keys were not, so a caller-supplied key containing `;` injected a command ahead of the requested one. Both env paths now reject anything that is not a valid shell identifier. - exists() reported every failure as "absent", so a 401 or a transport error made a caller believe a file it could not read was missing. Only 404 means absent now, matching resume() and destroy(). - A stream that overflowed while the exec.session handshake was still settling killed nothing, because there was no session yet, and nothing rechecked once there was. The streams closed while the process kept running. - spawn() signalled the process on an abort raised during the handshake but still returned a handle for the cancelled operation. It now rejects, as the pre-flight path does. - The overflow test bounded stdout at 9 MiB, which would pass a regression past the declared 8 MiB cap. It measures the payload apart from the truncation notice and asserts the cap itself. The 404 predicate lived in both handle.ts and provider.ts; it is now one function so the two cannot drift. * ci: apply automated fixes * ci: apply automated fixes (attempt 2/3) * fix(ai-sandbox-upstash-box): add fs.lstat and drop restating comments Portable snapshots throw SANDBOX_SNAPSHOT_LSTAT_REQUIRED without lstat. Use the same POSIX stat protocol as the other cloud providers so mode bits are available. Docs now list Sprites on the writableStdin false row and construct Upstash Box in the chooser snippet. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Alem Tuzlak <t.zlak@hotmail.com>
by Ali Tarık ...
A
Succeeded
feat/upstash-box-sandbox-provider
b96df3c1 Merge 5161395bca58494d53311bf2f3ae10163b2c64f9 into a7e079872af372496728d25e6ec23149cd5e04b9
by Ali Tarık ...
A
Succeeded
feat/upstash-box-sandbox-provider
2b989f4d Merge 01d8848a141379a4969a009762a059ecbd84ebbf into 552303b0f16af3605d34467c92c89ad4bf63e498
by Ali Tarık ...
A
Succeeded
feat/upstash-box-sandbox-provider
eea6ea47 Merge c0fa75f639d8445d1314c799b8e656c6ac9bddff into 4e9c5d2887dc9a3d64fce6ed424aa68f451e20f6
by Ali Tarık ...
A
Succeeded
feat/upstash-box-sandbox-provider
baacd7ef Merge ce1584680e47a9e14f03e9f05dc4bdb792221a3a into 4e9c5d2887dc9a3d64fce6ed424aa68f451e20f6
by Ali Tarık ...
A
Previous
Next