From 82b5453c8812b981fdb0756b469b4e2215ddc4cf Mon Sep 17 00:00:00 2001 From: mptyl Date: Tue, 11 Aug 2026 19:24:15 +0200 Subject: [PATCH] fix: use sha256 descriptor digest and keep operator errors fully sanitized --- backend/src/workspace-maintenance.ts | 7 +++---- backend/src/workspaces/preprocessing-service.ts | 4 +--- backend/src/workspaces/runtime-config-lease.ts | 5 +++-- backend/test/workspace-runtime-config-lease.test.ts | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/backend/src/workspace-maintenance.ts b/backend/src/workspace-maintenance.ts index bb66d8b3..e50d1e5e 100644 --- a/backend/src/workspace-maintenance.ts +++ b/backend/src/workspace-maintenance.ts @@ -41,10 +41,9 @@ function boundedJson(result: WorkspaceOperationResult): string { return encoded; } -function sanitizeStderr(error: unknown): string { - const detail = error instanceof Error ? error.message : String(error); - const safe = detail.replace(/[\r\n]+/g, " ").slice(0, 512); - return safe.length > 0 ? `workspace maintenance failed: ${safe}\n` : "workspace maintenance failed\n"; +function sanitizeStderr(_error: unknown): string { + // Never return raw exception text: it may embed endpoints, tokens, or SQL. + return "workspace maintenance failed\n"; } function parseRequest(command: string, stdin: string): Record { diff --git a/backend/src/workspaces/preprocessing-service.ts b/backend/src/workspaces/preprocessing-service.ts index 9afe0390..da5d7bc6 100644 --- a/backend/src/workspaces/preprocessing-service.ts +++ b/backend/src/workspaces/preprocessing-service.ts @@ -129,8 +129,7 @@ export class WorkspacePreprocessingService { { kind: "runtime_config", digest: runtime.configLease.configDigest }, ], }); - } catch (error) { - const detail = error instanceof Error ? error.message : String(error); + } catch { return { schemaVersion: 1, status: "failed", @@ -140,7 +139,6 @@ export class WorkspacePreprocessingService { descriptorBlob: "", operation: "inspect", completedStages: [], - warnings: detail.length > 0 ? [detail.slice(0, 512)] : undefined, }; } } diff --git a/backend/src/workspaces/runtime-config-lease.ts b/backend/src/workspaces/runtime-config-lease.ts index a0453622..f437fff7 100644 --- a/backend/src/workspaces/runtime-config-lease.ts +++ b/backend/src/workspaces/runtime-config-lease.ts @@ -352,7 +352,8 @@ export async function renderActiveWorkspaceRuntime(options: { const repository = new GitWorkspaceRepository(options.registryConfig); await repository.ensureLayout(); const snapshotPath = options.registry.snapshotPath(revision.commit, revision.id); - const workspace = parseWorkspaceYaml(await readFileAsync(snapshotPath, "utf8")); + const descriptorSource = await readFileAsync(snapshotPath, "utf8"); + const workspace = parseWorkspaceYaml(descriptorSource); const rendered = renderWorkspaceRuntimeFromWorkspace({ workspace, workspaceId: revision.id, @@ -367,7 +368,7 @@ export async function renderActiveWorkspaceRuntime(options: { return { ...rendered, snapshotPath, - descriptorBlob: revision.blob, + descriptorBlob: `sha256:${createHash("sha256").update(descriptorSource).digest("hex")}`, catalogBlob: (await repository.catalogBlob(revision.commit)).trim(), }; } diff --git a/backend/test/workspace-runtime-config-lease.test.ts b/backend/test/workspace-runtime-config-lease.test.ts index b91e3e27..8ab5ee87 100644 --- a/backend/test/workspace-runtime-config-lease.test.ts +++ b/backend/test/workspace-runtime-config-lease.test.ts @@ -159,7 +159,7 @@ test("active workspace rendering is byte-identical to direct snapshot rendering" expect(active.renderedConfig).toBe(direct.renderedConfig); expect(active.workspaceRevision).toBe(f.revision.commit); - expect(active.descriptorBlob).toBe(f.revision.blob); + expect(active.descriptorBlob).toMatch(/^sha256:[0-9a-f]{64}$/); expect(active.catalogBlob).toMatch(/^[0-9a-f]{40}$/); });