@herdctl/core 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/__tests__/agent.test.js +12 -12
- package/dist/config/__tests__/agent.test.js.map +1 -1
- package/dist/config/__tests__/loader.test.js +201 -4
- package/dist/config/__tests__/loader.test.js.map +1 -1
- package/dist/config/__tests__/merge.test.js +29 -4
- package/dist/config/__tests__/merge.test.js.map +1 -1
- package/dist/config/__tests__/parser.test.js +13 -13
- package/dist/config/__tests__/parser.test.js.map +1 -1
- package/dist/config/__tests__/schema.test.js +10 -10
- package/dist/config/__tests__/schema.test.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -2
- package/dist/config/index.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +71 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/merge.d.ts +4 -1
- package/dist/config/merge.d.ts.map +1 -1
- package/dist/config/merge.js +16 -0
- package/dist/config/merge.js.map +1 -1
- package/dist/config/schema.d.ts +906 -89
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +109 -7
- package/dist/config/schema.js.map +1 -1
- package/dist/fleet-manager/__tests__/coverage.test.js +25 -24
- package/dist/fleet-manager/__tests__/coverage.test.js.map +1 -1
- package/dist/fleet-manager/__tests__/discord-manager.test.js +9 -2
- package/dist/fleet-manager/__tests__/discord-manager.test.js.map +1 -1
- package/dist/fleet-manager/__tests__/integration.test.js +27 -0
- package/dist/fleet-manager/__tests__/integration.test.js.map +1 -1
- package/dist/fleet-manager/__tests__/job-control.test.js +66 -0
- package/dist/fleet-manager/__tests__/job-control.test.js.map +1 -1
- package/dist/fleet-manager/__tests__/status-queries.test.js +12 -11
- package/dist/fleet-manager/__tests__/status-queries.test.js.map +1 -1
- package/dist/fleet-manager/config-reload.js +9 -9
- package/dist/fleet-manager/config-reload.js.map +1 -1
- package/dist/fleet-manager/discord-manager.d.ts.map +1 -1
- package/dist/fleet-manager/discord-manager.js +27 -4
- package/dist/fleet-manager/discord-manager.js.map +1 -1
- package/dist/fleet-manager/fleet-manager.d.ts +11 -0
- package/dist/fleet-manager/fleet-manager.d.ts.map +1 -1
- package/dist/fleet-manager/fleet-manager.js +27 -0
- package/dist/fleet-manager/fleet-manager.js.map +1 -1
- package/dist/fleet-manager/job-control.d.ts +1 -1
- package/dist/fleet-manager/job-control.d.ts.map +1 -1
- package/dist/fleet-manager/job-control.js +36 -14
- package/dist/fleet-manager/job-control.js.map +1 -1
- package/dist/fleet-manager/schedule-executor.d.ts +1 -1
- package/dist/fleet-manager/schedule-executor.d.ts.map +1 -1
- package/dist/fleet-manager/schedule-executor.js +11 -14
- package/dist/fleet-manager/schedule-executor.js.map +1 -1
- package/dist/fleet-manager/status-queries.js +7 -7
- package/dist/fleet-manager/status-queries.js.map +1 -1
- package/dist/fleet-manager/types.d.ts +10 -2
- package/dist/fleet-manager/types.d.ts.map +1 -1
- package/dist/fleet-manager/working-directory-helper.d.ts +29 -0
- package/dist/fleet-manager/working-directory-helper.d.ts.map +1 -0
- package/dist/fleet-manager/working-directory-helper.js +36 -0
- package/dist/fleet-manager/working-directory-helper.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/runner/__tests__/job-executor.test.js +449 -118
- package/dist/runner/__tests__/job-executor.test.js.map +1 -1
- package/dist/runner/__tests__/sdk-adapter.test.js +147 -23
- package/dist/runner/__tests__/sdk-adapter.test.js.map +1 -1
- package/dist/runner/index.d.ts +2 -0
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/index.js +1 -0
- package/dist/runner/index.js.map +1 -1
- package/dist/runner/job-executor.d.ts +12 -8
- package/dist/runner/job-executor.d.ts.map +1 -1
- package/dist/runner/job-executor.js +257 -126
- package/dist/runner/job-executor.js.map +1 -1
- package/dist/runner/runtime/__tests__/cli-session-path.test.d.ts +2 -0
- package/dist/runner/runtime/__tests__/cli-session-path.test.d.ts.map +1 -0
- package/dist/runner/runtime/__tests__/cli-session-path.test.js +150 -0
- package/dist/runner/runtime/__tests__/cli-session-path.test.js.map +1 -0
- package/dist/runner/runtime/__tests__/docker-config.test.d.ts +2 -0
- package/dist/runner/runtime/__tests__/docker-config.test.d.ts.map +1 -0
- package/dist/runner/runtime/__tests__/docker-config.test.js +352 -0
- package/dist/runner/runtime/__tests__/docker-config.test.js.map +1 -0
- package/dist/runner/runtime/__tests__/docker-security.test.d.ts +2 -0
- package/dist/runner/runtime/__tests__/docker-security.test.d.ts.map +1 -0
- package/dist/runner/runtime/__tests__/docker-security.test.js +384 -0
- package/dist/runner/runtime/__tests__/docker-security.test.js.map +1 -0
- package/dist/runner/runtime/__tests__/factory.test.d.ts +2 -0
- package/dist/runner/runtime/__tests__/factory.test.d.ts.map +1 -0
- package/dist/runner/runtime/__tests__/factory.test.js +149 -0
- package/dist/runner/runtime/__tests__/factory.test.js.map +1 -0
- package/dist/runner/runtime/__tests__/integration.test.d.ts +2 -0
- package/dist/runner/runtime/__tests__/integration.test.d.ts.map +1 -0
- package/dist/runner/runtime/__tests__/integration.test.js +274 -0
- package/dist/runner/runtime/__tests__/integration.test.js.map +1 -0
- package/dist/runner/runtime/cli-runtime.d.ts +107 -0
- package/dist/runner/runtime/cli-runtime.d.ts.map +1 -0
- package/dist/runner/runtime/cli-runtime.js +335 -0
- package/dist/runner/runtime/cli-runtime.js.map +1 -0
- package/dist/runner/runtime/cli-session-path.d.ts +108 -0
- package/dist/runner/runtime/cli-session-path.d.ts.map +1 -0
- package/dist/runner/runtime/cli-session-path.js +173 -0
- package/dist/runner/runtime/cli-session-path.js.map +1 -0
- package/dist/runner/runtime/cli-session-watcher.d.ts +55 -0
- package/dist/runner/runtime/cli-session-watcher.d.ts.map +1 -0
- package/dist/runner/runtime/cli-session-watcher.js +187 -0
- package/dist/runner/runtime/cli-session-watcher.js.map +1 -0
- package/dist/runner/runtime/container-manager.d.ts +76 -0
- package/dist/runner/runtime/container-manager.d.ts.map +1 -0
- package/dist/runner/runtime/container-manager.js +229 -0
- package/dist/runner/runtime/container-manager.js.map +1 -0
- package/dist/runner/runtime/container-runner.d.ts +62 -0
- package/dist/runner/runtime/container-runner.d.ts.map +1 -0
- package/dist/runner/runtime/container-runner.js +235 -0
- package/dist/runner/runtime/container-runner.js.map +1 -0
- package/dist/runner/runtime/docker-config.d.ts +100 -0
- package/dist/runner/runtime/docker-config.d.ts.map +1 -0
- package/dist/runner/runtime/docker-config.js +98 -0
- package/dist/runner/runtime/docker-config.js.map +1 -0
- package/dist/runner/runtime/factory.d.ts +63 -0
- package/dist/runner/runtime/factory.d.ts.map +1 -0
- package/dist/runner/runtime/factory.js +68 -0
- package/dist/runner/runtime/factory.js.map +1 -0
- package/dist/runner/runtime/index.d.ts +20 -0
- package/dist/runner/runtime/index.d.ts.map +1 -0
- package/dist/runner/runtime/index.js +21 -0
- package/dist/runner/runtime/index.js.map +1 -0
- package/dist/runner/runtime/interface.d.ts +59 -0
- package/dist/runner/runtime/interface.d.ts.map +1 -0
- package/dist/runner/runtime/interface.js +12 -0
- package/dist/runner/runtime/interface.js.map +1 -0
- package/dist/runner/runtime/sdk-runtime.d.ts +46 -0
- package/dist/runner/runtime/sdk-runtime.d.ts.map +1 -0
- package/dist/runner/runtime/sdk-runtime.js +63 -0
- package/dist/runner/runtime/sdk-runtime.js.map +1 -0
- package/dist/runner/sdk-adapter.d.ts +4 -0
- package/dist/runner/sdk-adapter.d.ts.map +1 -1
- package/dist/runner/sdk-adapter.js +35 -16
- package/dist/runner/sdk-adapter.js.map +1 -1
- package/dist/runner/types.d.ts +12 -6
- package/dist/runner/types.d.ts.map +1 -1
- package/dist/scheduler/__tests__/schedule-runner.test.js +61 -50
- package/dist/scheduler/__tests__/schedule-runner.test.js.map +1 -1
- package/dist/scheduler/schedule-runner.d.ts +1 -4
- package/dist/scheduler/schedule-runner.d.ts.map +1 -1
- package/dist/scheduler/schedule-runner.js +40 -8
- package/dist/scheduler/schedule-runner.js.map +1 -1
- package/dist/state/__tests__/session-schema.test.js +4 -0
- package/dist/state/__tests__/session-schema.test.js.map +1 -1
- package/dist/state/__tests__/session-validation.test.d.ts +2 -0
- package/dist/state/__tests__/session-validation.test.d.ts.map +1 -0
- package/dist/state/__tests__/session-validation.test.js +446 -0
- package/dist/state/__tests__/session-validation.test.js.map +1 -0
- package/dist/state/__tests__/session.test.js +68 -0
- package/dist/state/__tests__/session.test.js.map +1 -1
- package/dist/state/__tests__/working-directory-validation.test.d.ts +5 -0
- package/dist/state/__tests__/working-directory-validation.test.d.ts.map +1 -0
- package/dist/state/__tests__/working-directory-validation.test.js +101 -0
- package/dist/state/__tests__/working-directory-validation.test.js.map +1 -0
- package/dist/state/index.d.ts +2 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +4 -0
- package/dist/state/index.js.map +1 -1
- package/dist/state/schemas/session-info.d.ts +32 -0
- package/dist/state/schemas/session-info.d.ts.map +1 -1
- package/dist/state/schemas/session-info.js +22 -0
- package/dist/state/schemas/session-info.js.map +1 -1
- package/dist/state/session-validation.d.ts +202 -0
- package/dist/state/session-validation.d.ts.map +1 -0
- package/dist/state/session-validation.js +407 -0
- package/dist/state/session-validation.js.map +1 -0
- package/dist/state/session.d.ts +23 -3
- package/dist/state/session.d.ts.map +1 -1
- package/dist/state/session.js +41 -6
- package/dist/state/session.js.map +1 -1
- package/dist/state/working-directory-validation.d.ts +52 -0
- package/dist/state/working-directory-validation.d.ts.map +1 -0
- package/dist/state/working-directory-validation.js +81 -0
- package/dist/state/working-directory-validation.js.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { mkdir, rm, realpath } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
import { exec } from "node:child_process";
|
|
8
|
+
import { buildContainerMounts, buildContainerEnv, } from "../container-manager.js";
|
|
9
|
+
import { resolveDockerConfig } from "../docker-config.js";
|
|
10
|
+
const execAsync = promisify(exec);
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Environment Detection
|
|
13
|
+
// =============================================================================
|
|
14
|
+
function isDockerAvailable() {
|
|
15
|
+
try {
|
|
16
|
+
execSync("docker info", { stdio: "ignore" });
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const DOCKER_AVAILABLE = isDockerAvailable();
|
|
24
|
+
// Skip entire file if Docker not available
|
|
25
|
+
const describeDocker = DOCKER_AVAILABLE ? describe : describe.skip;
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// Test Helpers
|
|
28
|
+
// =============================================================================
|
|
29
|
+
async function createTempDir() {
|
|
30
|
+
const baseDir = join(tmpdir(), `herdctl-docker-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
31
|
+
await mkdir(baseDir, { recursive: true });
|
|
32
|
+
return await realpath(baseDir);
|
|
33
|
+
}
|
|
34
|
+
function createTestAgent(overrides = {}) {
|
|
35
|
+
return {
|
|
36
|
+
name: "test-agent",
|
|
37
|
+
configPath: "/path/to/agent.yaml",
|
|
38
|
+
working_directory: "/workspace/project",
|
|
39
|
+
...overrides,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function inspectContainer(containerId) {
|
|
43
|
+
const { stdout } = await execAsync(`docker inspect ${containerId}`);
|
|
44
|
+
return JSON.parse(stdout)[0];
|
|
45
|
+
}
|
|
46
|
+
async function removeContainer(containerId) {
|
|
47
|
+
try {
|
|
48
|
+
await execAsync(`docker rm -f ${containerId}`);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore if already removed
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// =============================================================================
|
|
55
|
+
// Docker Security Tests
|
|
56
|
+
// =============================================================================
|
|
57
|
+
describeDocker("Docker Security Hardening", () => {
|
|
58
|
+
let tempDir;
|
|
59
|
+
const containers = [];
|
|
60
|
+
beforeEach(async () => {
|
|
61
|
+
tempDir = await createTempDir();
|
|
62
|
+
});
|
|
63
|
+
afterEach(async () => {
|
|
64
|
+
// Clean up containers
|
|
65
|
+
for (const id of containers) {
|
|
66
|
+
await removeContainer(id);
|
|
67
|
+
}
|
|
68
|
+
containers.length = 0;
|
|
69
|
+
// Clean up temp dir
|
|
70
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
71
|
+
});
|
|
72
|
+
describe("buildContainerMounts", () => {
|
|
73
|
+
it("includes workspace mount", () => {
|
|
74
|
+
const agent = createTestAgent();
|
|
75
|
+
const dockerConfig = resolveDockerConfig({
|
|
76
|
+
enabled: true,
|
|
77
|
+
workspace_mode: "rw",
|
|
78
|
+
});
|
|
79
|
+
const mounts = buildContainerMounts(agent, dockerConfig, tempDir);
|
|
80
|
+
const workspaceMount = mounts.find((m) => m.containerPath === "/workspace");
|
|
81
|
+
expect(workspaceMount).toBeDefined();
|
|
82
|
+
expect(workspaceMount?.mode).toBe("rw");
|
|
83
|
+
});
|
|
84
|
+
it("mounts workspace read-only when workspace_mode is ro", () => {
|
|
85
|
+
const agent = createTestAgent();
|
|
86
|
+
const dockerConfig = resolveDockerConfig({
|
|
87
|
+
enabled: true,
|
|
88
|
+
workspace_mode: "ro",
|
|
89
|
+
});
|
|
90
|
+
const mounts = buildContainerMounts(agent, dockerConfig, tempDir);
|
|
91
|
+
const workspaceMount = mounts.find((m) => m.containerPath === "/workspace");
|
|
92
|
+
expect(workspaceMount?.mode).toBe("ro");
|
|
93
|
+
});
|
|
94
|
+
it("does not mount auth files (uses ANTHROPIC_API_KEY instead)", () => {
|
|
95
|
+
const agent = createTestAgent();
|
|
96
|
+
const dockerConfig = resolveDockerConfig({ enabled: true });
|
|
97
|
+
const mounts = buildContainerMounts(agent, dockerConfig, tempDir);
|
|
98
|
+
// Auth should NOT be mounted - we use ANTHROPIC_API_KEY env var instead
|
|
99
|
+
const authMount = mounts.find((m) => m.containerPath?.includes(".claude") && m.hostPath?.includes(".claude"));
|
|
100
|
+
expect(authMount).toBeUndefined();
|
|
101
|
+
});
|
|
102
|
+
it("includes docker-sessions directory mount at Claude session path", () => {
|
|
103
|
+
const agent = createTestAgent();
|
|
104
|
+
const dockerConfig = resolveDockerConfig({ enabled: true });
|
|
105
|
+
const mounts = buildContainerMounts(agent, dockerConfig, tempDir);
|
|
106
|
+
// Session mount at Claude CLI session location (encoded path: /workspace → -workspace)
|
|
107
|
+
const sessionMount = mounts.find((m) => m.containerPath === "/home/claude/.claude/projects/-workspace");
|
|
108
|
+
expect(sessionMount).toBeDefined();
|
|
109
|
+
expect(sessionMount?.mode).toBe("rw");
|
|
110
|
+
});
|
|
111
|
+
it("includes additional volumes from config", () => {
|
|
112
|
+
const agent = createTestAgent();
|
|
113
|
+
const dockerConfig = resolveDockerConfig({
|
|
114
|
+
enabled: true,
|
|
115
|
+
volumes: ["/data:/data:ro"],
|
|
116
|
+
});
|
|
117
|
+
const mounts = buildContainerMounts(agent, dockerConfig, tempDir);
|
|
118
|
+
const dataMount = mounts.find((m) => m.containerPath === "/data");
|
|
119
|
+
expect(dataMount).toBeDefined();
|
|
120
|
+
expect(dataMount?.mode).toBe("ro");
|
|
121
|
+
});
|
|
122
|
+
it("handles agent workspace as string", () => {
|
|
123
|
+
const agent = createTestAgent({
|
|
124
|
+
working_directory: "/path/to/workspace",
|
|
125
|
+
});
|
|
126
|
+
const dockerConfig = resolveDockerConfig({ enabled: true });
|
|
127
|
+
const mounts = buildContainerMounts(agent, dockerConfig, tempDir);
|
|
128
|
+
const workspaceMount = mounts.find((m) => m.containerPath === "/workspace");
|
|
129
|
+
expect(workspaceMount).toBeDefined();
|
|
130
|
+
expect(workspaceMount?.hostPath).toBe("/path/to/workspace");
|
|
131
|
+
});
|
|
132
|
+
it("handles agent workspace as object with root", () => {
|
|
133
|
+
const agent = createTestAgent({
|
|
134
|
+
working_directory: {
|
|
135
|
+
root: "/path/to/workspace",
|
|
136
|
+
auto_clone: true,
|
|
137
|
+
clone_depth: 1,
|
|
138
|
+
default_branch: "main",
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
const dockerConfig = resolveDockerConfig({ enabled: true });
|
|
142
|
+
const mounts = buildContainerMounts(agent, dockerConfig, tempDir);
|
|
143
|
+
const workspaceMount = mounts.find((m) => m.containerPath === "/workspace");
|
|
144
|
+
expect(workspaceMount).toBeDefined();
|
|
145
|
+
expect(workspaceMount?.hostPath).toBe("/path/to/workspace");
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe("buildContainerEnv", () => {
|
|
149
|
+
it("includes HOME environment variable", () => {
|
|
150
|
+
const agent = createTestAgent();
|
|
151
|
+
const env = buildContainerEnv(agent);
|
|
152
|
+
expect(env).toContain("HOME=/home/claude");
|
|
153
|
+
});
|
|
154
|
+
it("includes TERM environment variable", () => {
|
|
155
|
+
const agent = createTestAgent();
|
|
156
|
+
const env = buildContainerEnv(agent);
|
|
157
|
+
const termEnv = env.find((e) => e.startsWith("TERM="));
|
|
158
|
+
expect(termEnv).toBeDefined();
|
|
159
|
+
});
|
|
160
|
+
it("includes ANTHROPIC_API_KEY if set in process.env", () => {
|
|
161
|
+
const originalKey = process.env.ANTHROPIC_API_KEY;
|
|
162
|
+
process.env.ANTHROPIC_API_KEY = "test-key-123";
|
|
163
|
+
const agent = createTestAgent();
|
|
164
|
+
const env = buildContainerEnv(agent);
|
|
165
|
+
expect(env).toContain("ANTHROPIC_API_KEY=test-key-123");
|
|
166
|
+
// Restore
|
|
167
|
+
if (originalKey) {
|
|
168
|
+
process.env.ANTHROPIC_API_KEY = originalKey;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
delete process.env.ANTHROPIC_API_KEY;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
it("does not include ANTHROPIC_API_KEY if not set", () => {
|
|
175
|
+
const originalKey = process.env.ANTHROPIC_API_KEY;
|
|
176
|
+
delete process.env.ANTHROPIC_API_KEY;
|
|
177
|
+
const agent = createTestAgent();
|
|
178
|
+
const env = buildContainerEnv(agent);
|
|
179
|
+
const apiKeyEnv = env.find((e) => e.startsWith("ANTHROPIC_API_KEY="));
|
|
180
|
+
expect(apiKeyEnv).toBeUndefined();
|
|
181
|
+
// Restore
|
|
182
|
+
if (originalKey) {
|
|
183
|
+
process.env.ANTHROPIC_API_KEY = originalKey;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
it("includes custom env vars from docker config", () => {
|
|
187
|
+
const agent = createTestAgent();
|
|
188
|
+
const dockerConfig = resolveDockerConfig({
|
|
189
|
+
enabled: true,
|
|
190
|
+
env: {
|
|
191
|
+
GITHUB_TOKEN: "ghp_test123",
|
|
192
|
+
CUSTOM_VAR: "custom_value",
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
const env = buildContainerEnv(agent, dockerConfig);
|
|
196
|
+
expect(env).toContain("GITHUB_TOKEN=ghp_test123");
|
|
197
|
+
expect(env).toContain("CUSTOM_VAR=custom_value");
|
|
198
|
+
});
|
|
199
|
+
it("works without docker config (backwards compatible)", () => {
|
|
200
|
+
const agent = createTestAgent();
|
|
201
|
+
const env = buildContainerEnv(agent);
|
|
202
|
+
// Should still include basic env vars
|
|
203
|
+
expect(env).toContain("HOME=/home/claude");
|
|
204
|
+
expect(env.find((e) => e.startsWith("TERM="))).toBeDefined();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe("Container Configuration", () => {
|
|
208
|
+
it("applies no-new-privileges security option", async () => {
|
|
209
|
+
// Create a container to inspect (don't start it)
|
|
210
|
+
const { stdout } = await execAsync(`docker create --security-opt=no-new-privileges alpine:latest sleep 1`);
|
|
211
|
+
const containerId = stdout.trim();
|
|
212
|
+
containers.push(containerId);
|
|
213
|
+
const inspection = await inspectContainer(containerId);
|
|
214
|
+
// Verify security options are applied
|
|
215
|
+
expect(inspection.HostConfig.SecurityOpt).toContain("no-new-privileges");
|
|
216
|
+
});
|
|
217
|
+
it("drops all capabilities", async () => {
|
|
218
|
+
const { stdout } = await execAsync(`docker create --cap-drop=ALL alpine:latest sleep 1`);
|
|
219
|
+
const containerId = stdout.trim();
|
|
220
|
+
containers.push(containerId);
|
|
221
|
+
const inspection = await inspectContainer(containerId);
|
|
222
|
+
expect(inspection.HostConfig.CapDrop).toContain("ALL");
|
|
223
|
+
});
|
|
224
|
+
it("sets memory limits", async () => {
|
|
225
|
+
const memoryLimit = 512 * 1024 * 1024; // 512MB
|
|
226
|
+
const { stdout } = await execAsync(`docker create --memory=${memoryLimit} alpine:latest sleep 1`);
|
|
227
|
+
const containerId = stdout.trim();
|
|
228
|
+
containers.push(containerId);
|
|
229
|
+
const inspection = await inspectContainer(containerId);
|
|
230
|
+
expect(inspection.HostConfig.Memory).toBe(memoryLimit);
|
|
231
|
+
});
|
|
232
|
+
it("sets user to non-root", async () => {
|
|
233
|
+
const { stdout } = await execAsync(`docker create --user=1000:1000 alpine:latest sleep 1`);
|
|
234
|
+
const containerId = stdout.trim();
|
|
235
|
+
containers.push(containerId);
|
|
236
|
+
const inspection = await inspectContainer(containerId);
|
|
237
|
+
expect(inspection.Config.User).toBe("1000:1000");
|
|
238
|
+
});
|
|
239
|
+
it("applies network mode", async () => {
|
|
240
|
+
const { stdout } = await execAsync(`docker create --network=bridge alpine:latest sleep 1`);
|
|
241
|
+
const containerId = stdout.trim();
|
|
242
|
+
containers.push(containerId);
|
|
243
|
+
const inspection = await inspectContainer(containerId);
|
|
244
|
+
expect(inspection.HostConfig.NetworkMode).toBe("bridge");
|
|
245
|
+
});
|
|
246
|
+
it("mounts with read-only flag when specified", async () => {
|
|
247
|
+
await mkdir(join(tempDir, "data"), { recursive: true });
|
|
248
|
+
const { stdout } = await execAsync(`docker create -v ${tempDir}/data:/data:ro alpine:latest sleep 1`);
|
|
249
|
+
const containerId = stdout.trim();
|
|
250
|
+
containers.push(containerId);
|
|
251
|
+
const inspection = await inspectContainer(containerId);
|
|
252
|
+
const dataMount = inspection.Mounts.find((m) => m.Destination === "/data");
|
|
253
|
+
expect(dataMount?.RW).toBe(false);
|
|
254
|
+
});
|
|
255
|
+
it("sets AutoRemove when ephemeral is true", async () => {
|
|
256
|
+
const { stdout } = await execAsync(`docker create --rm alpine:latest sleep 1`);
|
|
257
|
+
const containerId = stdout.trim();
|
|
258
|
+
containers.push(containerId);
|
|
259
|
+
const inspection = await inspectContainer(containerId);
|
|
260
|
+
expect(inspection.HostConfig.AutoRemove).toBe(true);
|
|
261
|
+
});
|
|
262
|
+
it("does not set AutoRemove when ephemeral is false", async () => {
|
|
263
|
+
const { stdout } = await execAsync(`docker create alpine:latest sleep 1`);
|
|
264
|
+
const containerId = stdout.trim();
|
|
265
|
+
containers.push(containerId);
|
|
266
|
+
const inspection = await inspectContainer(containerId);
|
|
267
|
+
expect(inspection.HostConfig.AutoRemove).toBe(false);
|
|
268
|
+
});
|
|
269
|
+
it("sets memory and swap limit to same value (no swap)", async () => {
|
|
270
|
+
const memoryLimit = 1024 * 1024 * 1024; // 1GB
|
|
271
|
+
const { stdout } = await execAsync(`docker create --memory=${memoryLimit} --memory-swap=${memoryLimit} alpine:latest sleep 1`);
|
|
272
|
+
const containerId = stdout.trim();
|
|
273
|
+
containers.push(containerId);
|
|
274
|
+
const inspection = await inspectContainer(containerId);
|
|
275
|
+
expect(inspection.HostConfig.Memory).toBe(memoryLimit);
|
|
276
|
+
expect(inspection.HostConfig.MemorySwap).toBe(memoryLimit);
|
|
277
|
+
});
|
|
278
|
+
it("sets CPU shares for resource limits", async () => {
|
|
279
|
+
const cpuShares = 512;
|
|
280
|
+
const { stdout } = await execAsync(`docker create --cpu-shares=${cpuShares} alpine:latest sleep 1`);
|
|
281
|
+
const containerId = stdout.trim();
|
|
282
|
+
containers.push(containerId);
|
|
283
|
+
const inspection = await inspectContainer(containerId);
|
|
284
|
+
expect(inspection.HostConfig.CpuShares).toBe(cpuShares);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
// =============================================================================
|
|
289
|
+
// Docker Config Resolution Tests (don't need Docker running)
|
|
290
|
+
// =============================================================================
|
|
291
|
+
describe("Docker Config Security Defaults", () => {
|
|
292
|
+
it("defaults to bridge network (not none)", () => {
|
|
293
|
+
const config = resolveDockerConfig({ enabled: true });
|
|
294
|
+
expect(config.network).toBe("bridge");
|
|
295
|
+
});
|
|
296
|
+
it("defaults to 2GB memory", () => {
|
|
297
|
+
const config = resolveDockerConfig({ enabled: true });
|
|
298
|
+
expect(config.memoryBytes).toBe(2 * 1024 * 1024 * 1024);
|
|
299
|
+
});
|
|
300
|
+
it("defaults to host user UID:GID", () => {
|
|
301
|
+
const config = resolveDockerConfig({ enabled: true });
|
|
302
|
+
expect(config.user).toMatch(/^\d+:\d+$/);
|
|
303
|
+
});
|
|
304
|
+
it("defaults workspace to read-write", () => {
|
|
305
|
+
const config = resolveDockerConfig({ enabled: true });
|
|
306
|
+
expect(config.workspaceMode).toBe("rw");
|
|
307
|
+
});
|
|
308
|
+
it("defaults ephemeral to true", () => {
|
|
309
|
+
const config = resolveDockerConfig({ enabled: true });
|
|
310
|
+
expect(config.ephemeral).toBe(true);
|
|
311
|
+
});
|
|
312
|
+
it("defaults max_containers to 5", () => {
|
|
313
|
+
const config = resolveDockerConfig({ enabled: true });
|
|
314
|
+
expect(config.maxContainers).toBe(5);
|
|
315
|
+
});
|
|
316
|
+
it("allows custom network mode", () => {
|
|
317
|
+
const config = resolveDockerConfig({
|
|
318
|
+
enabled: true,
|
|
319
|
+
network: "host",
|
|
320
|
+
});
|
|
321
|
+
expect(config.network).toBe("host");
|
|
322
|
+
});
|
|
323
|
+
it("allows custom memory limit", () => {
|
|
324
|
+
const config = resolveDockerConfig({
|
|
325
|
+
enabled: true,
|
|
326
|
+
memory: "512m",
|
|
327
|
+
});
|
|
328
|
+
expect(config.memoryBytes).toBe(512 * 1024 * 1024);
|
|
329
|
+
});
|
|
330
|
+
it("allows custom user", () => {
|
|
331
|
+
const config = resolveDockerConfig({
|
|
332
|
+
enabled: true,
|
|
333
|
+
user: "1001:1001",
|
|
334
|
+
});
|
|
335
|
+
expect(config.user).toBe("1001:1001");
|
|
336
|
+
});
|
|
337
|
+
it("allows custom workspace mode", () => {
|
|
338
|
+
const config = resolveDockerConfig({
|
|
339
|
+
enabled: true,
|
|
340
|
+
workspace_mode: "ro",
|
|
341
|
+
});
|
|
342
|
+
expect(config.workspaceMode).toBe("ro");
|
|
343
|
+
});
|
|
344
|
+
it("allows ephemeral mode", () => {
|
|
345
|
+
const config = resolveDockerConfig({
|
|
346
|
+
enabled: true,
|
|
347
|
+
ephemeral: true,
|
|
348
|
+
});
|
|
349
|
+
expect(config.ephemeral).toBe(true);
|
|
350
|
+
});
|
|
351
|
+
it("allows custom max_containers", () => {
|
|
352
|
+
const config = resolveDockerConfig({
|
|
353
|
+
enabled: true,
|
|
354
|
+
max_containers: 10,
|
|
355
|
+
});
|
|
356
|
+
expect(config.maxContainers).toBe(10);
|
|
357
|
+
});
|
|
358
|
+
it("parses additional volumes correctly", () => {
|
|
359
|
+
const config = resolveDockerConfig({
|
|
360
|
+
enabled: true,
|
|
361
|
+
volumes: ["/host/path:/container/path:ro"],
|
|
362
|
+
});
|
|
363
|
+
expect(config.volumes).toHaveLength(1);
|
|
364
|
+
expect(config.volumes[0].hostPath).toBe("/host/path");
|
|
365
|
+
expect(config.volumes[0].containerPath).toBe("/container/path");
|
|
366
|
+
expect(config.volumes[0].mode).toBe("ro");
|
|
367
|
+
});
|
|
368
|
+
it("uses base_image if image not specified", () => {
|
|
369
|
+
const config = resolveDockerConfig({
|
|
370
|
+
enabled: true,
|
|
371
|
+
base_image: "custom:latest",
|
|
372
|
+
});
|
|
373
|
+
expect(config.image).toBe("custom:latest");
|
|
374
|
+
});
|
|
375
|
+
it("prefers image over base_image", () => {
|
|
376
|
+
const config = resolveDockerConfig({
|
|
377
|
+
enabled: true,
|
|
378
|
+
image: "specific:latest",
|
|
379
|
+
base_image: "fallback:latest",
|
|
380
|
+
});
|
|
381
|
+
expect(config.image).toBe("specific:latest");
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
//# sourceMappingURL=docker-security.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-security.test.js","sourceRoot":"","sources":["../../../../src/runner/runtime/__tests__/docker-security.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.test.d.ts","sourceRoot":"","sources":["../../../../src/runner/runtime/__tests__/factory.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { RuntimeFactory } from "../factory.js";
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Test Helpers
|
|
5
|
+
// =============================================================================
|
|
6
|
+
function createTestAgent(overrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
name: "test-agent",
|
|
9
|
+
configPath: "/path/to/agent.yaml",
|
|
10
|
+
...overrides,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// RuntimeFactory Tests
|
|
15
|
+
// =============================================================================
|
|
16
|
+
describe("RuntimeFactory", () => {
|
|
17
|
+
describe("runtime type selection", () => {
|
|
18
|
+
it("defaults to SDK runtime when runtime not specified", () => {
|
|
19
|
+
const agent = createTestAgent();
|
|
20
|
+
const runtime = RuntimeFactory.create(agent);
|
|
21
|
+
// Verify it's SDKRuntime by checking constructor name
|
|
22
|
+
expect(runtime.constructor.name).toBe("SDKRuntime");
|
|
23
|
+
});
|
|
24
|
+
it("creates SDK runtime for runtime: sdk", () => {
|
|
25
|
+
const agent = createTestAgent({ runtime: "sdk" });
|
|
26
|
+
const runtime = RuntimeFactory.create(agent);
|
|
27
|
+
expect(runtime.constructor.name).toBe("SDKRuntime");
|
|
28
|
+
});
|
|
29
|
+
it("creates CLI runtime for runtime: cli", () => {
|
|
30
|
+
const agent = createTestAgent({ runtime: "cli" });
|
|
31
|
+
const runtime = RuntimeFactory.create(agent);
|
|
32
|
+
expect(runtime.constructor.name).toBe("CLIRuntime");
|
|
33
|
+
});
|
|
34
|
+
it("throws for unknown runtime type", () => {
|
|
35
|
+
const agent = createTestAgent({ runtime: "unknown" });
|
|
36
|
+
expect(() => RuntimeFactory.create(agent)).toThrow("Unknown runtime type: unknown");
|
|
37
|
+
expect(() => RuntimeFactory.create(agent)).toThrow("Supported types: 'sdk' (default), 'cli'");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("Docker wrapping", () => {
|
|
41
|
+
it("returns base runtime when docker not enabled", () => {
|
|
42
|
+
const agent = createTestAgent({
|
|
43
|
+
runtime: "sdk",
|
|
44
|
+
docker: { enabled: false },
|
|
45
|
+
});
|
|
46
|
+
const runtime = RuntimeFactory.create(agent);
|
|
47
|
+
// Should be SDKRuntime, not ContainerRunner
|
|
48
|
+
expect(runtime.constructor.name).toBe("SDKRuntime");
|
|
49
|
+
});
|
|
50
|
+
it("returns base runtime when docker undefined", () => {
|
|
51
|
+
const agent = createTestAgent({
|
|
52
|
+
runtime: "sdk",
|
|
53
|
+
// No docker config at all
|
|
54
|
+
});
|
|
55
|
+
const runtime = RuntimeFactory.create(agent);
|
|
56
|
+
expect(runtime.constructor.name).toBe("SDKRuntime");
|
|
57
|
+
});
|
|
58
|
+
it("wraps with ContainerRunner when docker.enabled is true", () => {
|
|
59
|
+
const agent = createTestAgent({
|
|
60
|
+
runtime: "sdk",
|
|
61
|
+
docker: { enabled: true },
|
|
62
|
+
});
|
|
63
|
+
const runtime = RuntimeFactory.create(agent, {
|
|
64
|
+
stateDir: "/test/.herdctl",
|
|
65
|
+
});
|
|
66
|
+
// Should be wrapped with ContainerRunner
|
|
67
|
+
expect(runtime.constructor.name).toBe("ContainerRunner");
|
|
68
|
+
});
|
|
69
|
+
it("passes stateDir to ContainerRunner", () => {
|
|
70
|
+
const agent = createTestAgent({
|
|
71
|
+
runtime: "sdk",
|
|
72
|
+
docker: { enabled: true },
|
|
73
|
+
});
|
|
74
|
+
const customStateDir = "/custom/state/dir";
|
|
75
|
+
const runtime = RuntimeFactory.create(agent, {
|
|
76
|
+
stateDir: customStateDir,
|
|
77
|
+
});
|
|
78
|
+
expect(runtime.constructor.name).toBe("ContainerRunner");
|
|
79
|
+
// ContainerRunner has a stateDir property we can check
|
|
80
|
+
expect(runtime.stateDir).toBe(customStateDir);
|
|
81
|
+
});
|
|
82
|
+
it("uses default stateDir when not provided", () => {
|
|
83
|
+
const agent = createTestAgent({
|
|
84
|
+
runtime: "sdk",
|
|
85
|
+
docker: { enabled: true },
|
|
86
|
+
});
|
|
87
|
+
const runtime = RuntimeFactory.create(agent);
|
|
88
|
+
expect(runtime.constructor.name).toBe("ContainerRunner");
|
|
89
|
+
// Default should be {cwd}/.herdctl
|
|
90
|
+
const expectedDefault = process.cwd() + "/.herdctl";
|
|
91
|
+
expect(runtime.stateDir).toBe(expectedDefault);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe("combined scenarios", () => {
|
|
95
|
+
it("wraps SDK with Docker", () => {
|
|
96
|
+
const agent = createTestAgent({
|
|
97
|
+
runtime: "sdk",
|
|
98
|
+
docker: { enabled: true },
|
|
99
|
+
});
|
|
100
|
+
const runtime = RuntimeFactory.create(agent, {
|
|
101
|
+
stateDir: "/test/.herdctl",
|
|
102
|
+
});
|
|
103
|
+
// Should be wrapped with ContainerRunner
|
|
104
|
+
expect(runtime.constructor.name).toBe("ContainerRunner");
|
|
105
|
+
// Has execute method from RuntimeInterface
|
|
106
|
+
expect(typeof runtime.execute).toBe("function");
|
|
107
|
+
});
|
|
108
|
+
it("wraps CLI with Docker", () => {
|
|
109
|
+
const agent = createTestAgent({
|
|
110
|
+
runtime: "cli",
|
|
111
|
+
docker: { enabled: true },
|
|
112
|
+
});
|
|
113
|
+
const runtime = RuntimeFactory.create(agent, {
|
|
114
|
+
stateDir: "/test/.herdctl",
|
|
115
|
+
});
|
|
116
|
+
// Should be wrapped with ContainerRunner
|
|
117
|
+
expect(runtime.constructor.name).toBe("ContainerRunner");
|
|
118
|
+
// Has execute method from RuntimeInterface
|
|
119
|
+
expect(typeof runtime.execute).toBe("function");
|
|
120
|
+
});
|
|
121
|
+
it("CLI without Docker is unwrapped", () => {
|
|
122
|
+
const agent = createTestAgent({
|
|
123
|
+
runtime: "cli",
|
|
124
|
+
docker: { enabled: false },
|
|
125
|
+
});
|
|
126
|
+
const runtime = RuntimeFactory.create(agent);
|
|
127
|
+
expect(runtime.constructor.name).toBe("CLIRuntime");
|
|
128
|
+
});
|
|
129
|
+
it("handles complex Docker config", () => {
|
|
130
|
+
const agent = createTestAgent({
|
|
131
|
+
runtime: "sdk",
|
|
132
|
+
docker: {
|
|
133
|
+
enabled: true,
|
|
134
|
+
image: "custom:latest",
|
|
135
|
+
network: "none",
|
|
136
|
+
memory: "4g",
|
|
137
|
+
ephemeral: true,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
const runtime = RuntimeFactory.create(agent, {
|
|
141
|
+
stateDir: "/test/.herdctl",
|
|
142
|
+
});
|
|
143
|
+
// Verify it creates ContainerRunner (config is private, we can't test it directly)
|
|
144
|
+
expect(runtime.constructor.name).toBe("ContainerRunner");
|
|
145
|
+
expect(typeof runtime.execute).toBe("function");
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=factory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.test.js","sourceRoot":"","sources":["../../../../src/runner/runtime/__tests__/factory.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../../../src/runner/runtime/__tests__/integration.test.ts"],"names":[],"mappings":""}
|