From 0c94bb51a24a75610a0256c2a3804fb23d706b3d Mon Sep 17 00:00:00 2001 From: Topper Bowers Date: Sat, 25 Jul 2026 16:12:56 -0400 Subject: [PATCH] fix(agentos-apps): read the pack artifact over the VM API instead of a host_dir mount Guest-side access to host_dir mounts fails with "Permission denied (os error 2)" (#1872), which made every deployApp() pack step fail with agentos_apps_pack_failed. The build VM no longer mounts a host output directory: tar writes the artifact to the guest filesystem and the host reads it back with vm.readFile, which works. This also removes the host temp directory and its cleanup from the build path. Co-Authored-By: Claude Fable 5 --- packages/agentos-apps/src/actors.ts | 60 ++++++++--------------------- 1 file changed, 17 insertions(+), 43 deletions(-) diff --git a/packages/agentos-apps/src/actors.ts b/packages/agentos-apps/src/actors.ts index 64652e76f8..dbe7cde851 100644 --- a/packages/agentos-apps/src/actors.ts +++ b/packages/agentos-apps/src/actors.ts @@ -1,5 +1,5 @@ import { createHash, randomUUID, timingSafeEqual } from "node:crypto"; -import { mkdtemp, open, readFile, rm, stat } from "node:fs/promises"; +import { mkdtemp, open, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -18,7 +18,6 @@ import { import { AgentOs, type AgentOsOptions, - createHostDirBackend, } from "@rivet-dev/agentos-core"; import { packAospkgFromTarBytes } from "@rivet-dev/agentos-toolchain"; import { actor, UserError } from "rivetkit"; @@ -3131,52 +3130,27 @@ export function createAppsActors( }, }; const createBuildVm = async (): Promise => { - const outputDirectory = await mkdtemp( - join(tmpdir(), "agentos-apps-build-output-"), - ); - const artifactGuestPath = "/agentos-app-output/agentos-app.tar"; - const artifactHostPath = join(outputDirectory, "agentos-app.tar"); - let vm: AgentOs; - try { - vm = await AgentOs.create({ - ...buildVmOptions, - mounts: [ - ...(buildVmOptions.mounts ?? []), - { - path: "/agentos-app-output", - readOnly: false, - plugin: createHostDirBackend({ - hostPath: outputDirectory, - readOnly: false, - }), - }, - ], - }); - } catch (error) { - await rm(outputDirectory, { recursive: true, force: true }); - throw error; - } + // The artifact stays on the guest filesystem and is read back over the + // host VM API instead of a writable host_dir mount: guest-side access + // to host_dir mounts fails with "Permission denied (os error 2)" + // (rivet-dev/agentos#1872), which made every pack step fail. Reading + // through vm.readFile also removes the host temp directory and its + // cleanup entirely. + const artifactGuestPath = "/agentos-app.tar"; + const vm = await AgentOs.create(buildVmOptions); + let artifact: Uint8Array | undefined; + const readArtifact = async (): Promise => { + artifact ??= new Uint8Array(await vm.readFile(artifactGuestPath)); + return artifact; + }; return { artifactGuestPath, writeFiles: (...args) => vm.writeFiles(...args), execArgv: (...args) => vm.execArgv(...args), - artifactSize: async () => (await stat(artifactHostPath)).size, - readArtifact: async () => - new Uint8Array(await readFile(artifactHostPath)), + artifactSize: async () => (await readArtifact()).byteLength, + readArtifact, dispose: async () => { - const results = await Promise.allSettled([ - vm.dispose(), - rm(outputDirectory, { recursive: true, force: true }), - ]); - const failures = results.flatMap((result) => - result.status === "rejected" ? [result.reason] : [], - ); - if (failures.length > 0) { - throw new AggregateError( - failures, - "failed to dispose AgentOS Apps build VM output", - ); - } + await vm.dispose(); }, }; };