Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ export class DenoRuntimeSubprocessController extends BaseRuntimeSubprocessContro
this.denoDir = process.env.DENO_DIR ?? path.join(this.packagePath, '.deno-cache');

this.denoRuntimePath = path.join(this.tempFilePath, 'deno-runtime', 'main.ts');
this.denoEphemeralConfigPath = this.denoConfigPath.replace('.jsonc', '.runtime.jsonc');
this.denoEphemeralConfigPath = path.join(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P0: Writing ephemeral config to <tempFilePath>/deno-runtime/deno.runtime.jsonc goes through the symlink back to the read-only package directory, so the EROFS error on Snap deployments persists — the fix doesn't reach writable storage. The constructor creates a 'dir' symlink at <tempFilePath>/deno-runtime<packageDir>/deno-runtime/ before the config write. Write the ephemeral config to a path that does not traverse the symlink, e.g. path.join(this.tempFilePath, 'deno.runtime.jsonc'), and update generateEphemeralDenoConfig and the --config arg accordingly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/apps/src/server/runtime/deno/AppsEngineDenoRuntime.ts, line 70:

<comment>Writing ephemeral config to `<tempFilePath>/deno-runtime/deno.runtime.jsonc` goes through the symlink back to the read-only package directory, so the EROFS error on Snap deployments persists — the fix doesn't reach writable storage. The constructor creates a 'dir' symlink at `<tempFilePath>/deno-runtime` → `<packageDir>/deno-runtime/` before the config write. Write the ephemeral config to a path that does not traverse the symlink, e.g. `path.join(this.tempFilePath, 'deno.runtime.jsonc')`, and update `generateEphemeralDenoConfig` and the `--config` arg accordingly.</comment>

<file context>
@@ -67,7 +67,12 @@ export class DenoRuntimeSubprocessController extends BaseRuntimeSubprocessContro
 
 		this.denoRuntimePath = path.join(this.tempFilePath, 'deno-runtime', 'main.ts');
-		this.denoEphemeralConfigPath = this.denoConfigPath.replace('.jsonc', '.runtime.jsonc');
+	this.denoEphemeralConfigPath = path.join(
+	this.tempFilePath,
+	'deno-runtime',
</file context>

this.tempFilePath,
'deno-runtime',
'deno.runtime.jsonc',
Comment on lines +70 to +73

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: Indentation is inconsistent with the rest of the constructor body. The surrounding code uses two tabs for statements inside the constructor, but the new lines use only one tab. Consider aligning the indentation to match the file's convention (two tabs for constructor-body statements).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/apps/src/server/runtime/deno/AppsEngineDenoRuntime.ts, line 70:

<comment>Indentation is inconsistent with the rest of the constructor body. The surrounding code uses two tabs for statements inside the constructor, but the new lines use only one tab. Consider aligning the indentation to match the file's convention (two tabs for constructor-body statements).</comment>

<file context>
@@ -67,7 +67,12 @@ export class DenoRuntimeSubprocessController extends BaseRuntimeSubprocessContro
 
 		this.denoRuntimePath = path.join(this.tempFilePath, 'deno-runtime', 'main.ts');
-		this.denoEphemeralConfigPath = this.denoConfigPath.replace('.jsonc', '.runtime.jsonc');
+	this.denoEphemeralConfigPath = path.join(
+	this.tempFilePath,
+	'deno-runtime',
</file context>
Suggested change
this.denoEphemeralConfigPath = path.join(
this.tempFilePath,
'deno-runtime',
'deno.runtime.jsonc',
this.denoEphemeralConfigPath = path.join(
this.tempFilePath,
'deno-runtime',
'deno.runtime.jsonc',
);

);
Comment on lines +70 to +74

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

The ephemeral config still resolves to the read-only package directory through the symlink.

Line 82 creates a symlink: this.tempFilePath/deno-runtime/path.dirname(this.denoConfigPath) (the package's Deno config directory, which is read-only on Snap). The new denoEphemeralConfigPath at lines 70-74 is this.tempFilePath/deno-runtime/deno.runtime.jsonc, which resolves through that symlink to path.dirname(this.denoConfigPath)/deno.runtime.jsonc — the same read-only location the old code wrote to. The fs.writeFileSync at line 45 (invoked via line 90) will still fail with EROFS on Snap deployments, so this PR does not achieve its stated objective.

The fix is to place the ephemeral config in a directory that is not covered by the symlink:

🐛 Proposed fix: write ephemeral config outside the symlinked directory
	this.denoRuntimePath = path.join(this.tempFilePath, 'deno-runtime', 'main.ts');
-	this.denoEphemeralConfigPath = path.join(
-		this.tempFilePath,
-		'deno-runtime',
-		'deno.runtime.jsonc',
-	);
+	this.denoEphemeralConfigPath = path.join(this.tempFilePath, 'deno-runtime-config', 'deno.runtime.jsonc');

Then ensure the parent directory exists before writing (add before line 90):

+	fs.mkdirSync(path.dirname(this.denoEphemeralConfigPath), { recursive: true });
 	generateEphemeralDenoConfig(this.denoEphemeralConfigPath, this.denoConfigPath, this.appsEnginePath);

This keeps the ephemeral config in the writable temp directory while the symlink at deno-runtime/ continues to expose only the runtime script (main.ts) and other static files from the package.

Also applies to: 82-90

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/apps/src/server/runtime/deno/AppsEngineDenoRuntime.ts` around lines
70 - 74, The ephemeral config path in AppsEngineDenoRuntime still traverses the
deno-runtime symlink into the read-only package directory. Update
denoEphemeralConfigPath to a writable location outside the symlinked
deno-runtime directory, and ensure its parent directory exists before the write
performed by the runtime configuration setup near the symlink creation logic.



/**
* Deno 2.x refuses to run scripts inside the node_modules, so we create a symlink to the deno runtime files in the temp directory
Expand Down