Fix detached process startup in docker-sandbox.ts: capture the real process group PID via setsid, redirect stdout/stderr to durable log files, refresh status and exit code after natural completion, make getProcessLogs return real logs, and implement bounded TERM/KILL cleanup with no leftover containers. Switch the adapter to node:child_process (supported by Bun) so tests execute under vitest, add -i to docker exec so staged files reach cat, and assert the launcher is nonempty before launch. Ensure Orb creation disposes the VM before its sandbox on partial failure (AgentOS creation or OpenCode linking), and dispose the VM before its sandbox in OrbHandle.dispose. Fix the Effect state callbacks (tapError/sync/asVoid) and prepareRepository branch/base shell quoting. Split normalizeSessionEvent to stay under the complexity limit without suppressing the rule. Raw outbound prompts stay unchanged; only persisted and logged event copies are redacted. Rewrite scripts/orb-proof.ts to emit explicit stable stage markers for Docker, AgentOS/OpenCode, and the model turn; ORB_GATEWAY_* fall back safely to AGENT_MODEL_* without printing secrets; an unreachable gateway is BLOCKED not passed; container removal is verified after disposal. Strengthen tests: drop the any-failure createOrb test and add focused Docker lifecycle coverage (PID, logs, status, exit code, stop/kill, removal) guarded only when Docker is unavailable.
83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
/* eslint-disable no-non-null-assertion -- test assertions on defined objects */
|
|
import { Effect } from "effect";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { OrbConfigurationError } from "./domain";
|
|
import {
|
|
opencodeSetupCommands,
|
|
prepareOpenCodeConfig,
|
|
} from "./opencode-config";
|
|
|
|
const validGateway = {
|
|
apiKey: "test-key-123",
|
|
baseUrl: "https://gateway.example.com/v1",
|
|
model: "test-model",
|
|
provider: "test-provider",
|
|
};
|
|
|
|
const validContext = {
|
|
artifacts: [],
|
|
contextFiles: [],
|
|
issueBody: "Fix the bug",
|
|
issueTitle: "Bug fix",
|
|
repositoryUrl: undefined,
|
|
};
|
|
|
|
describe("prepareOpenCodeConfig", () => {
|
|
it("produces valid config JSON with provider and model", () => {
|
|
const result = Effect.runSync(
|
|
prepareOpenCodeConfig({
|
|
context: validContext,
|
|
gateway: validGateway,
|
|
})
|
|
);
|
|
const parsed = JSON.parse(result.configJson);
|
|
expect(parsed.model).toBe("test-provider/test-model");
|
|
expect(parsed.provider["test-provider"].baseUrl).toBe(
|
|
"https://gateway.example.com/v1"
|
|
);
|
|
expect(parsed.provider["test-provider"].apiKey).toBe("test-key-123");
|
|
});
|
|
|
|
it("sets config path under opencode config directory", () => {
|
|
const result = Effect.runSync(
|
|
prepareOpenCodeConfig({
|
|
context: validContext,
|
|
gateway: validGateway,
|
|
})
|
|
);
|
|
expect(result.configPath).toContain("opencode");
|
|
expect(result.configPath).toContain("config.json");
|
|
expect(result.instructionsPath).toBe("/workspace/control/issue.md");
|
|
});
|
|
|
|
it("rejects empty base URL", () => {
|
|
const error = Effect.runSync(
|
|
Effect.flip(
|
|
prepareOpenCodeConfig({
|
|
context: validContext,
|
|
gateway: { ...validGateway, baseUrl: " " },
|
|
})
|
|
)
|
|
);
|
|
expect(error).toBeInstanceOf(OrbConfigurationError);
|
|
expect(error.reason).toBe("InvalidModelConfig");
|
|
});
|
|
});
|
|
|
|
describe("opencodeSetupCommands", () => {
|
|
it("produces mkdir, write, and chmod commands", () => {
|
|
const config = Effect.runSync(
|
|
prepareOpenCodeConfig({
|
|
context: validContext,
|
|
gateway: validGateway,
|
|
})
|
|
);
|
|
const commands = opencodeSetupCommands(config);
|
|
expect(commands.length).toBe(3);
|
|
expect(commands[0]).toContain("mkdir");
|
|
expect(commands[1]).toContain("cat >");
|
|
expect(commands[2]).toContain("chmod 600");
|
|
});
|
|
});
|