Files
PaperClipAI/server/src/__tests__/managed-config.test.ts
T
Nicky LeachandClaude Opus 5.5 1206373a95 fix(environments): close Apex findings on managed plugin environments (#19526)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A managed instance gets its instance-level environments from the
`PAPERCLIP_MANAGED_CONFIG` document, and #19508 added plugin environment
entries to it
> - Greptile's Apex review of #19508 arrived after it merged, with three
findings
> - A credential inside an array nested in an array passed the secret
check and the response redaction
> - Recovery of an archived environment listened on one worker handle,
which a restart replaces, and its attempts were not tracked through idle
checks and shutdown
> - This pull request closes all three findings
> - The benefit is that credentials never pass the check, an environment
comes back after any worker restart, and shutdown never cuts off a
recovery write

## Linked Issues or Issue Description

Refs #19508 (the Apex findings this pull request fixes)

**Subsystem affected**
Server environments: the managed-config parser, the environment routes'
response floor, the managed environment bootstrap, and the plugin worker
manager.

**Problem or motivation**
Greptile's Apex review of #19508 found three problems. (1)
`findSecretLikeConfigKey` and `redactSecretLikeConfigKeys` skip array
elements that are arrays, so `{"groups":[[{"apiToken":"..."}]]}` passes
the boot check and is echoed to restricted readers. (2) Recovery
subscribes to `ready` on one worker handle. A restart such as a settings
save replaces that handle, so the new worker's `ready` never reaches the
listener, and the environment stays archived. (3) A recovery attempt is
fire-and-forget. The worker manager's work token ends when the worker
replies, but the database write continues, so an idle check or the
database shutdown can overlap it.

**Proposed solution**
Walk arrays at any depth in both functions. Add a manager-wide
`onWorkerReady` subscription and use it for recovery. Run every recovery
attempt through a controller that tracks it as idle work and that
shutdown stops and awaits before the database closes.

**Alternatives considered**
Re-subscribing on each new handle after a restart. That needs a hook in
every restart path. The manager-wide subscription covers all of them in
one place.

**Roadmap alignment**
This only fixes code that #19508 added or touched. It adds no product
surface.

## What Changed

- `server/src/services/managed-config.ts`: `findSecretLikeConfigKey`
walks arrays at any depth (new `findSecretLikeConfigKeyInValue`). This
covers sandbox `config` and plugin `driverConfig`.
- `server/src/routes/environments.ts`: `redactSecretLikeConfigKeys`
walks arrays at any depth (new `redactSecretLikeConfigValue`).
- `server/src/services/plugin-worker-manager.ts`: new optional
`onWorkerReady(listener)` on `PluginWorkerManager`. It fires on every
worker `ready`, including a replacement handle from a restart. A
listener error is logged and does not affect the worker.
- `server/src/services/managed-environments.ts`:
- Sandbox and plugin recovery subscribe through `subscribeWorkerReady`.
It prefers `onWorkerReady` and falls back to the handle when the manager
has no such method.
- New `createManagedEnvironmentRecovery()` controller. Each attempt runs
inside `trackIdleWork` for its whole duration. `stop()` removes every
`ready` subscription, refuses new attempts, and awaits unfinished ones.
- `server/src/index.ts`: creates the controller, passes it to
`applyManagedEnvironments`, and awaits `stop()` during shutdown, after
the delivery workers stop and before the application teardown and
database close.

## Verification

- `cd server && npx vitest run src/__tests__/managed-config.test.ts`: a
secret-like key in an array nested in an array refuses boot, for plugin
`driverConfig` and sandbox `config`.
- `npx vitest run src/__tests__/environment-routes.test.ts`: a
nested-array credential is removed from the response, and other nested
values stay.
- `npx vitest run
src/services/managed-environments-plugin-entries.test.ts`:
- With `onWorkerReady`, recovery never consults the handle. It ignores
another plugin's `ready`, re-ensures on this plugin's `ready`, and then
unsubscribes.
- An attempt counts in `idleWorkSnapshot()` until its ensure settles.
`stop()` unsubscribes, waits for the unfinished attempt, and later
`ready` events start nothing.
- `npx vitest run src/services/managed-environments.test.ts
src/__tests__/managed-plugin-environments.test.ts`: pass.
- `pnpm --filter @paperclipai/server typecheck` passes.
- I did not run the full `pnpm test:run`, `pnpm -r typecheck` or `pnpm
build`. CI covers them.

## Risks

- The redaction now also walks nested arrays in sandbox config
responses. Only credential-shaped keys are removed; other values are
unchanged.
- The boot check now refuses a document that hides a secret-like key in
a nested array. A valid document has no such key.
- `onWorkerReady` is optional, so other `PluginWorkerManager`
implementations and test fakes keep working.
- Shutdown now waits for an unfinished recovery attempt. An attempt is
one worker call plus one short transaction.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, through Claude Code
with tool use (file edits, shell, test runs).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 10:35:57 -08:00

533 lines
23 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
MANAGED_CONFIG_ENV_KEY,
MANAGED_ENVIRONMENT_DRIVERS,
getManagedInstanceConfig,
managedFeatureKeySet,
parseManagedConfigEnv,
} from "../services/managed-config.js";
function envWith(raw: string | undefined) {
return { [MANAGED_CONFIG_ENV_KEY]: raw };
}
function validDoc(overrides: Record<string, unknown> = {}) {
return JSON.stringify({
v: 1,
mode: "cloud",
catalogVersion: "2026.720.0",
features: { enableApps: false, enableStatusCards: true },
plugins: { autoInstall: ["daytona", "kubernetes"] },
...overrides,
});
}
describe("plugins.workerEnv", () => {
const plugins = (workerEnv: unknown) => ({ plugins: { autoInstall: ["daytona"], workerEnv } });
it("is absent from documents that do not declare it", () => {
expect(parseManagedConfigEnv(envWith(validDoc()))?.plugins).toEqual({ autoInstall: ["daytona", "kubernetes"] });
});
it("accepts variable names for an auto-installed plugin", () => {
const parsed = parseManagedConfigEnv(envWith(validDoc(plugins({ daytona: ["PROVIDER_ORIGIN", "PROVIDER_CAPABILITY_2"] }))));
expect(parsed?.plugins.workerEnv).toEqual({ daytona: ["PROVIDER_ORIGIN", "PROVIDER_CAPABILITY_2"] });
});
it.each([
"ANTHROPIC_API_KEY", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "BETTER_AUTH_SECRET", "DATABASE_MIGRATION_URL", "DATABASE_URL", "DB_PASSWORD",
"GH_TOKEN", "GITHUB_TOKEN", "LD_PRELOAD", "NODE_OPTIONS", "PAPERCLIP_AGENT_JWT_SECRET", "PAPERCLIP_AUTH_SECRET", "PAPERCLIP_BACKUP_WORKER_DATABASE_URL",
"PAPERCLIP_CLOUD_CONNECTOR_SIGN_PRIVATE_KEY", "PAPERCLIP_CLOUD_TENANT_SERVER_TOKEN", "PAPERCLIP_DECISION_SIGNING_SECRET", "PAPERCLIP_MANAGED_CONFIG",
"PAPERCLIP_SECRETS_MASTER_KEY", "PAPERCLIP_SECRETS_MASTER_KEY_FILE", "PAPERCLIP_TEST_POSTGRES_ADMIN_URL", "PATH", "SENTRY_DSN",
])("refuses to start with a grant of %s", (name) => {
expect(() => parseManagedConfigEnv(envWith(validDoc(plugins({ daytona: [name] }))))).toThrow(`must not grant host credential or loader variable "${name}"`);
});
it.each(["PAPERCLIP_CLOUD_API_ORIGIN", "PAPERCLIP_PRIMARY_HOST", "PROVIDER_CAPABILITY", "MONKEY_ORIGIN"])("accepts a grant of %s", (name) => {
expect(parseManagedConfigEnv(envWith(validDoc(plugins({ daytona: [name] }))))?.plugins.workerEnv).toEqual({ daytona: [name] });
});
it.each([
["a plugin that is not auto-installed", { other: ["PROVIDER_ORIGIN"] }, /not in "plugins.autoInstall"/],
["a non-object section", ["PROVIDER_ORIGIN"], /must be an object/],
["an empty grant", { daytona: [] }, /non-empty array/],
["a value instead of a name", { daytona: ["https://example.test"] }, /uppercase variable names/],
["a lowercase name", { daytona: ["database_url"] }, /uppercase variable names/],
["a duplicate name", { daytona: ["PROVIDER_ORIGIN", "PROVIDER_ORIGIN"] }, /duplicate entry/],
])("refuses to start with %s", (_label, workerEnv, message) => {
expect(() => parseManagedConfigEnv(envWith(validDoc(plugins(workerEnv))))).toThrow(message);
});
});
describe("plugins.enabledCompanies", () => {
const companyId = "f0679247-e2be-5a76-adb6-6bd360e5a833";
const plugins = (enabledCompanies: unknown) => ({ plugins: { autoInstall: ["daytona"], enabledCompanies } });
it("accepts company ids for an auto-installed plugin", () => {
expect(parseManagedConfigEnv(envWith(validDoc(plugins({ daytona: [companyId] }))))?.plugins.enabledCompanies).toEqual({ daytona: [companyId] });
});
it.each([
["a plugin that is not auto-installed", { other: [companyId] }, /not in "plugins.autoInstall"/],
["a non-object section", [companyId], /must be an object/],
["an empty list", { daytona: [] }, /non-empty array/],
["a value that is not a UUID", { daytona: ["all"] }, /lowercase company UUIDs/],
["an uppercase UUID", { daytona: [companyId.toUpperCase()] }, /lowercase company UUIDs/],
["a duplicate id", { daytona: [companyId, companyId] }, /duplicate entry/],
])("refuses to start with %s", (_label, enabledCompanies, message) => {
expect(() => parseManagedConfigEnv(envWith(validDoc(plugins(enabledCompanies))))).toThrow(message);
});
});
describe("managedFeatureKeySet", () => {
it("contains exactly the boolean flags of the experimental schema", () => {
const keys = managedFeatureKeySet();
expect(keys.has("enableApps")).toBe(true);
expect(keys.has("enableWorktreeRunExecution")).toBe(true);
// Server-managed bookkeeping fields are not overlayable features.
expect(keys.has("worktreeRunExecutionActivatedAt")).toBe(false);
expect(keys.has("worktreeRunExecutionActivationInstanceId")).toBe(false);
});
});
describe("parseManagedConfigEnv", () => {
it("returns null when the env var is absent (self-hosted)", () => {
expect(parseManagedConfigEnv({})).toBeNull();
expect(parseManagedConfigEnv(envWith(undefined))).toBeNull();
});
it("throws when the env var is present but blank (fail closed)", () => {
expect(() => parseManagedConfigEnv(envWith(""))).toThrow(/is set but blank/);
expect(() => parseManagedConfigEnv(envWith(" "))).toThrow(/is set but blank/);
expect(() => parseManagedConfigEnv(envWith("\n\t"))).toThrow(/is set but blank/);
});
it("parses a complete valid document", () => {
const config = parseManagedConfigEnv(envWith(validDoc()));
expect(config).toEqual({
v: 1,
mode: "cloud",
catalogVersion: "2026.720.0",
features: { enableApps: false, enableStatusCards: true },
plugins: { autoInstall: ["daytona", "kubernetes"] },
environments: [],
pluginEnvironments: [],
});
});
it("accepts the deprecated runner ingress key for managed-config compatibility", () => {
const config = parseManagedConfigEnv(
envWith(validDoc({ features: { enableRunnerPreviewIngress: true } })),
);
expect(config?.features).toEqual({ enableRunnerPreviewIngress: true });
});
it("accepts empty features {} and autoInstall [] sections", () => {
const config = parseManagedConfigEnv(
envWith(validDoc({ features: {}, plugins: { autoInstall: [] } })),
);
expect(config).toEqual({
v: 1,
mode: "cloud",
catalogVersion: "2026.720.0",
features: {},
plugins: { autoInstall: [] },
environments: [],
pluginEnvironments: [],
});
});
it("throws when the features section is missing (fail closed)", () => {
const doc = { v: 1, mode: "cloud", catalogVersion: "2026.720.0", plugins: { autoInstall: [] } };
expect(() => parseManagedConfigEnv(envWith(JSON.stringify(doc)))).toThrow(
/requires a "features" object/,
);
});
it("throws when the plugins section or autoInstall is missing (fail closed)", () => {
const noPlugins = {
v: 1,
mode: "cloud",
catalogVersion: "2026.720.0",
features: {},
};
expect(() => parseManagedConfigEnv(envWith(JSON.stringify(noPlugins)))).toThrow(
/requires a "plugins" object/,
);
expect(() => parseManagedConfigEnv(envWith(validDoc({ plugins: {} })))).toThrow(
/requires a "plugins.autoInstall" array/,
);
});
it("returns a frozen document", () => {
const config = parseManagedConfigEnv(envWith(validDoc()));
expect(Object.isFrozen(config)).toBe(true);
expect(Object.isFrozen(config?.features)).toBe(true);
expect(Object.isFrozen(config?.plugins.autoInstall)).toBe(true);
});
it("throws on invalid JSON", () => {
expect(() => parseManagedConfigEnv(envWith("{not json"))).toThrow(
/PAPERCLIP_MANAGED_CONFIG is not valid JSON/,
);
});
it("throws on non-object documents", () => {
expect(() => parseManagedConfigEnv(envWith("[]"))).toThrow(/must be a JSON object/);
expect(() => parseManagedConfigEnv(envWith("42"))).toThrow(/must be a JSON object/);
expect(() => parseManagedConfigEnv(envWith("null"))).toThrow(/must be a JSON object/);
expect(() => parseManagedConfigEnv(envWith('"cloud"'))).toThrow(/must be a JSON object/);
});
it("throws on an unknown top-level key", () => {
expect(() => parseManagedConfigEnv(envWith(validDoc({ extra: true })))).toThrow(
/unknown top-level key "extra"/,
);
});
it("throws on an unsupported v", () => {
expect(() => parseManagedConfigEnv(envWith(validDoc({ v: 2 })))).toThrow(
/unsupported "v" 2; this build supports v=1/,
);
expect(() => parseManagedConfigEnv(envWith(validDoc({ v: "1" })))).toThrow(/unsupported "v"/);
expect(() =>
parseManagedConfigEnv(
envWith(JSON.stringify({ mode: "cloud", catalogVersion: "x" })),
),
).toThrow(/unsupported "v"/);
});
it("throws on a non-cloud mode", () => {
expect(() => parseManagedConfigEnv(envWith(validDoc({ mode: "self-hosted" })))).toThrow(
/invalid "mode" "self-hosted"; expected "cloud"/,
);
expect(() =>
parseManagedConfigEnv(envWith(JSON.stringify({ v: 1, catalogVersion: "x" }))),
).toThrow(/invalid "mode"/);
});
it("throws on a missing or empty catalogVersion", () => {
expect(() =>
parseManagedConfigEnv(envWith(JSON.stringify({ v: 1, mode: "cloud" }))),
).toThrow(/non-empty string "catalogVersion"/);
expect(() => parseManagedConfigEnv(envWith(validDoc({ catalogVersion: "" })))).toThrow(
/non-empty string "catalogVersion"/,
);
expect(() => parseManagedConfigEnv(envWith(validDoc({ catalogVersion: 7 })))).toThrow(
/non-empty string "catalogVersion"/,
);
});
it("throws on a non-object features section", () => {
expect(() => parseManagedConfigEnv(envWith(validDoc({ features: ["enableApps"] })))).toThrow(
/"features" must be an object/,
);
});
it.each([true, false])("ignores the retired Pipelines flag (%s) from older Cloud catalogs", (enabled) => {
const config = parseManagedConfigEnv(envWith(validDoc({
features: { enablePipelines: enabled, enableCases: true },
})));
expect(config?.features).toEqual({ enableCases: true });
expect(managedFeatureKeySet().has("enablePipelines")).toBe(false);
});
it("throws on an unknown feature key", () => {
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ features: { enableTimeTravel: true } }))),
).toThrow(/unknown feature key "enableTimeTravel"/);
// A server-managed bookkeeping field is not an overlayable feature.
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ features: { worktreeRunExecutionActivatedAt: true } })),
),
).toThrow(/unknown feature key "worktreeRunExecutionActivatedAt"/);
});
it("throws on a feature key the catalog does not mark tier \"managed\"", () => {
// `enableStreamlinedLeftNavigation` is a real schema flag, but its catalog
// tier is `preference` (tenant-controllable) — a managed-config document
// targeting it has incompatible catalog semantics and must fail closed.
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ features: { enableStreamlinedLeftNavigation: true } })),
),
).toThrow(
/"features" key "enableStreamlinedLeftNavigation" has tier "preference".*only tier "managed" keys/,
);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ features: { enableDecisions: false } }))),
).toThrow(/has tier "preference"/);
});
it("throws on non-boolean feature values", () => {
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ features: { enableApps: "true" } }))),
).toThrow(/"features.enableApps" must be a boolean/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ features: { enableApps: 1 } }))),
).toThrow(/"features.enableApps" must be a boolean/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ features: { enableApps: null } }))),
).toThrow(/"features.enableApps" must be a boolean/);
});
it("throws on malformed plugins sections", () => {
expect(() => parseManagedConfigEnv(envWith(validDoc({ plugins: [] })))).toThrow(
/"plugins" must be an object/,
);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ plugins: { install: [] } }))),
).toThrow(/"plugins" has unknown key "install"/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ plugins: { autoInstall: "daytona" } }))),
).toThrow(/"plugins.autoInstall" must be an array/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ plugins: { autoInstall: [""] } }))),
).toThrow(/non-empty strings/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ plugins: { autoInstall: [" daytona"] } }))),
).toThrow(/non-empty strings/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ plugins: { autoInstall: [42] } }))),
).toThrow(/non-empty strings/);
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ plugins: { autoInstall: ["daytona", "daytona"] } })),
),
).toThrow(/duplicate entry "daytona"/);
});
});
describe("parseManagedConfigEnv environments section", () => {
const entry = (overrides: Record<string, unknown> = {}) => ({
name: "Daytona",
provider: "daytona",
config: { target: "us" },
...overrides,
});
it("defaults to an empty list when the section is absent (pre-section documents keep booting)", () => {
const config = parseManagedConfigEnv(envWith(validDoc()));
expect(config?.environments).toEqual([]);
});
it("parses a declared environment and freezes it", () => {
const config = parseManagedConfigEnv(
envWith(validDoc({ environments: [entry({ description: "Managed Daytona sandbox." })] })),
);
expect(config?.environments).toHaveLength(1);
const spec = config?.environments[0];
expect(spec?.name).toBe("Daytona");
expect(spec?.description).toBe("Managed Daytona sandbox.");
expect(spec?.provider).toBe("daytona");
expect(spec?.config).toEqual({ target: "us" });
expect(Object.isFrozen(config?.environments)).toBe(true);
expect(Object.isFrozen(spec)).toBe(true);
expect(Object.isFrozen(spec?.config)).toBe(true);
});
it("treats config and description as optional", () => {
const config = parseManagedConfigEnv(
envWith(validDoc({ environments: [{ name: "Daytona", provider: "daytona" }] })),
);
expect(config?.environments[0]?.config).toEqual({});
expect(config?.environments[0]?.description).toBeUndefined();
});
it("rejects a non-array section and non-object entries", () => {
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: {} }))),
).toThrow(/"environments" must be an array/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: ["daytona"] }))),
).toThrow(/"environments\[0\]" must be an object/);
});
it("rejects more than one sandbox entry (single managed sandbox slot)", () => {
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ environments: [entry(), entry({ name: "Other", provider: "kubernetes" })] })),
),
).toThrow(/at most one sandbox entry/);
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ environments: [entry(), entry({ name: "Other", driver: "sandbox", provider: "kubernetes" })] })),
),
).toThrow(/at most one sandbox entry/);
});
it("rejects unknown entry keys", () => {
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: [entry({ envVars: {} })] }))),
).toThrow(/unknown key "envVars"/);
});
it("rejects malformed names, descriptions, and providers", () => {
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: [entry({ name: "" })] }))),
).toThrow(/"environments\[0\].name"/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: [entry({ name: " Daytona" })] }))),
).toThrow(/"environments\[0\].name"/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: [entry({ description: " " })] }))),
).toThrow(/"environments\[0\].description"/);
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: [entry({ provider: 7 })] }))),
).toThrow(/"environments\[0\].provider"/);
});
it("rejects a provider that plugins.autoInstall does not provision", () => {
expect(() =>
parseManagedConfigEnv(envWith(validDoc({ environments: [entry({ provider: "modal" })] }))),
).toThrow(/not in "plugins.autoInstall"/);
});
it("rejects a config that sets provider", () => {
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ environments: [entry({ config: { provider: "daytona" } })] })),
),
).toThrow(/must not set "provider"/);
});
it("rejects secret-bearing config keys at any depth (secrets travel as env vars)", () => {
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ environments: [entry({ config: { apiKey: "not-a-real-key" } })] })),
),
).toThrow(/looks secret-bearing/);
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ environments: [entry({ config: { auth: { accessToken: "t" } } })] })),
),
).toThrow(/auth.accessToken/);
expect(() =>
parseManagedConfigEnv(
envWith(
validDoc({ environments: [entry({ config: { adapters: [{ clientSecret: "s" }] } })] }),
),
),
).toThrow(/adapters\[0\].clientSecret/);
expect(() =>
parseManagedConfigEnv(
envWith(validDoc({ environments: [entry({ config: { pools: [[], [{ privateKey: { password: "s" } }]] } })] })),
),
).toThrow(/pools\[1\]\[0\].privateKey.password/);
});
});
describe("parseManagedConfigEnv plugin environment entries", () => {
const PLUGIN_KEY = "example.remote-host-plugin";
const remoteHost = (overrides: Record<string, unknown> = {}) => ({
name: "Remote Host",
description: "Runs the agent on a remote host",
driver: "plugin",
pluginKey: PLUGIN_KEY,
driverKey: "tasks",
driverConfig: {},
...overrides,
});
const sandbox = { name: "Managed Sandbox", provider: "daytona", config: { target: "us" } };
// `plugins.autoInstall` holds catalog keys ("remote-host"); the entry's
// `pluginKey` is the plugin's manifest id, which boot maps through the catalog.
const docWith = (environments: unknown[], autoInstall = ["daytona", "remote-host"]) =>
envWith(validDoc({ plugins: { autoInstall }, environments }));
it("lists the drivers an entry may declare", () => {
expect(MANAGED_ENVIRONMENT_DRIVERS).toEqual(["sandbox", "plugin"]);
});
it("parses an old document's sandbox entry unchanged", () => {
const config = parseManagedConfigEnv(docWith([sandbox]));
expect(config?.environments).toEqual([{ name: "Managed Sandbox", provider: "daytona", config: { target: "us" } }]);
expect(config?.pluginEnvironments).toEqual([]);
});
it("parses the sandbox entry beside a plugin entry", () => {
const config = parseManagedConfigEnv(docWith([sandbox, remoteHost()]));
expect(config?.environments).toEqual([{ name: "Managed Sandbox", provider: "daytona", config: { target: "us" } }]);
expect(config?.pluginEnvironments).toEqual([{
driver: "plugin",
name: "Remote Host",
description: "Runs the agent on a remote host",
pluginKey: PLUGIN_KEY,
driverKey: "tasks",
driverConfig: {},
}]);
expect(Object.isFrozen(config?.pluginEnvironments)).toBe(true);
expect(Object.isFrozen(config?.pluginEnvironments[0])).toBe(true);
});
it("parses a plugin entry alone, with optional fields omitted", () => {
const config = parseManagedConfigEnv(docWith([{ name: "Remote", driver: "plugin", pluginKey: PLUGIN_KEY, driverKey: "tasks" }]));
expect(config?.environments).toEqual([]);
expect(config?.pluginEnvironments[0]).toMatchObject({ driverConfig: {} });
expect(config?.pluginEnvironments[0]?.description).toBeUndefined();
});
it("does not compare the manifest id with autoInstall catalog keys (boot checks the catalog)", () => {
expect(parseManagedConfigEnv(docWith([remoteHost()]))?.pluginEnvironments[0]?.pluginKey).toBe(PLUGIN_KEY);
});
it("refuses duplicate names, including across drivers", () => {
expect(() => parseManagedConfigEnv(docWith([sandbox, remoteHost({ name: "Managed Sandbox" })])))
.toThrow(/"environments\[1\].name" duplicates another entry's name/);
});
it("refuses a duplicate pluginKey and driverKey pair", () => {
expect(() => parseManagedConfigEnv(docWith([remoteHost(), remoteHost({ name: "Second" })])))
.toThrow(/duplicates another plugin entry's pluginKey and driverKey/);
});
it("refuses secret-like driverConfig keys at any depth", () => {
expect(() => parseManagedConfigEnv(docWith([remoteHost({ driverConfig: { apiToken: "t" } })])))
.toThrow(/"environments\[0\].driverConfig" key "apiToken" looks secret-bearing/);
expect(() => parseManagedConfigEnv(docWith([remoteHost({ driverConfig: { auth: [{ password: "p" }] } })])))
.toThrow(/auth\[0\].password/);
expect(() => parseManagedConfigEnv(docWith([remoteHost({ driverConfig: { groups: [[{ apiToken: "t" }]] } })])))
.toThrow(/groups\[0\]\[0\].apiToken/);
});
it("refuses unknown keys, including sandbox keys on a plugin entry and the reverse", () => {
expect(() => parseManagedConfigEnv(docWith([remoteHost({ envVars: {} })]))).toThrow(/unknown key "envVars"/);
expect(() => parseManagedConfigEnv(docWith([remoteHost({ provider: "daytona" })]))).toThrow(/unknown key "provider"/);
expect(() => parseManagedConfigEnv(docWith([{ ...sandbox, pluginKey: PLUGIN_KEY }]))).toThrow(/unknown key "pluginKey"/);
// Not supported by this build on either entry.
expect(() => parseManagedConfigEnv(docWith([remoteHost({ instanceDefault: true })]))).toThrow(/unknown key "instanceDefault"/);
expect(() => parseManagedConfigEnv(docWith([{ ...sandbox, instanceDefault: false }]))).toThrow(/unknown key "instanceDefault"/);
});
it("refuses an unknown driver and malformed plugin fields", () => {
expect(() => parseManagedConfigEnv(docWith([remoteHost({ driver: "ssh" })]))).toThrow(/"environments\[0\].driver" must be one of "sandbox", "plugin"/);
expect(() => parseManagedConfigEnv(docWith([{ ...sandbox, driver: null }]))).toThrow(/"environments\[0\].driver" must be one of "sandbox", "plugin" when present \(got null\)/);
expect(() => parseManagedConfigEnv(docWith([remoteHost({ driverKey: "Tasks" })]))).toThrow(/"environments\[0\].driverKey" must start/);
expect(() => parseManagedConfigEnv(docWith([remoteHost({ driverKey: undefined })]))).toThrow(/"environments\[0\].driverKey" must be a non-empty string/);
expect(() => parseManagedConfigEnv(docWith([remoteHost({ driverConfig: [] })]))).toThrow(/"environments\[0\].driverConfig" must be an object/);
});
});
describe("getManagedInstanceConfig", () => {
it("caches by raw env value and reparses when it changes", () => {
const raw = validDoc();
const first = getManagedInstanceConfig(envWith(raw));
const second = getManagedInstanceConfig(envWith(raw));
expect(second).toBe(first);
const changed = getManagedInstanceConfig(
envWith(validDoc({ catalogVersion: "2026.721.0" })),
);
expect(changed?.catalogVersion).toBe("2026.721.0");
expect(changed).not.toBe(first);
expect(getManagedInstanceConfig(envWith(undefined))).toBeNull();
});
it("rethrows parse failures on every call instead of caching them", () => {
expect(() => getManagedInstanceConfig(envWith("{bad"))).toThrow(/not valid JSON/);
expect(() => getManagedInstanceConfig(envWith("{bad"))).toThrow(/not valid JSON/);
});
});