fix(SEC-ORCH-30): Add unique suffix to container names
Add crypto.randomBytes(4) hex suffix to container name generation to prevent name collisions when multiple agents spawn simultaneously within the same millisecond. Container names now include both a timestamp and 8 random hex characters for guaranteed uniqueness. Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
3880993b60
commit
6934d9261c
@@ -162,6 +162,42 @@ describe("DockerSandboxService", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should include a random suffix in container name for uniqueness", async () => {
|
||||||
|
const agentId = "agent-123";
|
||||||
|
const taskId = "task-456";
|
||||||
|
const workspacePath = "/workspace/agent-123";
|
||||||
|
|
||||||
|
await service.createContainer(agentId, taskId, workspacePath);
|
||||||
|
|
||||||
|
const callArgs = (mockDocker.createContainer as ReturnType<typeof vi.fn>).mock
|
||||||
|
.calls[0][0] as Docker.ContainerCreateOptions;
|
||||||
|
const containerName = callArgs.name as string;
|
||||||
|
|
||||||
|
// Name format: mosaic-agent-{agentId}-{timestamp}-{8 hex chars}
|
||||||
|
expect(containerName).toMatch(/^mosaic-agent-agent-123-\d+-[0-9a-f]{8}$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should generate unique container names across rapid successive calls", async () => {
|
||||||
|
const agentId = "agent-123";
|
||||||
|
const taskId = "task-456";
|
||||||
|
const workspacePath = "/workspace/agent-123";
|
||||||
|
const containerNames = new Set<string>();
|
||||||
|
|
||||||
|
// Spawn multiple containers rapidly to test for collisions
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
await service.createContainer(agentId, taskId, workspacePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const calls = (mockDocker.createContainer as ReturnType<typeof vi.fn>).mock.calls;
|
||||||
|
for (const call of calls) {
|
||||||
|
const args = call[0] as Docker.ContainerCreateOptions;
|
||||||
|
containerNames.add(args.name as string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All 20 names must be unique (no collisions)
|
||||||
|
expect(containerNames.size).toBe(20);
|
||||||
|
});
|
||||||
|
|
||||||
it("should throw error if container creation fails", async () => {
|
it("should throw error if container creation fails", async () => {
|
||||||
const agentId = "agent-123";
|
const agentId = "agent-123";
|
||||||
const taskId = "task-456";
|
const taskId = "task-456";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Injectable, Logger } from "@nestjs/common";
|
import { Injectable, Logger } from "@nestjs/common";
|
||||||
import { ConfigService } from "@nestjs/config";
|
import { ConfigService } from "@nestjs/config";
|
||||||
|
import { randomBytes } from "crypto";
|
||||||
import Docker from "dockerode";
|
import Docker from "dockerode";
|
||||||
import {
|
import {
|
||||||
DockerSandboxOptions,
|
DockerSandboxOptions,
|
||||||
@@ -248,8 +249,10 @@ export class DockerSandboxService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container name with timestamp to ensure uniqueness
|
// Container name with timestamp and random suffix to guarantee uniqueness
|
||||||
const containerName = `mosaic-agent-${agentId}-${Date.now().toString()}`;
|
// even when multiple agents are spawned simultaneously within the same millisecond
|
||||||
|
const uniqueSuffix = randomBytes(4).toString("hex");
|
||||||
|
const containerName = `mosaic-agent-${agentId}-${Date.now().toString()}-${uniqueSuffix}`;
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`Creating container for agent ${agentId} (image: ${image}, memory: ${memoryMB.toString()}MB, cpu: ${cpuLimit.toString()})`
|
`Creating container for agent ${agentId} (image: ${image}, memory: ${memoryMB.toString()}MB, cpu: ${cpuLimit.toString()})`
|
||||||
|
|||||||
Reference in New Issue
Block a user