diff --git a/apps/api/src/knowledge/utils/markdown.ts b/apps/api/src/knowledge/utils/markdown.ts index b648e62..9e7d40b 100644 --- a/apps/api/src/knowledge/utils/markdown.ts +++ b/apps/api/src/knowledge/utils/markdown.ts @@ -124,6 +124,7 @@ const SANITIZE_OPTIONS: sanitizeHtml.IOptions = { const href = attribs.href; // Strip data: URI scheme from links if (href?.trim().toLowerCase().startsWith("data:")) { + logger.warn(`Blocked data: URI in link href`); const { href: _removed, ...safeAttribs } = attribs; return { tagName, @@ -149,6 +150,7 @@ const SANITIZE_OPTIONS: sanitizeHtml.IOptions = { img: (tagName: string, attribs: sanitizeHtml.Attributes) => { const src = attribs.src; if (src?.trim().toLowerCase().startsWith("data:")) { + logger.warn(`Blocked data: URI in image src`); const { src: _removed, ...safeAttribs } = attribs; return { tagName, diff --git a/apps/orchestrator/src/main.ts b/apps/orchestrator/src/main.ts index 146f973..bdaec70 100644 --- a/apps/orchestrator/src/main.ts +++ b/apps/orchestrator/src/main.ts @@ -17,4 +17,7 @@ async function bootstrap() { logger.log(`🚀 Orchestrator running on http://${host}:${String(port)}`); } -void bootstrap(); +bootstrap().catch((err: unknown) => { + logger.error("Failed to start orchestrator", err instanceof Error ? err.stack : String(err)); + process.exit(1); +}); diff --git a/apps/orchestrator/src/spawner/docker-sandbox.service.spec.ts b/apps/orchestrator/src/spawner/docker-sandbox.service.spec.ts index 49c51cf..bd68184 100644 --- a/apps/orchestrator/src/spawner/docker-sandbox.service.spec.ts +++ b/apps/orchestrator/src/spawner/docker-sandbox.service.spec.ts @@ -243,11 +243,25 @@ describe("DockerSandboxService", () => { expect(mockContainer.remove).toHaveBeenCalledWith({ force: false }); }); - it("should fall back to force remove when graceful stop fails", async () => { + it("should remove without force when container is not running", async () => { const containerId = "container-123"; (mockContainer.stop as ReturnType).mockRejectedValueOnce( - new Error("Container already stopped") + new Error("container is not running") + ); + + await service.removeContainer(containerId); + + expect(mockContainer.stop).toHaveBeenCalledWith({ t: 10 }); + // Not-running containers are removed without force, no escalation needed + expect(mockContainer.remove).toHaveBeenCalledWith({ force: false }); + }); + + it("should fall back to force remove when graceful stop fails with unknown error", async () => { + const containerId = "container-123"; + + (mockContainer.stop as ReturnType).mockRejectedValueOnce( + new Error("Connection timeout") ); await service.removeContainer(containerId); diff --git a/apps/orchestrator/src/spawner/docker-sandbox.service.ts b/apps/orchestrator/src/spawner/docker-sandbox.service.ts index fd52c18..d90cbde 100644 --- a/apps/orchestrator/src/spawner/docker-sandbox.service.ts +++ b/apps/orchestrator/src/spawner/docker-sandbox.service.ts @@ -361,8 +361,17 @@ export class DockerSandboxService { this.logger.log(`Container gracefully stopped and removed: ${containerId}`); return; } catch (gracefulError) { + const errMsg = gracefulError instanceof Error ? gracefulError.message : String(gracefulError); + + // If container is already stopped, just remove without force + if (errMsg.includes("is not running") || errMsg.includes("304")) { + this.logger.log(`Container ${containerId} already stopped, removing without force`); + await container.remove({ force: false }); + return; + } + this.logger.warn( - `Graceful stop failed for container ${containerId}, falling back to force remove: ${gracefulError instanceof Error ? gracefulError.message : String(gracefulError)}` + `Graceful stop failed for container ${containerId}, falling back to force remove: ${errMsg}` ); }