From 4ad94d0bde593c6d1b678228cafc6a8d6c87ffb4 Mon Sep 17 00:00:00 2001 From: Jannes Stubbemann Date: Thu, 11 Jun 2026 06:09:02 +0200 Subject: [PATCH] feat(server): kubernetes execution integration for sandbox-provider plugins (stage 2/3) (#7938) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The execution subsystem runs those agents in environments (local, ssh, sandbox), and sandbox-provider plugins let an environment materialize per-run sandboxes > - Stage 1 (#5790) contributed a first-party Kubernetes sandbox-provider plugin, but the server core has no way to adopt it operationally: no per-run adapter selection, no way to force an instance onto sandboxed execution, no declarative adapter/model configuration, and the plugin must be installed by hand > - Without this, a multi-tenant or security-conscious deployment cannot guarantee that agent runs never execute on the host, and a single environment cannot serve agents with different harnesses > - This pull request adds the server + SDK integration: per-run adapterType on the lease protocol, an env-gated forced-Kubernetes execution policy with provisioning and a per-run allowlist guard, a declarative adapter registry and model list, in-cluster env passthrough for sandbox plugin workers, fail-safe auto-install of the bundled plugin, and the matching UI affordance > - The benefit is that sandbox-provider plugins become fully usable for Kubernetes execution: operators configure everything via environment variables and GitOps, while self-hosters who set none of the variables see exactly the behavior they have today ## Linked Issues or Issue Description Refs #5790 (stage 1 of 3: the Kubernetes sandbox-provider plugin package). No existing issue. Feature description: the server core lacks the integration seams to operate a sandbox-provider plugin as the mandatory execution path of an instance. This PR is stage 2 of 3 of the staged Kubernetes contribution; stage 3 will contribute the agent runtime images and their build pipeline. ## What Changed One line per piece: - `packages/plugins/sdk/protocol.ts`: optional `adapterType` on `PluginEnvironmentAcquireLeaseParams` so a provider can select the runtime image per run; existing providers simply ignore it - `server/services/environment-runtime.ts` + `environment-run-orchestrator.ts`: thread the agent's adapter type into both lease-acquiring drivers, including the heartbeat path (the two call sites have historically drifted, hence the pinned test) - `server/services/environments.ts`: `ensureKubernetesEnvironment` / `findKubernetesEnvironment`, an idempotent managed Kubernetes environment per company, identified by a metadata marker and refreshed (not recreated) on config change; `timeoutMs` rides on the config for slow cold-start leases - `server/services/execution-allowlist.ts`: pure (driver, provider, policy) -> allow/deny guard; `executionMode=kubernetes` only allows the kubernetes sandbox provider - `server/services/execution-policy-bootstrap.ts` + startup hook in `server/index.ts`: parse `PAPERCLIP_EXECUTION_MODE` / `PAPERCLIP_K8S_*`, persist `executionMode` into instance general settings, and provision the managed environment for every company; fails loud on misconfiguration - `server/services/heartbeat.ts`: when the policy forces Kubernetes, pin run selection to the managed environment (also overriding any persisted workspace environment id), refuse to fall back to local, and re-check the actually acquired environment against the allowlist as defense in depth - `server/services/adapter-registry-bootstrap.ts` + shared `AdapterRegistryEntry` type/validator: declarative `PAPERCLIP_ADAPTERS` registry (inline JSON or file) that reconciles adapter availability at startup and rides on the Kubernetes environment config - `server/services/adapter-models-env.ts` + `adapters/registry.ts`: `PAPERCLIP_ADAPTER_MODELS` lets an operator declare picker model lists the server cannot CLI-discover - `server/services/plugin-loader.ts`: pass `KUBERNETES_SERVICE_HOST/PORT(_HTTPS)` through to plugin workers that register environment drivers, so in-cluster API clients can be constructed; all other host env stays stripped - `server/app.ts`: fail-safe auto-install of the bundled kubernetes plugin at boot; no-ops when the bundle is absent and never blocks startup on error - `packages/shared` types/validators: `InstanceExecutionMode` on general settings (optional, strict schema) - `ui/lib/forced-kubernetes-environment.ts` + `AgentConfigForm`: when the policy is active, show a read-only Kubernetes environment instead of the environment picker and default new agents onto the managed environment - Tests for every new module plus the adapterType pin in `heartbeat-plugin-environment` and the managed-environment lifecycle in `environment-service` Everything is gated: with `PAPERCLIP_EXECUTION_MODE`, `PAPERCLIP_ADAPTERS`, and `PAPERCLIP_ADAPTER_MODELS` unset (and no bundled plugin present), every code path reduces to current behavior. The per-run `adapterType` is an optional SDK parameter that existing providers ignore. ## Verification - `cd server && npx tsc --noEmit`: clean (0 errors); `ui` typecheck also clean - Targeted suites all green (11 files, 90 tests): `npx vitest run server/src/__tests__/heartbeat-plugin-environment.test.ts server/src/__tests__/environment-service.test.ts server/src/__tests__/environment-runtime.test.ts server/src/__tests__/environment-run-orchestrator.test.ts server/src/__tests__/plugin-database.test.ts server/src/services/execution-policy-bootstrap.test.ts server/src/services/execution-allowlist.test.ts server/src/services/adapter-registry-bootstrap.test.ts server/src/services/adapter-registry-bootstrap.reconcile.test.ts server/src/services/adapter-models-env.test.ts packages/shared/src/validators/adapter-registry.test.ts` - `npx vitest run ui/src/components/AgentConfigForm.test.ts`: green (6 tests) - Full `npx vitest run server/src/__tests__`: 2323 passed, 1 skipped; the only failures (heartbeat-process-recovery pid-retry, workspace-runtime symbolic-ref/git tests) reproduce identically on pristine `master` in the same environment, so they are machine-environment issues unrelated to this change; `server-startup-feedback-export` needed its `services/index.js` mock extended with the new export and is green - This integration has been running in production on a hosted multi-tenant deployment, where it executes agent runs across five different harnesses through the stage 1 plugin ## Risks - Low for existing deployments: every behavior is env-gated and the defaults preserve current semantics; the auto-install block is wrapped fail-safe and skips silently when the plugin bundle is absent - `executionMode` is a new optional field on a strict zod schema; absent input normalizes exactly as before - The forced policy intentionally fails runs loudly (rather than falling back to local) when no managed Kubernetes environment exists; this only affects instances that explicitly set `PAPERCLIP_EXECUTION_MODE=kubernetes` ## Model Used Claude Opus 4.8 (claude-opus-4-8, 1M context), extended thinking, agentic tool use via Claude Code. ## UI screenshots The UI change is a new read-only "Execution" section in `AgentConfigForm`, shown only when the instance execution policy forces Kubernetes (`executionMode=kubernetes`); there is no "before" state for it (the section did not exist, and instances without the forced policy render the existing picker unchanged). Captured from the new Storybook stories added in this PR (`Product/Agent Management`): Managed Kubernetes environment present (read-only display, no local/SSH picker): ![AgentConfigForm with forced Kubernetes execution](https://raw.githubusercontent.com/paperclipinc/paperclip/296ad06e8/screenshots/PR-7938-agent-config-forced-kubernetes.png) No managed environment available yet (warning notice, no silent local fallback): ![AgentConfigForm forced Kubernetes, missing environment warning](https://raw.githubusercontent.com/paperclipinc/paperclip/296ad06e8/screenshots/PR-7938-agent-config-forced-kubernetes-missing-env.png) ## 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 run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] 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 4.8 (1M context) --- packages/plugins/sdk/src/protocol.ts | 7 + packages/shared/src/index.ts | 9 + packages/shared/src/types/adapter-registry.ts | 30 +++ packages/shared/src/types/index.ts | 1 + packages/shared/src/types/instance.ts | 18 ++ .../src/validators/adapter-registry.test.ts | 34 +++ .../shared/src/validators/adapter-registry.ts | 17 ++ packages/shared/src/validators/instance.ts | 3 + ...t-config-forced-kubernetes-missing-env.png | Bin 0 -> 107274 bytes ...PR-7938-agent-config-forced-kubernetes.png | Bin 0 -> 97462 bytes server/src/__tests__/adapter-models.test.ts | 62 +++++- .../src/__tests__/environment-service.test.ts | 130 +++++++++++- .../heartbeat-plugin-environment.test.ts | 6 + server/src/__tests__/plugin-database.test.ts | 20 ++ .../server-startup-feedback-export.test.ts | 1 + server/src/adapters/registry.ts | 36 ++++ server/src/app.ts | 62 +++++- server/src/index.ts | 38 ++++ .../src/services/adapter-models-env.test.ts | 30 +++ server/src/services/adapter-models-env.ts | 40 ++++ ...apter-registry-bootstrap.reconcile.test.ts | 44 ++++ .../adapter-registry-bootstrap.test.ts | 31 +++ .../services/adapter-registry-bootstrap.ts | 97 +++++++++ .../services/environment-run-orchestrator.ts | 2 + server/src/services/environment-runtime.ts | 19 ++ server/src/services/environments.ts | 163 ++++++++++++++- .../src/services/execution-allowlist.test.ts | 96 +++++++++ server/src/services/execution-allowlist.ts | 103 ++++++++++ .../execution-policy-bootstrap.test.ts | 168 +++++++++++++++ .../services/execution-policy-bootstrap.ts | 194 ++++++++++++++++++ server/src/services/heartbeat.ts | 104 +++++++++- server/src/services/index.ts | 1 + server/src/services/instance-settings.ts | 2 + server/src/services/plugin-loader.ts | 27 ++- ui/src/components/AgentConfigForm.test.ts | 57 +++++ ui/src/components/AgentConfigForm.tsx | 66 +++++- ui/src/lib/forced-kubernetes-environment.ts | 56 +++++ .../stories/agent-management.stories.tsx | 86 ++++++++ 38 files changed, 1851 insertions(+), 9 deletions(-) create mode 100644 packages/shared/src/types/adapter-registry.ts create mode 100644 packages/shared/src/validators/adapter-registry.test.ts create mode 100644 packages/shared/src/validators/adapter-registry.ts create mode 100644 screenshots/PR-7938-agent-config-forced-kubernetes-missing-env.png create mode 100644 screenshots/PR-7938-agent-config-forced-kubernetes.png create mode 100644 server/src/services/adapter-models-env.test.ts create mode 100644 server/src/services/adapter-models-env.ts create mode 100644 server/src/services/adapter-registry-bootstrap.reconcile.test.ts create mode 100644 server/src/services/adapter-registry-bootstrap.test.ts create mode 100644 server/src/services/adapter-registry-bootstrap.ts create mode 100644 server/src/services/execution-allowlist.test.ts create mode 100644 server/src/services/execution-allowlist.ts create mode 100644 server/src/services/execution-policy-bootstrap.test.ts create mode 100644 server/src/services/execution-policy-bootstrap.ts create mode 100644 ui/src/lib/forced-kubernetes-environment.ts diff --git a/packages/plugins/sdk/src/protocol.ts b/packages/plugins/sdk/src/protocol.ts index 92fcbf42..5607b470 100644 --- a/packages/plugins/sdk/src/protocol.ts +++ b/packages/plugins/sdk/src/protocol.ts @@ -478,6 +478,13 @@ export interface PluginEnvironmentAcquireLeaseParams extends PluginEnvironmentDr runId: string; workspaceMode?: string; requestedCwd?: string; + /** + * The harness/adapter type for THIS run (the agent's adapter), so a single + * environment can serve mixed harnesses. When omitted, the driver falls back to + * the environment's configured default adapter. A provider that materializes a + * per-run sandbox should use this to select the runtime image and per-run env. + */ + adapterType?: string; } export interface PluginEnvironmentResumeLeaseParams extends PluginEnvironmentDriverBaseParams { diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 74b55c61..0a1d3f79 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -393,6 +393,7 @@ export type { AgentSkillEntry, AgentSkillSnapshot, AgentSkillSyncRequest, + InstanceExecutionMode, InstanceExperimentalSettings, InstanceGeneralSettings, InstanceSettings, @@ -1400,3 +1401,11 @@ export type { EnvironmentProviderCapability, EnvironmentSupportStatus, } from "./environment-support.js"; + +export type { AdapterRegistryEntry } from "./types/adapter-registry.js"; + +export { + adapterRegistryEntrySchema, + adapterRegistrySchema, + type AdapterRegistryEntryParsed, +} from "./validators/adapter-registry.js"; diff --git a/packages/shared/src/types/adapter-registry.ts b/packages/shared/src/types/adapter-registry.ts new file mode 100644 index 00000000..bd9b0a1f --- /dev/null +++ b/packages/shared/src/types/adapter-registry.ts @@ -0,0 +1,30 @@ +/** + * One declarative agent-harness ("adapter") entry. The same shape is used for + * local self-hosting and our operator/cloud: it governs both availability (the + * picker) and, when the run is sandboxed on Kubernetes, the runtime wiring. + * + * Replace semantics: when a registry is supplied it is the COMPLETE declared + * set. Adopt (built-in defaults) = no registry at all. Remove = omit the entry. + * Add = include a new entry. Override = redefine an existing adapterType. + */ +export interface AdapterRegistryEntry { + /** The harness, e.g. "opencode_local". */ + adapterType: string; + /** Availability (both local + k8s). Default true. */ + enabled?: boolean; + /** k8s-sandbox-only: container image the Job/Sandbox runs. */ + runtimeImage?: string; + /** k8s-sandbox-only: process-env keys forwarded into the Job (e.g. ANTHROPIC_API_KEY). */ + envKeys?: string[]; + /** k8s-sandbox-only: egress FQDN allow-list for the agent pod. */ + allowFqdns?: string[]; + /** k8s-sandbox-only: liveness/probe command. */ + probeCommand?: string[]; + /** + * Non-secret env injected into the Job/Sandbox as the BASE; the process-env + * values (the secret API key, via envKeys) override it. Carries e.g. + * ANTHROPIC_BASE_URL pointing at the in-cluster Bifrost gateway. NEVER put + * secrets here. + */ + defaultEnv?: Record; +} diff --git a/packages/shared/src/types/index.ts b/packages/shared/src/types/index.ts index fead54e4..5fc8b5f8 100644 --- a/packages/shared/src/types/index.ts +++ b/packages/shared/src/types/index.ts @@ -24,6 +24,7 @@ export type { FeedbackTraceBundle, } from "./feedback.js"; export type { + InstanceExecutionMode, InstanceExperimentalSettings, InstanceGeneralSettings, InstanceSettings, diff --git a/packages/shared/src/types/instance.ts b/packages/shared/src/types/instance.ts index 0a6c946c..05e6270a 100644 --- a/packages/shared/src/types/instance.ts +++ b/packages/shared/src/types/instance.ts @@ -19,11 +19,29 @@ export const DEFAULT_BACKUP_RETENTION: BackupRetentionPolicy = { monthlyMonths: 1, }; +/** + * Instance-wide execution policy. + * + * - `"any"` (default / absent): unrestricted โ€” any environment driver (local, + * ssh, sandbox) may run agents. Preserves single-tenant / local-trusted + * behavior. + * - `"kubernetes"`: force ALL agent execution onto the Kubernetes + * sandbox-provider environment and REFUSE local/in-process execution. Used by + * shared cloud (cloud_tenant) instances so untrusted tenant agents can never + * run in the server process or on an unsandboxed local/ssh adapter. + */ +export type InstanceExecutionMode = "kubernetes" | "any"; + export interface InstanceGeneralSettings { censorUsernameInLogs: boolean; keyboardShortcuts: boolean; feedbackDataSharingPreference: FeedbackDataSharingPreference; backupRetention: BackupRetentionPolicy; + /** + * Execution policy. Absent/`"any"` = unrestricted; `"kubernetes"` forces the + * Kubernetes sandbox provider and denies local/ssh execution. + */ + executionMode?: InstanceExecutionMode; } export interface InstanceExperimentalSettings { diff --git a/packages/shared/src/validators/adapter-registry.test.ts b/packages/shared/src/validators/adapter-registry.test.ts new file mode 100644 index 00000000..567c113e --- /dev/null +++ b/packages/shared/src/validators/adapter-registry.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { adapterRegistrySchema } from "./adapter-registry.js"; + +describe("adapterRegistrySchema", () => { + it("parses a full entry", () => { + const parsed = adapterRegistrySchema.parse([ + { + adapterType: "opencode_local", + runtimeImage: "ghcr.io/paperclipai/agent-runtime-opencode:v1", + envKeys: ["ANTHROPIC_API_KEY"], + allowFqdns: [], + probeCommand: ["opencode", "--version"], + defaultEnv: { ANTHROPIC_BASE_URL: "http://bifrost.bifrost.svc.cluster.local:8080" }, + }, + ]); + expect(parsed[0].adapterType).toBe("opencode_local"); + expect(parsed[0].enabled).toBe(true); // defaulted + expect(parsed[0].defaultEnv?.ANTHROPIC_BASE_URL).toContain("bifrost"); + }); + + it("defaults enabled to true and optional collections to undefined", () => { + const parsed = adapterRegistrySchema.parse([{ adapterType: "pi_local" }]); + expect(parsed[0]).toMatchObject({ adapterType: "pi_local", enabled: true }); + expect(parsed[0].runtimeImage).toBeUndefined(); + }); + + it("rejects an entry with no adapterType", () => { + expect(() => adapterRegistrySchema.parse([{ enabled: true }])).toThrow(); + }); + + it("rejects a non-array", () => { + expect(() => adapterRegistrySchema.parse({ adapterType: "x" })).toThrow(); + }); +}); diff --git a/packages/shared/src/validators/adapter-registry.ts b/packages/shared/src/validators/adapter-registry.ts new file mode 100644 index 00000000..dcab1a93 --- /dev/null +++ b/packages/shared/src/validators/adapter-registry.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; + +export const adapterRegistryEntrySchema = z + .object({ + adapterType: z.string().min(1), + enabled: z.boolean().default(true), + runtimeImage: z.string().optional(), + envKeys: z.array(z.string()).optional(), + allowFqdns: z.array(z.string()).optional(), + probeCommand: z.array(z.string()).optional(), + defaultEnv: z.record(z.string()).optional(), + }) + .strict(); + +export const adapterRegistrySchema = z.array(adapterRegistryEntrySchema); + +export type AdapterRegistryEntryParsed = z.infer; diff --git a/packages/shared/src/validators/instance.ts b/packages/shared/src/validators/instance.ts index e5c235cb..a36e1519 100644 --- a/packages/shared/src/validators/instance.ts +++ b/packages/shared/src/validators/instance.ts @@ -31,6 +31,9 @@ export const instanceGeneralSettingsSchema = z.object({ DEFAULT_FEEDBACK_DATA_SHARING_PREFERENCE, ), backupRetention: backupRetentionPolicySchema.default(DEFAULT_BACKUP_RETENTION), + // Execution policy. Absent/"any" = unrestricted; "kubernetes" forces the + // Kubernetes sandbox provider and denies local/ssh execution (cloud_tenant). + executionMode: z.enum(["kubernetes", "any"]).optional(), }).strict(); export const patchInstanceGeneralSettingsSchema = instanceGeneralSettingsSchema.partial(); diff --git a/screenshots/PR-7938-agent-config-forced-kubernetes-missing-env.png b/screenshots/PR-7938-agent-config-forced-kubernetes-missing-env.png new file mode 100644 index 0000000000000000000000000000000000000000..edef5b53ba2247dc397ab92e208514fb7db56272 GIT binary patch literal 107274 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 YWlCj9kGa&Z=Is=4by>qay(}>GANq{nOaK4? literal 0 HcmV?d00001 diff --git a/screenshots/PR-7938-agent-config-forced-kubernetes.png b/screenshots/PR-7938-agent-config-forced-kubernetes.png new file mode 100644 index 0000000000000000000000000000000000000000..6eef5b5265f9bf69fc11b1b7487f44c80a61914d GIT binary patch literal 97462 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%0D8|BU<@kpnn|m{#!Tp{P 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 LG>@bzpS|{P;_cEQ literal 0 HcmV?d00001 diff --git a/server/src/__tests__/adapter-models.test.ts b/server/src/__tests__/adapter-models.test.ts index dc1eba55..b72a7290 100644 --- a/server/src/__tests__/adapter-models.test.ts +++ b/server/src/__tests__/adapter-models.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { models as claudeFallbackModels } from "@paperclipai/adapter-claude-local"; import { resetClaudeModelsCacheForTests } from "@paperclipai/adapter-claude-local/server"; import { models as codexFallbackModels } from "@paperclipai/adapter-codex-local"; @@ -220,4 +220,64 @@ describe("adapter model listing", () => { expect(first.some((model) => model.id === "composer-1")).toBe(true); }); + describe("PAPERCLIP_ADAPTER_MODELS declared models", () => { + afterEach(() => { + delete process.env.PAPERCLIP_ADAPTER_MODELS; + }); + + it("prefers declared env models over adapter discovery", async () => { + process.env.PAPERCLIP_ADAPTER_MODELS = JSON.stringify({ + opencode_local: [ + { id: "tensorix/deepseek/deepseek-chat-v3.1", label: "DeepSeek v3.1" }, + { id: "tensorix/z-ai/glm-4.7" }, + ], + }); + + const models = await listAdapterModels("opencode_local"); + + expect(models).toEqual([ + { id: "tensorix/deepseek/deepseek-chat-v3.1", label: "DeepSeek v3.1" }, + { id: "tensorix/z-ai/glm-4.7", label: "tensorix/z-ai/glm-4.7" }, + ]); + }); + + it("observes env changes between calls (memo keyed by raw env value)", async () => { + process.env.PAPERCLIP_ADAPTER_MODELS = JSON.stringify({ + opencode_local: [{ id: "model-a" }], + }); + expect(await listAdapterModels("opencode_local")).toEqual([ + { id: "model-a", label: "model-a" }, + ]); + + process.env.PAPERCLIP_ADAPTER_MODELS = JSON.stringify({ + opencode_local: [{ id: "model-b" }], + }); + expect(await listAdapterModels("opencode_local")).toEqual([ + { id: "model-b", label: "model-b" }, + ]); + }); + + it("fails soft on malformed values: falls back to adapter models instead of throwing", async () => { + process.env.PAPERCLIP_ADAPTER_MODELS = "{not json"; + process.env.PAPERCLIP_OPENCODE_COMMAND = "__paperclip_missing_opencode_command__"; + const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + + const models = await listAdapterModels("opencode_local"); + expect(models).toEqual(opencodeFallbackModels); + + // Parsing is memoized per raw value: a second call must not re-log. + const callsAfterFirst = errorSpy.mock.calls.length; + expect(callsAfterFirst).toBeGreaterThan(0); + await listAdapterModels("opencode_local"); + expect(errorSpy.mock.calls.length).toBe(callsAfterFirst); + }); + + it("ignores declared models for adapters not in the map", async () => { + process.env.PAPERCLIP_ADAPTER_MODELS = JSON.stringify({ + opencode_local: [{ id: "model-a" }], + }); + const models = await listAdapterModels("codex_local"); + expect(models).toEqual(codexFallbackModels); + }); + }); }); diff --git a/server/src/__tests__/environment-service.test.ts b/server/src/__tests__/environment-service.test.ts index 30d66c4f..3232301d 100644 --- a/server/src/__tests__/environment-service.test.ts +++ b/server/src/__tests__/environment-service.test.ts @@ -1,6 +1,6 @@ import { randomUUID } from "node:crypto"; import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest"; -import { eq } from "drizzle-orm"; +import { and, eq } from "drizzle-orm"; import { agents, companies, createDb, environmentLeases, environments, heartbeatRuns } from "@paperclipai/db"; import { getEmbeddedPostgresTestSupport, @@ -222,6 +222,134 @@ describeEmbeddedPostgres("environmentService leases", () => { expect(rows[0]?.status).toBe("active"); }); + it("ensures, refreshes, and finds a managed Kubernetes sandbox environment", async () => { + const companyId = randomUUID(); + await db.insert(companies).values({ + id: companyId, + name: "Acme", + status: "active", + createdAt: new Date(), + updatedAt: new Date(), + }); + + // No managed k8s env yet. + expect(await svc.findKubernetesEnvironment(companyId)).toBeNull(); + + const created = await svc.ensureKubernetesEnvironment(companyId, { + backend: "job", + inCluster: true, + runtimeClassName: "gvisor", + egressMode: "cilium", + egressAllowFqdns: ["api.anthropic.com"], + }); + + expect(created.driver).toBe("sandbox"); + expect(created.config.provider).toBe("kubernetes"); + expect(created.config.backend).toBe("job"); + expect(created.config.runtimeClassName).toBe("gvisor"); + expect(created.metadata?.managedKubernetesSandbox).toBe(true); + + // Idempotent: second call refreshes config in place, no new row. + const refreshed = await svc.ensureKubernetesEnvironment(companyId, { + backend: "job", + inCluster: true, + egressMode: "cilium", + egressAllowFqdns: ["api.anthropic.com", "api.openai.com"], + }); + expect(refreshed.id).toBe(created.id); + expect(refreshed.config.egressAllowFqdns).toEqual([ + "api.anthropic.com", + "api.openai.com", + ]); + + const found = await svc.findKubernetesEnvironment(companyId); + expect(found?.id).toBe(created.id); + + const rows = await db + .select() + .from(environments) + .where(eq(environments.companyId, companyId)); + expect(rows.filter((row) => row.driver === "sandbox")).toHaveLength(1); + }); + + it("deduplicates concurrent managed Kubernetes environment creation", async () => { + const companyId = randomUUID(); + await db.insert(companies).values({ + id: companyId, + name: "Acme", + status: "active", + createdAt: new Date(), + updatedAt: new Date(), + }); + + // No partial unique index covers sandbox drivers yet, so dedup is + // post-insert convergence (prefer the oldest row, delete the loser). + const results = await Promise.all( + Array.from({ length: 8 }, () => + svc.ensureKubernetesEnvironment(companyId, { inCluster: true, backend: "job" }), + ), + ); + + expect(new Set(results.map((environment) => environment.id)).size).toBe(1); + + const rows = await db + .select() + .from(environments) + .where(and(eq(environments.companyId, companyId), eq(environments.driver, "sandbox"))); + expect(rows).toHaveLength(1); + expect((rows[0]?.metadata as Record)?.managedKubernetesSandbox).toBe(true); + }); + + it("does not treat a non-kubernetes sandbox environment as the managed k8s env", async () => { + const companyId = randomUUID(); + await db.insert(companies).values({ + id: companyId, + name: "Acme", + status: "active", + createdAt: new Date(), + updatedAt: new Date(), + }); + await svc.create(companyId, { + name: "Fake Sandbox", + driver: "sandbox", + config: { provider: "fake", image: "busybox", reuseLease: false }, + }); + + expect(await svc.findKubernetesEnvironment(companyId)).toBeNull(); + }); + + it("ignores a config.provider=kubernetes sandbox env without the managed marker", async () => { + const companyId = randomUUID(); + await db.insert(companies).values({ + id: companyId, + name: "Acme", + status: "active", + createdAt: new Date(), + updatedAt: new Date(), + }); + + // A tenant-created sandbox env with config.provider "kubernetes" but WITHOUT + // the managed metadata marker must NOT be treated as the managed k8s env, + // otherwise it would bypass the operator gVisor runtimeClass / Cilium egress. + await svc.create(companyId, { + name: "Tenant K8s Sandbox", + driver: "sandbox", + config: { provider: "kubernetes", reuseLease: false }, + }); + + expect(await svc.findKubernetesEnvironment(companyId)).toBeNull(); + + // The managed env (created via ensureKubernetesEnvironment) carries the + // marker and is the only one found. + const managed = await svc.ensureKubernetesEnvironment(companyId, { + backend: "job", + inCluster: true, + runtimeClassName: "gvisor", + }); + const found = await svc.findKubernetesEnvironment(companyId); + expect(found?.id).toBe(managed.id); + }); + it("allows multiple SSH environments for the same company", async () => { const companyId = randomUUID(); await db.insert(companies).values({ diff --git a/server/src/__tests__/heartbeat-plugin-environment.test.ts b/server/src/__tests__/heartbeat-plugin-environment.test.ts index 381f4556..5419dc22 100644 --- a/server/src/__tests__/heartbeat-plugin-environment.test.ts +++ b/server/src/__tests__/heartbeat-plugin-environment.test.ts @@ -210,6 +210,11 @@ describeEmbeddedPostgres("heartbeat plugin environments", () => { config: { template: "base" }, runId: run!.id, workspaceMode: "shared_workspace", + // Pins the HEARTBEAT-path lease call forwarding the AGENT's adapter type + // (per-run adapter / mixed-harness envs). environment-runtime.ts has two + // drivers calling environmentAcquireLease; regressions here previously + // shipped by editing only the non-heartbeat one. + adapterType: "codex_local", }); await vi.waitFor(() => { expect(workerManager.call).toHaveBeenCalledWith(pluginId, "environmentReleaseLease", { @@ -427,6 +432,7 @@ describeEmbeddedPostgres("heartbeat plugin environments", () => { config: { template: "new" }, runId: run!.id, workspaceMode: "shared_workspace", + adapterType: "codex_local", }); }, 15_000); }); diff --git a/server/src/__tests__/plugin-database.test.ts b/server/src/__tests__/plugin-database.test.ts index 82b455a9..98753b41 100644 --- a/server/src/__tests__/plugin-database.test.ts +++ b/server/src/__tests__/plugin-database.test.ts @@ -168,6 +168,26 @@ describe("buildPluginWorkerEnv", () => { }); }); + it("passes in-cluster Kubernetes service-discovery vars to environment driver plugins", () => { + const env = buildPluginWorkerEnv({ + manifest: { capabilities: ["environment.drivers.register"] }, + instanceInfo, + processEnv: { + KUBERNETES_SERVICE_HOST: "10.0.0.1", + KUBERNETES_SERVICE_PORT: "443", + KUBERNETES_SERVICE_PORT_HTTPS: " ", + AWS_SECRET_ACCESS_KEY: "aws-secret", + }, + }); + + expect(env).toEqual({ + PAPERCLIP_DEPLOYMENT_MODE: "authenticated", + PAPERCLIP_DEPLOYMENT_EXPOSURE: "public", + KUBERNETES_SERVICE_HOST: "10.0.0.1", + KUBERNETES_SERVICE_PORT: "443", + }); + }); + it("does not pass provider keys to non-environment plugins", () => { const env = buildPluginWorkerEnv({ manifest: { capabilities: ["ui.slots.register"] }, diff --git a/server/src/__tests__/server-startup-feedback-export.test.ts b/server/src/__tests__/server-startup-feedback-export.test.ts index 3cdab7c4..f51c09f3 100644 --- a/server/src/__tests__/server-startup-feedback-export.test.ts +++ b/server/src/__tests__/server-startup-feedback-export.test.ts @@ -143,6 +143,7 @@ vi.mock("../services/index.js", () => ({ humanGrantsInserted: 0, })), feedbackService: feedbackServiceFactoryMock, + bootstrapExecutionPolicyFromEnv: vi.fn(async () => null), heartbeatService: vi.fn(() => ({ reapOrphanedRuns: vi.fn(async () => undefined), promoteDueScheduledRetries: vi.fn(async () => ({ promoted: 0, runIds: [] })), diff --git a/server/src/adapters/registry.ts b/server/src/adapters/registry.ts index 5bb261b8..55bce77b 100644 --- a/server/src/adapters/registry.ts +++ b/server/src/adapters/registry.ts @@ -4,6 +4,7 @@ import type { AdapterRuntimeCommandSpec, ServerAdapterModule, } from "./types.js"; +import { parseAdapterModelsEnv } from "../services/adapter-models-env.js"; import { buildSandboxNpmInstallCommand, getAdapterSessionManagement, @@ -654,7 +655,42 @@ export function getServerAdapter(type: string): ServerAdapterModule { return findActiveServerAdapter(type) ?? processAdapter; } +/** + * Memoized view of PAPERCLIP_ADAPTER_MODELS, keyed by the raw env string so + * tests (and live env mutation) that change the variable are still observed. + * Parsing happens at most once per distinct raw value instead of per + * `listAdapterModels` request, and malformed values fail SOFT here: we log the + * parse error once (per distinct raw value) and fall back to adapter-discovered + * models rather than throwing at request time. + */ +let adapterModelsEnvCache: { + raw: string | undefined; + value: ReturnType; +} | null = null; + +function getDeclaredAdapterModels(): ReturnType { + const raw = process.env.PAPERCLIP_ADAPTER_MODELS; + if (adapterModelsEnvCache && adapterModelsEnvCache.raw === raw) { + return adapterModelsEnvCache.value; + } + let value: ReturnType = null; + try { + value = parseAdapterModelsEnv(process.env); + } catch (err) { + console.error( + "[paperclip] Invalid PAPERCLIP_ADAPTER_MODELS; ignoring declared model lists:", + err, + ); + } + adapterModelsEnvCache = { raw, value }; + return value; +} + export async function listAdapterModels(type: string): Promise<{ id: string; label: string }[]> { + const declaredModels = getDeclaredAdapterModels(); + if (declaredModels && declaredModels[type]?.length) { + return declaredModels[type].map((m) => ({ id: m.id, label: m.label ?? m.id })); + } const adapter = findActiveServerAdapter(type); if (!adapter) return []; if (adapter.listModels) { diff --git a/server/src/app.ts b/server/src/app.ts index e91bc00a..b02b963d 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -471,7 +471,67 @@ export async function createApp( lifecycle, async (pluginId) => (await pluginRegistry.getById(pluginId))?.packagePath ?? null, ); - void loader.loadAll().then((result) => { + // Auto-install the bundled kubernetes sandbox-provider plugin so the + // "kubernetes" sandbox provider is registered for agent runs. The plugin is + // excluded from the pnpm workspace and built standalone into the image (see + // Dockerfile), then installed here from its local path. This runs BEFORE + // loadAll() so loadAll() can activate it in the same startup pass. + // + // SAFETY (invariant B): this is fully fail-safe. Any failure (missing path, + // install error, load error) is caught, logged, and swallowed so the server + // ALWAYS finishes booting. A degraded boot (no kubernetes provider, agents + // cannot run) is strictly preferable to a crash loop. + const ensureBundledKubernetesPlugin = async (): Promise => { + const KUBERNETES_PLUGIN_KEY = "paperclip.kubernetes-sandbox-provider"; + const pluginPath = + process.env["PAPERCLIP_KUBERNETES_PLUGIN_PATH"] ?? + "/app/packages/plugins/sandbox-providers/kubernetes"; + try { + // Idempotent: skip if already installed (any non-uninstalled status). + const existing = await pluginRegistry.getByKey(KUBERNETES_PLUGIN_KEY); + if (existing) { + logger.info( + { pluginKey: KUBERNETES_PLUGIN_KEY, status: existing.status }, + "kubernetes sandbox plugin already installed; skipping auto-install", + ); + return; + } + // Skip silently when the bundle is absent (e.g. local dev or an image + // built without the plugin). Not an error condition. + if (!fs.existsSync(path.join(pluginPath, "dist", "manifest.js"))) { + logger.info( + { pluginPath }, + "kubernetes sandbox plugin bundle not present; skipping auto-install", + ); + return; + } + logger.info({ pluginPath }, "auto-installing bundled kubernetes sandbox plugin"); + const discovered = await loader.installPlugin({ localPath: pluginPath }); + if (!discovered.manifest) { + logger.error("kubernetes sandbox plugin installed but manifest is missing"); + return; + } + // Transition installed -> ready and activate the worker. + const installed = await pluginRegistry.getByKey(discovered.manifest.id); + if (installed) { + await lifecycle.load(installed.id); + logger.info( + { pluginId: installed.id, pluginKey: installed.pluginKey }, + "kubernetes sandbox plugin auto-installed and loaded", + ); + } else { + logger.error("kubernetes sandbox plugin installed but not found in registry"); + } + } catch (err) { + logger.error( + { err }, + "Failed to auto-install the kubernetes sandbox plugin; continuing boot (degraded: kubernetes provider unavailable)", + ); + } + }; + void ensureBundledKubernetesPlugin() + .then(() => loader.loadAll()) + .then((result) => { if (!result) return; for (const loaded of result.results) { if (devWatcher && loaded.success && loaded.plugin.packagePath) { diff --git a/server/src/index.ts b/server/src/index.ts index a81e50b5..6708c535 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -32,12 +32,17 @@ import { setupLiveEventsWebSocketServer } from "./realtime/live-events-ws.js"; import { feedbackService, backfillPrincipalAccessCompatibility, + bootstrapExecutionPolicyFromEnv, heartbeatService, instanceSettingsService, reconcileCloudUpstreamRunsOnStartup, reconcilePersistedRuntimeServicesOnStartup, routineService, } from "./services/index.js"; +import { + parseAdapterRegistryEnv, + reconcileAdapterAvailability, +} from "./services/adapter-registry-bootstrap.js"; import { createFeedbackTraceShareClientFromConfig } from "./services/feedback-share-client.js"; import { buildRuntimeApiCandidateUrls, choosePrimaryRuntimeApiUrl } from "./runtime-api.js"; import { createPluginWorkerManager } from "./services/plugin-worker-manager.js"; @@ -716,6 +721,27 @@ export async function startServer(): Promise { logger.error({ err }, "startup reconciliation of cloud upstream runs failed"); }); + // Force the instance onto the Kubernetes sandbox provider when configured via + // env (PAPERCLIP_EXECUTION_MODE=kubernetes). Runs BEFORE the heartbeat resumes + // queued runs so the policy + managed k8s environments are in place. A bad + // PAPERCLIP_EXECUTION_MODE / PAPERCLIP_K8S_* value throws and fails startup + // (fail-loud) rather than silently allowing local execution. + try { + const policyResult = await bootstrapExecutionPolicyFromEnv(db as any); + if (policyResult) { + logger.warn( + { + executionMode: policyResult.executionMode, + companiesConfigured: policyResult.companiesConfigured, + }, + "forced execution policy applied at startup", + ); + } + } catch (err) { + logger.error({ err }, "failed to apply forced execution policy from environment"); + throw err; + } + if (config.heartbeatSchedulerEnabled) { const heartbeat = heartbeatService(db as any, { pluginWorkerManager }); const routines = routineService(db as any, { pluginWorkerManager }); @@ -868,6 +894,18 @@ export async function startServer(): Promise { const { waitForExternalAdapters } = await import("./adapters/registry.js"); await waitForExternalAdapters(); + // Reconcile the agent-creation picker to the declaratively-configured adapter + // set (PAPERCLIP_ADAPTERS). Must run after external adapters are loaded so the + // known-adapter list is complete. Fail loud on misconfig (a declared adapter + // with no implementation), consistent with the execution-policy bootstrap: + // log the structured error, then rethrow to fail startup. + try { + reconcileAdapterAvailability(parseAdapterRegistryEnv()); + } catch (err) { + logger.error({ err }, "failed to reconcile adapter availability from PAPERCLIP_ADAPTERS"); + throw err; + } + await new Promise((resolveListen, rejectListen) => { const onError = (err: Error) => { server.off("error", onError); diff --git a/server/src/services/adapter-models-env.test.ts b/server/src/services/adapter-models-env.test.ts new file mode 100644 index 00000000..8b32b84a --- /dev/null +++ b/server/src/services/adapter-models-env.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest"; +import { parseAdapterModelsEnv } from "./adapter-models-env.js"; + +const ENV = JSON.stringify({ + opencode_local: [ + { id: "tensorix/deepseek/deepseek-chat-v3.1", label: "DeepSeek v3.1" }, + { id: "tensorix/z-ai/glm-4.7", label: "GLM 4.7" }, + ], +}); + +describe("parseAdapterModelsEnv", () => { + it("returns null when unset", () => { + expect(parseAdapterModelsEnv({})).toBeNull(); + }); + it("parses the per-adapter model map", () => { + const m = parseAdapterModelsEnv({ PAPERCLIP_ADAPTER_MODELS: ENV }); + expect(m?.opencode_local?.[0]).toEqual({ id: "tensorix/deepseek/deepseek-chat-v3.1", label: "DeepSeek v3.1" }); + expect(m?.opencode_local?.length).toBe(2); + }); + it("defaults label to id when omitted", () => { + const m = parseAdapterModelsEnv({ PAPERCLIP_ADAPTER_MODELS: JSON.stringify({ pi_local: [{ id: "tensorix/x/y" }] }) }); + expect(m?.pi_local?.[0]).toEqual({ id: "tensorix/x/y", label: "tensorix/x/y" }); + }); + it("throws on invalid JSON (fail loud)", () => { + expect(() => parseAdapterModelsEnv({ PAPERCLIP_ADAPTER_MODELS: "{bad" })).toThrow(/PAPERCLIP_ADAPTER_MODELS/); + }); + it("throws when an entry lacks a string id", () => { + expect(() => parseAdapterModelsEnv({ PAPERCLIP_ADAPTER_MODELS: JSON.stringify({ a: [{ label: "x" }] }) })).toThrow(); + }); +}); diff --git a/server/src/services/adapter-models-env.ts b/server/src/services/adapter-models-env.ts new file mode 100644 index 00000000..43ddb63b --- /dev/null +++ b/server/src/services/adapter-models-env.ts @@ -0,0 +1,40 @@ +export interface AdapterModelEntry { + id: string; + label?: string; +} + +/** + * Per-adapter model list supplied by the operator via env, so the agent model + * picker can offer models the server cannot CLI-discover (e.g. gateway models). + * JSON object: adapterType -> [{ id, label? }]. Returns null when unset; throws + * loudly on malformed input. + */ +export function parseAdapterModelsEnv( + env: Record = process.env, +): Record | null { + const raw = env.PAPERCLIP_ADAPTER_MODELS?.trim(); + if (!raw) return null; + let parsed: unknown; + try { + parsed = JSON.parse(raw); + } catch (e) { + throw new Error(`PAPERCLIP_ADAPTER_MODELS must be valid JSON: ${(e as Error).message}`); + } + if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { + throw new Error("PAPERCLIP_ADAPTER_MODELS must be a JSON object mapping adapterType to an array of {id,label}"); + } + const out: Record = {}; + for (const [type, list] of Object.entries(parsed as Record)) { + if (!Array.isArray(list)) { + throw new Error(`PAPERCLIP_ADAPTER_MODELS[${type}] must be an array`); + } + out[type] = list.map((m) => { + const o = m as Record; + if (typeof o.id !== "string" || !o.id) { + throw new Error(`PAPERCLIP_ADAPTER_MODELS[${type}] entries require a non-empty string id`); + } + return { id: o.id, label: typeof o.label === "string" ? o.label : o.id }; + }); + } + return out; +} diff --git a/server/src/services/adapter-registry-bootstrap.reconcile.test.ts b/server/src/services/adapter-registry-bootstrap.reconcile.test.ts new file mode 100644 index 00000000..fb406926 --- /dev/null +++ b/server/src/services/adapter-registry-bootstrap.reconcile.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, it, vi } from "vitest"; + +const setAdapterDisabled = vi.fn(); + +vi.mock("../adapters/registry.js", async (orig) => ({ + ...(await orig()), + listServerAdapters: () => [ + { type: "claude_local" }, + { type: "opencode_local" }, + { type: "pi_local" }, + ], +})); + +vi.mock("./adapter-plugin-store.js", () => ({ + setAdapterDisabled: (type: string, disabled: boolean) => setAdapterDisabled(type, disabled), +})); + +const { reconcileAdapterAvailability } = await import("./adapter-registry-bootstrap.js"); + +describe("reconcileAdapterAvailability", () => { + it("is a no-op when registry is null", () => { + setAdapterDisabled.mockReset(); + expect(reconcileAdapterAvailability(null)).toEqual({ enabled: [], disabled: [] }); + expect(setAdapterDisabled).not.toHaveBeenCalled(); + }); + + it("enables declared, disables everything else (e.g. drops claude_local)", () => { + setAdapterDisabled.mockReset(); + const result = reconcileAdapterAvailability([ + { adapterType: "opencode_local", enabled: true }, + ]); + expect(result.enabled).toEqual(["opencode_local"]); + expect(result.disabled.sort()).toEqual(["claude_local", "pi_local"]); + expect(setAdapterDisabled).toHaveBeenCalledWith("claude_local", true); + expect(setAdapterDisabled).toHaveBeenCalledWith("opencode_local", false); + }); + + it("throws when a declared adapter has no installed implementation", () => { + setAdapterDisabled.mockReset(); + expect(() => + reconcileAdapterAvailability([{ adapterType: "ghost_adapter", enabled: true }]), + ).toThrow(/no installed adapter: ghost_adapter/); + }); +}); diff --git a/server/src/services/adapter-registry-bootstrap.test.ts b/server/src/services/adapter-registry-bootstrap.test.ts new file mode 100644 index 00000000..c75a121d --- /dev/null +++ b/server/src/services/adapter-registry-bootstrap.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from "vitest"; +import { parseAdapterRegistryEnv } from "./adapter-registry-bootstrap.js"; + +const ENTRY = JSON.stringify([ + { adapterType: "opencode_local", runtimeImage: "img", envKeys: ["ANTHROPIC_API_KEY"], allowFqdns: [], probeCommand: ["opencode", "--version"], defaultEnv: { ANTHROPIC_BASE_URL: "http://bifrost:8080" } }, +]); + +describe("parseAdapterRegistryEnv", () => { + it("returns null when neither env nor file is set", () => { + expect(parseAdapterRegistryEnv({})).toBeNull(); + }); + + it("parses inline PAPERCLIP_ADAPTERS JSON", () => { + const r = parseAdapterRegistryEnv({ PAPERCLIP_ADAPTERS: ENTRY }); + expect(r).toHaveLength(1); + expect(r?.[0].adapterType).toBe("opencode_local"); + expect(r?.[0].enabled).toBe(true); + }); + + it("throws on malformed JSON (fail loud)", () => { + expect(() => parseAdapterRegistryEnv({ PAPERCLIP_ADAPTERS: "{not json" })).toThrow( + /PAPERCLIP_ADAPTERS/, + ); + }); + + it("throws on schema-invalid content (fail loud)", () => { + expect(() => + parseAdapterRegistryEnv({ PAPERCLIP_ADAPTERS: JSON.stringify([{ enabled: true }]) }), + ).toThrow(/PAPERCLIP_ADAPTERS/); + }); +}); diff --git a/server/src/services/adapter-registry-bootstrap.ts b/server/src/services/adapter-registry-bootstrap.ts new file mode 100644 index 00000000..c8e7f4b0 --- /dev/null +++ b/server/src/services/adapter-registry-bootstrap.ts @@ -0,0 +1,97 @@ +/** + * Declarative adapter-registry bootstrap. + * + * One source (`PAPERCLIP_ADAPTERS` inline JSON, or `PAPERCLIP_ADAPTERS_FILE` a + * path to a JSON file) feeds two consumers: + * 1. Availability: reconcile the file-backed disabled-set so the picker shows + * exactly the declared, enabled set (runs for any instance). + * 2. k8s runtime: the same registry rides on the Kubernetes environment config + * (see execution-policy-bootstrap) so the plugin resolves runtime + * image/envKeys/allowFqdns/probe/defaultEnv from it. + * + * Parsing is pure + fails loud on malformed/invalid config, mirroring + * execution-policy-bootstrap. + */ +import fs from "node:fs"; +import { adapterRegistrySchema, type AdapterRegistryEntryParsed } from "@paperclipai/shared"; +import { logger } from "../middleware/logger.js"; +import { listServerAdapters } from "../adapters/registry.js"; +import { setAdapterDisabled } from "./adapter-plugin-store.js"; + +export type AdapterRegistryEnv = Record; + +/** + * Parse the declarative registry from env. Returns null when unconfigured + * (built-in defaults; local/OSS unchanged). Throws on malformed/invalid input. + */ +export function parseAdapterRegistryEnv( + env: AdapterRegistryEnv = process.env, +): AdapterRegistryEntryParsed[] | null { + const inline = env.PAPERCLIP_ADAPTERS?.trim(); + const filePath = env.PAPERCLIP_ADAPTERS_FILE?.trim(); + if (!inline && !filePath) return null; + + let rawText: string; + if (inline) { + rawText = inline; + } else { + try { + rawText = fs.readFileSync(filePath as string, "utf-8"); + } catch (err) { + throw new Error( + `PAPERCLIP_ADAPTERS_FILE could not be read at "${filePath}": ${(err as Error).message}`, + ); + } + } + + let parsed: unknown; + try { + parsed = JSON.parse(rawText); + } catch (err) { + throw new Error(`PAPERCLIP_ADAPTERS must be valid JSON: ${(err as Error).message}`); + } + + const result = adapterRegistrySchema.safeParse(parsed); + if (!result.success) { + throw new Error( + `PAPERCLIP_ADAPTERS failed validation: ${result.error.issues + .map((i) => `${i.path.join(".")}: ${i.message}`) + .join("; ")}`, + ); + } + return result.data; +} + +/** + * Reconcile availability: every known server adapter NOT enabled in the declared + * registry is disabled; declared+enabled ones are enabled. Throws if a declared + * adapterType has no installed adapter (cannot offer a harness with no + * implementation). No-op when `registry` is null. + */ +export function reconcileAdapterAvailability( + registry: AdapterRegistryEntryParsed[] | null, +): { enabled: string[]; disabled: string[] } { + if (!registry) return { enabled: [], disabled: [] }; + + const knownTypes = new Set(listServerAdapters().map((a) => a.type)); + const declared = new Map(registry.map((e) => [e.adapterType, e])); + + const missing = [...declared.keys()].filter((t) => !knownTypes.has(t)); + if (missing.length > 0) { + throw new Error( + `PAPERCLIP_ADAPTERS declares adapter type(s) with no installed adapter: ${missing.join(", ")}`, + ); + } + + const enabled: string[] = []; + const disabled: string[] = []; + for (const type of knownTypes) { + const entry = declared.get(type); + const shouldEnable = entry !== undefined && entry.enabled !== false; + setAdapterDisabled(type, !shouldEnable); + (shouldEnable ? enabled : disabled).push(type); + } + + logger.info({ enabled, disabled }, "reconciled adapter availability from PAPERCLIP_ADAPTERS"); + return { enabled, disabled }; +} diff --git a/server/src/services/environment-run-orchestrator.ts b/server/src/services/environment-run-orchestrator.ts index 9b0a2066..693b57c6 100644 --- a/server/src/services/environment-run-orchestrator.ts +++ b/server/src/services/environment-run-orchestrator.ts @@ -208,6 +208,7 @@ export function environmentRunOrchestrator( issueId: string | null; heartbeatRunId: string; persistedExecutionWorkspace: Pick | null; + adapterType: string | null; }): Promise { try { return await environmentRuntime.acquireRunLease(input); @@ -282,6 +283,7 @@ export function environmentRunOrchestrator( issueId: input.issueId, heartbeatRunId: input.heartbeatRunId, persistedExecutionWorkspace: input.persistedExecutionWorkspace, + adapterType: input.adapterType ?? null, }); // Step 3: Log lease acquisition activity diff --git a/server/src/services/environment-runtime.ts b/server/src/services/environment-runtime.ts index d876b6d3..08451082 100644 --- a/server/src/services/environment-runtime.ts +++ b/server/src/services/environment-runtime.ts @@ -112,6 +112,13 @@ export interface EnvironmentDriverAcquireInput { heartbeatRunId: string | null; executionWorkspaceId: string | null; executionWorkspaceMode: ExecutionWorkspace["mode"] | null; + /** + * The harness/adapter type for this run (the agent's adapter). Drivers that + * materialize a per-run sandbox use it to select the runtime image so a single + * environment can serve mixed harnesses; null falls back to the environment's + * configured default adapter. + */ + adapterType: string | null; } export interface EnvironmentDriverReleaseInput { @@ -490,6 +497,14 @@ function createSandboxEnvironmentDriver( // a well-formed identifier. runId: input.heartbeatRunId ?? randomUUID(), workspaceMode: input.executionWorkspaceMode ?? undefined, + // The agent's harness for THIS run, so the plugin picks the matching + // runtime image (per-run adapter, mixed-harness environments). + // NOTE: environment-runtime.ts has TWO drivers calling + // environmentAcquireLease; this plugin-sandbox one is the HEARTBEAT + // path. Omitting adapterType here silently falls back to the + // environment's default adapter image (a pi agent then runs in the + // opencode image and the harness binary is missing at exec time). + adapterType: input.adapterType ?? undefined, }, resolvePluginSandboxRpcTimeoutMs(workerConfig), ); @@ -898,6 +913,7 @@ function createPluginEnvironmentDriver( config: parsed.config.driverConfig, runId: input.heartbeatRunId ?? randomUUID(), workspaceMode: input.executionWorkspaceMode ?? undefined, + adapterType: input.adapterType ?? undefined, }); return await environmentsSvc.acquireLease({ @@ -1113,6 +1129,8 @@ export function environmentRuntimeService( /** Null for ad-hoc invocations (e.g. operator-initiated `Test` probes). */ heartbeatRunId: string | null; persistedExecutionWorkspace: Pick | null; + /** The agent's adapter type for this run (mixed-harness environments). */ + adapterType?: string | null; }): Promise { if (input.environment.status !== "active") { throw new Error(`Environment "${input.environment.name}" is not active.`); @@ -1129,6 +1147,7 @@ export function environmentRuntimeService( heartbeatRunId: input.heartbeatRunId, executionWorkspaceId: leaseContext.executionWorkspaceId, executionWorkspaceMode: leaseContext.executionWorkspaceMode, + adapterType: input.adapterType ?? null, }); return { diff --git a/server/src/services/environments.ts b/server/src/services/environments.ts index a94e5aa4..e4287a3c 100644 --- a/server/src/services/environments.ts +++ b/server/src/services/environments.ts @@ -1,4 +1,4 @@ -import { and, desc, eq, sql } from "drizzle-orm"; +import { and, asc, desc, eq, sql } from "drizzle-orm"; import type { Db } from "@paperclipai/db"; import { environmentLeases, environments } from "@paperclipai/db"; import { @@ -22,6 +22,43 @@ const DEFAULT_LOCAL_ENVIRONMENT_NAME = "Local"; const DEFAULT_LOCAL_ENVIRONMENT_DESCRIPTION = "Default execution environment for Paperclip runs on this machine."; +const DEFAULT_KUBERNETES_ENVIRONMENT_NAME = "Kubernetes Sandbox"; +const DEFAULT_KUBERNETES_ENVIRONMENT_DESCRIPTION = + "Managed Kubernetes sandbox environment for hosted tenant execution."; +/** Provider key (== plugin driverKey) of the first-party Kubernetes sandbox provider. */ +const KUBERNETES_PROVIDER_KEY = "kubernetes"; +/** Metadata marker for the company's managed-by-config Kubernetes sandbox environment. */ +const KUBERNETES_MANAGED_MARKER = "managedKubernetesSandbox"; + +/** + * Configuration accepted by `ensureKubernetesEnvironment`. Mirrors the keys of + * the kubernetes sandbox-provider `configSchema` that an operator typically + * pins for a hosted cloud instance. Stored verbatim in `environment.config` + * (the plugin validates/defaults it via `kubernetesProviderConfigSchema` at + * lease time); `provider` is always forced to "kubernetes". + */ +export interface KubernetesEnvironmentConfigInput { + backend?: "sandbox-cr" | "job"; + inCluster?: boolean; + runtimeClassName?: string; + egressMode?: "cilium" | "standard"; + egressAllowFqdns?: string[]; + egressAllowCidrs?: string[]; + namespacePrefix?: string; + imageRegistry?: string; + adapterType?: string; + /** + * Sandbox lease RPC timeout in milliseconds. Read at lease time by + * `resolvePluginSandboxRpcTimeoutMs` to extend the worker-manager call + * timeout when acquiring a lease may take minutes (e.g. a cold node + * scale-up on an autoscale-to-zero pool). Stored verbatim in the + * environment config and validated by the sandbox config schema. + */ + timeoutMs?: number; + adapters?: import("@paperclipai/shared").AdapterRegistryEntry[]; + [key: string]: unknown; +} + function cloneRecord(value: unknown, fallback: Record | null = null): Record | null { if (!value || typeof value !== "object" || Array.isArray(value)) return fallback; return { ...(value as Record) }; @@ -147,6 +184,130 @@ export function environmentService(db: Db) { return toEnvironment(existing); }, + /** + * Idempotently ensure a managed Kubernetes sandbox environment exists for a + * company, configured from instance/operator-supplied config. Mirrors + * `ensureLocalEnvironment`, but there is no DB unique index for sandbox + * drivers, so idempotency is by metadata marker + driver lookup. + * + * The environment is `driver: "sandbox"` with `config.provider: + * "kubernetes"` so it resolves to the first-party Kubernetes sandbox + * provider. On subsequent calls the config is refreshed (so operators can + * update egress/runtimeClass via gitops without recreating the row). + */ + ensureKubernetesEnvironment: async ( + companyId: string, + config: KubernetesEnvironmentConfigInput, + ): Promise => { + const desiredConfig: Record = { + ...config, + provider: KUBERNETES_PROVIDER_KEY, + }; + const desiredMetadata: Record = { + managedByPaperclip: true, + [KUBERNETES_MANAGED_MARKER]: true, + }; + + const existing = await db + .select() + .from(environments) + .where(and(eq(environments.companyId, companyId), eq(environments.driver, "sandbox"))) + .then((rows) => + rows.find( + (row) => + (row.metadata as Record | null)?.[KUBERNETES_MANAGED_MARKER] === true, + ) ?? null, + ); + + const now = new Date(); + if (existing) { + const updated = await db + .update(environments) + .set({ + config: desiredConfig, + metadata: { ...(existing.metadata ?? {}), ...desiredMetadata }, + status: "active", + updatedAt: now, + }) + .where(eq(environments.id, existing.id)) + .returning() + .then((rows) => rows[0] ?? existing); + return toEnvironment(updated); + } + + const row = await db + .insert(environments) + .values({ + companyId, + name: DEFAULT_KUBERNETES_ENVIRONMENT_NAME, + description: DEFAULT_KUBERNETES_ENVIRONMENT_DESCRIPTION, + driver: "sandbox", + status: "active", + config: desiredConfig, + metadata: desiredMetadata, + createdAt: now, + updatedAt: now, + }) + .returning() + .then((rows) => rows[0] ?? null); + if (!row) { + throw new Error("Failed to ensure kubernetes environment"); + } + + // Concurrency: the schema's (companyId, driver) unique index is partial + // on driver='local' only, so there is no DB constraint stopping two + // simultaneous callers (e.g. concurrent heartbeats lazily provisioning a + // new company) from both inserting a managed k8s row. Until a partial + // unique index on (companyId, driver) WHERE the managed marker exists is + // added via migration (the proper long-term fix), converge here: re-read, + // deterministically prefer the oldest managed row, and delete our own + // insert if it lost the race. Both racers compute the same winner, so + // duplicates self-heal instead of persisting. + const winner = await db + .select() + .from(environments) + .where(and(eq(environments.companyId, companyId), eq(environments.driver, "sandbox"))) + .orderBy(asc(environments.createdAt), asc(environments.id)) + .then( + (rows) => + rows.find( + (candidate) => + (candidate.metadata as Record | null)?.[ + KUBERNETES_MANAGED_MARKER + ] === true, + ) ?? null, + ); + if (winner && winner.id !== row.id) { + await db.delete(environments).where(eq(environments.id, row.id)); + return toEnvironment(winner); + } + return toEnvironment(row); + }, + + /** + * Find an active Kubernetes sandbox environment for a company, if one + * exists. Read-only counterpart to `ensureKubernetesEnvironment` used by the + * per-run execution guard (which must not silently create config-less envs). + */ + findKubernetesEnvironment: async (companyId: string): Promise => { + const rows = await db + .select() + .from(environments) + .where( + and( + eq(environments.companyId, companyId), + eq(environments.driver, "sandbox"), + eq(environments.status, "active"), + ), + ) + .orderBy(desc(environments.updatedAt)); + const match = rows.find( + (row) => + (row.metadata as Record | null)?.[KUBERNETES_MANAGED_MARKER] === true, + ); + return match ? toEnvironment(match) : null; + }, + create: async (companyId: string, input: CreateEnvironment): Promise => { const now = new Date(); const row = await db diff --git a/server/src/services/execution-allowlist.test.ts b/server/src/services/execution-allowlist.test.ts new file mode 100644 index 00000000..fc53c7e5 --- /dev/null +++ b/server/src/services/execution-allowlist.test.ts @@ -0,0 +1,96 @@ +import { describe, expect, it } from "vitest"; +import { + KUBERNETES_PROVIDER_KEY, + evaluateExecutionAllowlist, + type ExecutionEnvironmentCandidate, +} from "./execution-allowlist.js"; + +const localEnv: ExecutionEnvironmentCandidate = { + driver: "local", + provider: null, +}; + +const kubernetesEnv: ExecutionEnvironmentCandidate = { + driver: "sandbox", + provider: KUBERNETES_PROVIDER_KEY, +}; + +const fakeSandboxEnv: ExecutionEnvironmentCandidate = { + driver: "sandbox", + provider: "fake", +}; + +const sshEnv: ExecutionEnvironmentCandidate = { + driver: "ssh", + provider: null, +}; + +describe("evaluateExecutionAllowlist", () => { + describe('executionMode "any" (unrestricted, default)', () => { + it("allows the local environment", () => { + const result = evaluateExecutionAllowlist({ executionMode: "any" }, localEnv); + expect(result.allowed).toBe(true); + }); + + it("allows the kubernetes sandbox environment", () => { + const result = evaluateExecutionAllowlist({ executionMode: "any" }, kubernetesEnv); + expect(result.allowed).toBe(true); + }); + + it("allows a non-kubernetes sandbox environment", () => { + const result = evaluateExecutionAllowlist({ executionMode: "any" }, fakeSandboxEnv); + expect(result.allowed).toBe(true); + }); + + it("treats absent executionMode as unrestricted", () => { + expect(evaluateExecutionAllowlist({}, localEnv).allowed).toBe(true); + expect(evaluateExecutionAllowlist({ executionMode: undefined }, localEnv).allowed).toBe(true); + }); + }); + + describe('executionMode "kubernetes" (forced sandbox)', () => { + it("allows ONLY a kubernetes sandbox_provider environment", () => { + const result = evaluateExecutionAllowlist({ executionMode: "kubernetes" }, kubernetesEnv); + expect(result.allowed).toBe(true); + }); + + it("DENIES the local environment", () => { + const result = evaluateExecutionAllowlist({ executionMode: "kubernetes" }, localEnv); + expect(result.allowed).toBe(false); + if (!result.allowed) { + expect(result.reason).toMatch(/kubernetes/i); + expect(result.deniedDriver).toBe("local"); + } + }); + + it("DENIES an ssh environment", () => { + const result = evaluateExecutionAllowlist({ executionMode: "kubernetes" }, sshEnv); + expect(result.allowed).toBe(false); + }); + + it("DENIES a non-kubernetes sandbox provider (e.g. fake)", () => { + const result = evaluateExecutionAllowlist({ executionMode: "kubernetes" }, fakeSandboxEnv); + expect(result.allowed).toBe(false); + if (!result.allowed) { + expect(result.deniedProvider).toBe("fake"); + } + }); + + it("DENIES a sandbox driver with no provider", () => { + const result = evaluateExecutionAllowlist( + { executionMode: "kubernetes" }, + { driver: "sandbox", provider: null }, + ); + expect(result.allowed).toBe(false); + }); + }); + + describe("isExecutionForcedToKubernetes helper", () => { + it("reflects the policy", async () => { + const { isExecutionForcedToKubernetes } = await import("./execution-allowlist.js"); + expect(isExecutionForcedToKubernetes({ executionMode: "kubernetes" })).toBe(true); + expect(isExecutionForcedToKubernetes({ executionMode: "any" })).toBe(false); + expect(isExecutionForcedToKubernetes({})).toBe(false); + }); + }); +}); diff --git a/server/src/services/execution-allowlist.ts b/server/src/services/execution-allowlist.ts new file mode 100644 index 00000000..c37e6b66 --- /dev/null +++ b/server/src/services/execution-allowlist.ts @@ -0,0 +1,103 @@ +/** + * Pure execution-allowlist guard. + * + * Decides whether a candidate execution environment is permitted to run an + * agent, given the instance-level execution policy. This is security-critical: + * on a shared cloud instance we FORCE all untrusted tenant agents onto the + * Kubernetes sandbox-provider and REFUSE local/in-process execution so that a + * tenant agent can never run inside the server process or on an unsandboxed + * local/ssh adapter. + * + * The merged tree's environment model represents the Kubernetes sandbox as a + * core `driver: "sandbox"` environment whose `config.provider` is the plugin's + * `driverKey` ("kubernetes", `kind: "sandbox_provider"`). The local default is + * `driver: "local"`. This module knows nothing about the DB or heartbeat โ€” it + * just maps (driver, provider, policy) -> allow/deny so it is trivially + * unit-testable. + */ + +/** Provider key (== plugin driverKey) of the first-party Kubernetes sandbox provider. */ +export const KUBERNETES_PROVIDER_KEY = "kubernetes" as const; + +/** + * Instance execution policy as read from instance general settings. + * + * - `"any"` / absent: unrestricted โ€” any environment driver is allowed (the + * default, preserves single-tenant / local-trusted behavior). + * - `"kubernetes"`: force the Kubernetes sandbox provider; deny local, ssh, and + * any non-kubernetes sandbox provider. + */ +export interface ExecutionPolicy { + executionMode?: "kubernetes" | "any"; +} + +/** + * The minimal shape of the selected/candidate environment the guard needs. + * `driver` is the core `EnvironmentDriver`; `provider` is the sandbox provider + * key (== plugin driverKey) for `driver: "sandbox"` environments, else null. + */ +export interface ExecutionEnvironmentCandidate { + driver: string; + provider: string | null | undefined; +} + +export type ExecutionAllowlistDecision = + | { allowed: true } + | { + allowed: false; + reason: string; + deniedDriver: string; + deniedProvider: string | null; + }; + +/** True when the policy forces all execution onto the Kubernetes sandbox. */ +export function isExecutionForcedToKubernetes(policy: ExecutionPolicy | null | undefined): boolean { + return policy?.executionMode === "kubernetes"; +} + +/** + * True iff the candidate environment is the Kubernetes sandbox provider, i.e. a + * core `sandbox` driver whose provider key is "kubernetes". + */ +export function isKubernetesSandboxEnvironment( + candidate: ExecutionEnvironmentCandidate, +): boolean { + return candidate.driver === "sandbox" && candidate.provider === KUBERNETES_PROVIDER_KEY; +} + +/** + * Decide whether the candidate environment may run under the given policy. + * + * When `executionMode === "kubernetes"`, ONLY a `sandbox_provider` driver with + * provider/driverKey "kubernetes" is allowed; a `local` driver (or any non-k8s + * sandbox provider, or ssh, or plugin) is DENIED. Otherwise everything is + * allowed. + */ +export function evaluateExecutionAllowlist( + policy: ExecutionPolicy | null | undefined, + candidate: ExecutionEnvironmentCandidate, +): ExecutionAllowlistDecision { + if (!isExecutionForcedToKubernetes(policy)) { + return { allowed: true }; + } + + if (isKubernetesSandboxEnvironment(candidate)) { + return { allowed: true }; + } + + const provider = candidate.provider ?? null; + const target = + candidate.driver === "sandbox" + ? `sandbox provider "${provider ?? "(none)"}"` + : `"${candidate.driver}" driver`; + + return { + allowed: false, + reason: + `Instance execution policy requires the Kubernetes sandbox provider ` + + `(executionMode=kubernetes), but the resolved environment uses the ${target}. ` + + `Untrusted execution on a non-Kubernetes environment is refused.`, + deniedDriver: candidate.driver, + deniedProvider: provider, + }; +} diff --git a/server/src/services/execution-policy-bootstrap.test.ts b/server/src/services/execution-policy-bootstrap.test.ts new file mode 100644 index 00000000..21f197e0 --- /dev/null +++ b/server/src/services/execution-policy-bootstrap.test.ts @@ -0,0 +1,168 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const updateGeneral = vi.fn(); +const listCompanyIds = vi.fn(); +const ensureKubernetesEnvironment = vi.fn(); + +vi.mock("./instance-settings.js", () => ({ + instanceSettingsService: () => ({ + updateGeneral, + listCompanyIds, + }), +})); + +vi.mock("./environments.js", () => ({ + environmentService: () => ({ + ensureKubernetesEnvironment, + }), +})); + +const { + parseExecutionPolicyBootstrapEnv, + applyExecutionPolicyBootstrap, +} = await import("./execution-policy-bootstrap.js"); +type ExecutionPolicyBootstrapEnv = import("./execution-policy-bootstrap.js").ExecutionPolicyBootstrapEnv; +type ExecutionPolicyBootstrap = import("./execution-policy-bootstrap.js").ExecutionPolicyBootstrap; + +function env(overrides: Record): ExecutionPolicyBootstrapEnv { + return overrides; +} + +const bootstrap: ExecutionPolicyBootstrap = { + executionMode: "kubernetes", + kubernetesConfig: { inCluster: true, backend: "job" }, +}; + +// `applyExecutionPolicyBootstrap` constructs its services internally from the +// Db, so we mock the service modules; the Db itself is never touched here. +const fakeDb = {} as never; + +describe("parseExecutionPolicyBootstrapEnv", () => { + it("returns null when no execution mode is set (default unrestricted)", () => { + expect(parseExecutionPolicyBootstrapEnv(env({}))).toBeNull(); + }); + + it("returns null when execution mode is explicitly any", () => { + expect( + parseExecutionPolicyBootstrapEnv(env({ PAPERCLIP_EXECUTION_MODE: "any" })), + ).toBeNull(); + }); + + it("parses the forced kubernetes policy with a job/gvisor/cilium config", () => { + const parsed = parseExecutionPolicyBootstrapEnv( + env({ + PAPERCLIP_EXECUTION_MODE: "kubernetes", + PAPERCLIP_K8S_BACKEND: "job", + PAPERCLIP_K8S_IN_CLUSTER: "true", + PAPERCLIP_K8S_RUNTIME_CLASS_NAME: "gvisor", + PAPERCLIP_K8S_EGRESS_MODE: "cilium", + PAPERCLIP_K8S_EGRESS_ALLOW_FQDNS: "api.anthropic.com, api.openai.com", + PAPERCLIP_K8S_EGRESS_ALLOW_CIDRS: "10.0.0.0/8", + }), + ); + expect(parsed).not.toBeNull(); + expect(parsed?.executionMode).toBe("kubernetes"); + expect(parsed?.kubernetesConfig).toMatchObject({ + backend: "job", + inCluster: true, + runtimeClassName: "gvisor", + egressMode: "cilium", + egressAllowFqdns: ["api.anthropic.com", "api.openai.com"], + egressAllowCidrs: ["10.0.0.0/8"], + }); + }); + + it("defaults inCluster false and omits unset optional fields", () => { + const parsed = parseExecutionPolicyBootstrapEnv( + env({ PAPERCLIP_EXECUTION_MODE: "kubernetes" }), + ); + expect(parsed?.kubernetesConfig.inCluster).toBe(false); + expect(parsed?.kubernetesConfig.runtimeClassName).toBeUndefined(); + expect(parsed?.kubernetesConfig.egressAllowFqdns).toBeUndefined(); + }); + + it("throws on an unknown execution mode", () => { + expect(() => + parseExecutionPolicyBootstrapEnv(env({ PAPERCLIP_EXECUTION_MODE: "vm" })), + ).toThrow(/PAPERCLIP_EXECUTION_MODE/); + }); + + it("attaches the declared adapter registry to the kubernetes config", () => { + const parsed = parseExecutionPolicyBootstrapEnv( + env({ + PAPERCLIP_EXECUTION_MODE: "kubernetes", + PAPERCLIP_ADAPTERS: JSON.stringify([ + { adapterType: "opencode_local", runtimeImage: "img", envKeys: ["ANTHROPIC_API_KEY"], allowFqdns: [], probeCommand: ["opencode", "--version"], defaultEnv: { ANTHROPIC_BASE_URL: "http://bifrost:8080" } }, + ]), + }), + ); + expect(parsed?.kubernetesConfig.adapters).toHaveLength(1); + expect(parsed?.kubernetesConfig.adapters?.[0].adapterType).toBe("opencode_local"); + }); + + it("leaves adapters undefined when PAPERCLIP_ADAPTERS is absent", () => { + const parsed = parseExecutionPolicyBootstrapEnv(env({ PAPERCLIP_EXECUTION_MODE: "kubernetes" })); + expect(parsed?.kubernetesConfig.adapters).toBeUndefined(); + }); + + it("reads PAPERCLIP_K8S_RPC_TIMEOUT_MS into kubernetesConfig.timeoutMs", () => { + const parsed = parseExecutionPolicyBootstrapEnv( + env({ + PAPERCLIP_EXECUTION_MODE: "kubernetes", + PAPERCLIP_K8S_RPC_TIMEOUT_MS: "600000", + }), + ); + expect(parsed?.kubernetesConfig.timeoutMs).toBe(600000); + }); + + it("omits timeoutMs when PAPERCLIP_K8S_RPC_TIMEOUT_MS is absent", () => { + const parsed = parseExecutionPolicyBootstrapEnv(env({ PAPERCLIP_EXECUTION_MODE: "kubernetes" })); + expect(parsed?.kubernetesConfig.timeoutMs).toBeUndefined(); + }); + + it("throws when PAPERCLIP_K8S_RPC_TIMEOUT_MS is not a positive integer", () => { + expect(() => + parseExecutionPolicyBootstrapEnv( + env({ PAPERCLIP_EXECUTION_MODE: "kubernetes", PAPERCLIP_K8S_RPC_TIMEOUT_MS: "0" }), + ), + ).toThrow(/PAPERCLIP_K8S_RPC_TIMEOUT_MS/); + expect(() => + parseExecutionPolicyBootstrapEnv( + env({ PAPERCLIP_EXECUTION_MODE: "kubernetes", PAPERCLIP_K8S_RPC_TIMEOUT_MS: "abc" }), + ), + ).toThrow(/PAPERCLIP_K8S_RPC_TIMEOUT_MS/); + }); +}); + +describe("applyExecutionPolicyBootstrap", () => { + beforeEach(() => { + updateGeneral.mockReset().mockResolvedValue(undefined); + listCompanyIds.mockReset(); + ensureKubernetesEnvironment.mockReset(); + }); + + it("does not throw when every company gets a managed environment", async () => { + listCompanyIds.mockResolvedValue(["c1", "c2", "c3"]); + ensureKubernetesEnvironment.mockResolvedValue({ id: "env" }); + + const result = await applyExecutionPolicyBootstrap(fakeDb, bootstrap); + + expect(result).toEqual({ executionMode: "kubernetes", companiesConfigured: 3 }); + expect(ensureKubernetesEnvironment).toHaveBeenCalledTimes(3); + }); + + it("throws when at least one company fails, after attempting every company", async () => { + listCompanyIds.mockResolvedValue(["c1", "c2", "c3"]); + ensureKubernetesEnvironment.mockImplementation(async (companyId: string) => { + if (companyId === "c2") throw new Error("operator config missing"); + return { id: `env-${companyId}` }; + }); + + await expect(applyExecutionPolicyBootstrap(fakeDb, bootstrap)).rejects.toThrow( + /execution-policy bootstrap: 1 of 3 companies failed.*c2/, + ); + + // It keeps going past the failure (attempts all three companies). + expect(ensureKubernetesEnvironment).toHaveBeenCalledTimes(3); + }); +}); diff --git a/server/src/services/execution-policy-bootstrap.ts b/server/src/services/execution-policy-bootstrap.ts new file mode 100644 index 00000000..a8428843 --- /dev/null +++ b/server/src/services/execution-policy-bootstrap.ts @@ -0,0 +1,194 @@ +/** + * Cloud execution-policy bootstrap. + * + * Lets an operator / gitops deployment force the instance onto the Kubernetes + * sandbox provider purely via environment variables, with no manual product-API + * calls. On startup we: + * 1. Parse `PAPERCLIP_EXECUTION_MODE` (+ `PAPERCLIP_K8S_*`) from the env. + * 2. Persist `executionMode` into instance general settings (so the per-run + * heartbeat guard enforces it). + * 3. Idempotently ensure a configured Kubernetes sandbox environment for every + * company (mirrors `ensureLocalEnvironment`). + * + * The boot hook is *configuration convenience*; the actual security gate is the + * per-run guard in the heartbeat (see `execution-allowlist.ts`). Even with no + * boot hook, setting `executionMode=kubernetes` denies local execution. + * + * The env-var parsing is a pure function so it is trivially unit-testable. + */ + +import type { Db } from "@paperclipai/db"; +import type { InstanceExecutionMode } from "@paperclipai/shared"; +import { logger } from "../middleware/logger.js"; +import { environmentService, type KubernetesEnvironmentConfigInput } from "./environments.js"; +import { instanceSettingsService } from "./instance-settings.js"; +import { parseAdapterRegistryEnv } from "./adapter-registry-bootstrap.js"; + +export type ExecutionPolicyBootstrapEnv = Record; + +export interface ExecutionPolicyBootstrap { + executionMode: Extract; + kubernetesConfig: KubernetesEnvironmentConfigInput; +} + +function parseBool(value: string | undefined): boolean | undefined { + if (value === undefined) return undefined; + const v = value.trim().toLowerCase(); + if (v === "true" || v === "1" || v === "yes") return true; + if (v === "false" || v === "0" || v === "no") return false; + return undefined; +} + +function parsePositiveIntMs(value: string | undefined): number | undefined { + if (value === undefined) return undefined; + const trimmed = value.trim(); + if (trimmed.length === 0) return undefined; + const parsed = Number(trimmed); + if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed <= 0) { + throw new Error( + `PAPERCLIP_K8S_RPC_TIMEOUT_MS must be a positive integer of milliseconds (got "${value}").`, + ); + } + return parsed; +} + +function parseList(value: string | undefined): string[] | undefined { + if (value === undefined) return undefined; + const items = value + .split(",") + .map((s) => s.trim()) + .filter((s) => s.length > 0); + return items.length > 0 ? items : undefined; +} + +/** + * Parse the forced-execution-mode env config. Returns null when execution is + * unrestricted (no env, or `PAPERCLIP_EXECUTION_MODE=any`). Throws on an + * unrecognized mode so a misconfigured deployment fails loudly instead of + * silently allowing local execution. + */ +export function parseExecutionPolicyBootstrapEnv( + env: ExecutionPolicyBootstrapEnv, +): ExecutionPolicyBootstrap | null { + const raw = env.PAPERCLIP_EXECUTION_MODE?.trim(); + if (!raw || raw === "any") return null; + if (raw !== "kubernetes") { + throw new Error( + `PAPERCLIP_EXECUTION_MODE must be "kubernetes" or "any" (got "${raw}").`, + ); + } + + const kubernetesConfig: KubernetesEnvironmentConfigInput = { + // inCluster defaults to false (matches the plugin schema default); an + // in-cluster cloud deployment sets PAPERCLIP_K8S_IN_CLUSTER=true. + inCluster: parseBool(env.PAPERCLIP_K8S_IN_CLUSTER) ?? false, + }; + + const backend = env.PAPERCLIP_K8S_BACKEND?.trim(); + if (backend) { + if (backend !== "job" && backend !== "sandbox-cr") { + throw new Error( + `PAPERCLIP_K8S_BACKEND must be "job" or "sandbox-cr" (got "${backend}").`, + ); + } + kubernetesConfig.backend = backend; + } + + const egressMode = env.PAPERCLIP_K8S_EGRESS_MODE?.trim(); + if (egressMode) { + if (egressMode !== "cilium" && egressMode !== "standard") { + throw new Error( + `PAPERCLIP_K8S_EGRESS_MODE must be "cilium" or "standard" (got "${egressMode}").`, + ); + } + kubernetesConfig.egressMode = egressMode; + } + + const runtimeClassName = env.PAPERCLIP_K8S_RUNTIME_CLASS_NAME?.trim(); + if (runtimeClassName) kubernetesConfig.runtimeClassName = runtimeClassName; + + const namespacePrefix = env.PAPERCLIP_K8S_NAMESPACE_PREFIX?.trim(); + if (namespacePrefix) kubernetesConfig.namespacePrefix = namespacePrefix; + + const imageRegistry = env.PAPERCLIP_K8S_IMAGE_REGISTRY?.trim(); + if (imageRegistry) kubernetesConfig.imageRegistry = imageRegistry; + + const rpcTimeoutMs = parsePositiveIntMs(env.PAPERCLIP_K8S_RPC_TIMEOUT_MS); + if (rpcTimeoutMs !== undefined) kubernetesConfig.timeoutMs = rpcTimeoutMs; + + const adapterType = env.PAPERCLIP_K8S_ADAPTER_TYPE?.trim(); + if (adapterType) kubernetesConfig.adapterType = adapterType; + + const egressAllowFqdns = parseList(env.PAPERCLIP_K8S_EGRESS_ALLOW_FQDNS); + if (egressAllowFqdns) kubernetesConfig.egressAllowFqdns = egressAllowFqdns; + + const egressAllowCidrs = parseList(env.PAPERCLIP_K8S_EGRESS_ALLOW_CIDRS); + if (egressAllowCidrs) kubernetesConfig.egressAllowCidrs = egressAllowCidrs; + + const adapters = parseAdapterRegistryEnv(env); + if (adapters) kubernetesConfig.adapters = adapters; + + return { executionMode: "kubernetes", kubernetesConfig }; +} + +/** + * Apply the parsed bootstrap to the database: persist `executionMode` into + * instance settings and ensure a configured Kubernetes environment for every + * company. Idempotent; safe to call on every boot. + */ +export async function applyExecutionPolicyBootstrap( + db: Db, + bootstrap: ExecutionPolicyBootstrap, +): Promise<{ executionMode: InstanceExecutionMode; companiesConfigured: number }> { + const instanceSettings = instanceSettingsService(db); + const environments = environmentService(db); + + await instanceSettings.updateGeneral({ executionMode: bootstrap.executionMode }); + + const companyIds = await instanceSettings.listCompanyIds(); + let configured = 0; + const failedCompanyIds: string[] = []; + for (const companyId of companyIds) { + try { + await environments.ensureKubernetesEnvironment(companyId, bootstrap.kubernetesConfig); + configured += 1; + } catch (err) { + logger.error( + { err, companyId }, + "failed to ensure managed Kubernetes environment during execution-policy bootstrap", + ); + failedCompanyIds.push(companyId); + } + } + + logger.info( + { + executionMode: bootstrap.executionMode, + companiesConfigured: configured, + backend: bootstrap.kubernetesConfig.backend, + runtimeClassName: bootstrap.kubernetesConfig.runtimeClassName, + egressMode: bootstrap.kubernetesConfig.egressMode, + }, + "applied forced Kubernetes execution policy", + ); + + if (failedCompanyIds.length > 0) { + throw new Error( + `execution-policy bootstrap: ${failedCompanyIds.length} of ${companyIds.length} companies failed to get a managed Kubernetes environment under executionMode=${bootstrap.executionMode}; refusing to start (companies: ${failedCompanyIds.join(", ")})`, + ); + } + + return { executionMode: bootstrap.executionMode, companiesConfigured: configured }; +} + +/** + * Convenience: parse + apply from a raw env map. Returns null when unrestricted. + */ +export async function bootstrapExecutionPolicyFromEnv( + db: Db, + env: ExecutionPolicyBootstrapEnv = process.env, +): Promise<{ executionMode: InstanceExecutionMode; companiesConfigured: number } | null> { + const bootstrap = parseExecutionPolicyBootstrapEnv(env); + if (!bootstrap) return null; + return applyExecutionPolicyBootstrap(db, bootstrap); +} diff --git a/server/src/services/heartbeat.ts b/server/src/services/heartbeat.ts index b88d6995..deec2ab6 100644 --- a/server/src/services/heartbeat.ts +++ b/server/src/services/heartbeat.ts @@ -132,6 +132,10 @@ import { resolveExecutionWorkspaceMode, } from "./execution-workspace-policy.js"; import { instanceSettingsService } from "./instance-settings.js"; +import { + evaluateExecutionAllowlist, + isExecutionForcedToKubernetes, +} from "./execution-allowlist.js"; import { RECOVERY_ORIGIN_KINDS, FINISH_SUCCESSFUL_RUN_HANDOFF_REASON, @@ -182,6 +186,7 @@ import { } from "@paperclipai/adapter-utils/server-utils"; import { extractSkillMentionIds, isUuidLike } from "@paperclipai/shared"; import { environmentService } from "./environments.js"; +import { parseExecutionPolicyBootstrapEnv } from "./execution-policy-bootstrap.js"; import { environmentRuntimeService } from "./environment-runtime.js"; import { environmentRunOrchestrator } from "./environment-run-orchestrator.js"; import { isUnsafeSessionWorkspaceCwd } from "./session-workspace-cwd.js"; @@ -8081,7 +8086,72 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {}) persistedExecutionWorkspaceMode === "agent_default" ? persistedExecutionWorkspaceMode : requestedExecutionWorkspaceMode; - const selectedEnvironmentId = environmentResolution.environmentId; + const executionPolicy = { executionMode: (await instanceSettings.getGeneral()).executionMode }; + let selectedEnvironmentId = environmentResolution.environmentId; + if (isExecutionForcedToKubernetes(executionPolicy)) { + let kubernetesEnvironment = await environmentsSvc.findKubernetesEnvironment(agent.companyId); + if (!kubernetesEnvironment) { + // Lazy recovery for companies created after the startup bootstrap ran + // (the boot hook only provisions environments for companies that exist + // at boot). Re-derive the managed-env config from the bootstrap env. + // If the process env no longer forces Kubernetes (rollback / config + // drift relative to the persisted executionMode setting), skip the + // provisioning gracefully: the guard below still refuses local + // fallback with the explicit error, instead of crashing here on + // undefined config. + let bootstrap: ReturnType = null; + let bootstrapSkipReason: string | null = null; + try { + bootstrap = parseExecutionPolicyBootstrapEnv(process.env); + if (!bootstrap) { + bootstrapSkipReason = + 'PAPERCLIP_EXECUTION_MODE bootstrap env is not kubernetes-forced (absent or "any")'; + } + } catch (err) { + bootstrapSkipReason = `PAPERCLIP_EXECUTION_MODE bootstrap env failed to parse: ${ + err instanceof Error ? err.message : String(err) + }`; + } + if (bootstrap) { + await environmentsSvc.ensureKubernetesEnvironment( + agent.companyId, + bootstrap.kubernetesConfig, + ); + kubernetesEnvironment = await environmentsSvc.findKubernetesEnvironment(agent.companyId); + } else { + logger.warn( + { + runId: run.id, + agentId: agent.id, + companyId: agent.companyId, + reason: bootstrapSkipReason, + }, + "executionMode=kubernetes is persisted but the bootstrap env cannot provision a managed Kubernetes environment; skipping lazy provisioning for this company (the run will fail with the explicit no-managed-environment error)", + ); + } + } + if (!kubernetesEnvironment) { + throw new Error( + "Instance execution policy requires the Kubernetes sandbox provider " + + "(executionMode=kubernetes) but no managed Kubernetes environment is " + + "configured for this company. Configure one (PAPERCLIP_K8S_* env on the " + + "cloud instance) before running agents; refusing to fall back to local execution.", + ); + } + if (kubernetesEnvironment.id !== selectedEnvironmentId) { + logger.info( + { + runId: run.id, + issueId, + agentId: agent.id, + resolvedEnvironmentId: selectedEnvironmentId, + forcedKubernetesEnvironmentId: kubernetesEnvironment.id, + }, + "Forcing run onto the managed Kubernetes environment (executionMode=kubernetes)", + ); + } + selectedEnvironmentId = kubernetesEnvironment.id; + } const { selectedEnvironmentDriver: lowTrustPreflightEnvironmentDriver, workspace: resolvedWorkspace, @@ -8402,7 +8472,13 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {}) }) .where(eq(heartbeatRuns.id, run.id)); } - const persistedEnvironmentId = persistedExecutionWorkspace?.config?.environmentId ?? selectedEnvironmentId; + // When execution is forced to Kubernetes, `selectedEnvironmentId` is already + // pinned to the managed k8s environment above; ignore any persisted workspace + // environmentId (which could point at a stale local/ssh env) so a reused + // workspace can never downgrade us off the sandbox. + const persistedEnvironmentId = isExecutionForcedToKubernetes(executionPolicy) + ? selectedEnvironmentId + : persistedExecutionWorkspace?.config?.environmentId ?? selectedEnvironmentId; const acquiredEnvironment = await envOrchestrator.acquireForRun({ companyId: agent.companyId, selectedEnvironmentId: persistedEnvironmentId, @@ -8414,6 +8490,30 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {}) persistedExecutionWorkspace, }); const selectedEnvironment = acquiredEnvironment.environment; + // Defense-in-depth: re-check the actually-acquired environment against the + // execution allowlist. Even if selection were bypassed, a denied (local/ssh/ + // non-k8s) environment FAILS the run here rather than executing untrusted. + const allowlistDecision = evaluateExecutionAllowlist(executionPolicy, { + driver: selectedEnvironment.driver, + provider: + typeof selectedEnvironment.config?.provider === "string" + ? selectedEnvironment.config.provider + : null, + }); + if (!allowlistDecision.allowed) { + logger.error( + { + runId: run.id, + issueId, + agentId: agent.id, + environmentId: selectedEnvironment.id, + deniedDriver: allowlistDecision.deniedDriver, + deniedProvider: allowlistDecision.deniedProvider, + }, + "Execution allowlist denied the resolved environment; failing run", + ); + throw new Error(allowlistDecision.reason); + } let activeEnvironmentLease = { environment: acquiredEnvironment.environment, lease: acquiredEnvironment.lease, diff --git a/server/src/services/index.ts b/server/src/services/index.ts index 7affa2e9..c299687c 100644 --- a/server/src/services/index.ts +++ b/server/src/services/index.ts @@ -62,6 +62,7 @@ export type { } from "./authorization.js"; export { boardAuthService } from "./board-auth.js"; export { instanceSettingsService } from "./instance-settings.js"; +export { bootstrapExecutionPolicyFromEnv } from "./execution-policy-bootstrap.js"; export { cloudUpstreamService, reconcileCloudUpstreamRunsOnStartup } from "./cloud-upstreams.js"; export { companyPortabilityService } from "./company-portability.js"; export { teamsCatalogService } from "./teams-catalog.js"; diff --git a/server/src/services/instance-settings.ts b/server/src/services/instance-settings.ts index 170c8ca2..22b71466 100644 --- a/server/src/services/instance-settings.ts +++ b/server/src/services/instance-settings.ts @@ -27,6 +27,8 @@ function normalizeGeneralSettings(raw: unknown): InstanceGeneralSettings { feedbackDataSharingPreference: parsed.data.feedbackDataSharingPreference ?? DEFAULT_FEEDBACK_DATA_SHARING_PREFERENCE, backupRetention: parsed.data.backupRetention ?? DEFAULT_BACKUP_RETENTION, + // Absent => unrestricted; only carry through an explicit policy. + ...(parsed.data.executionMode ? { executionMode: parsed.data.executionMode } : {}), }; } return { diff --git a/server/src/services/plugin-loader.ts b/server/src/services/plugin-loader.ts index 8d7c10bc..0424f0b1 100644 --- a/server/src/services/plugin-loader.ts +++ b/server/src/services/plugin-loader.ts @@ -79,6 +79,16 @@ export const DEFAULT_LOCAL_PLUGIN_DIR = path.join( const DEV_TSX_LOADER_PATH = path.resolve(__dirname, "../../../cli/node_modules/tsx/dist/loader.mjs"); +/** + * Model-provider API keys that sandbox-provider plugins (e.g. + * `@paperclipai/plugin-kubernetes`) are allowed to read from the + * server's process environment so they can inject them into per-run + * pod Secrets. All other host env vars remain stripped from plugin + * workers (see `PluginWorkerManager.spawnProcess`). The passthrough + * is gated on the plugin manifest declaring + * `environment.drivers.register` โ€” non-sandbox plugins never receive + * these keys. + */ const ADAPTER_ENV_PASSTHROUGH = [ "ANTHROPIC_API_KEY", "OPENAI_API_KEY", @@ -87,6 +97,21 @@ const ADAPTER_ENV_PASSTHROUGH = [ "OPENROUTER_API_KEY", ]; +/** + * In-cluster Kubernetes service-discovery vars. A sandbox-provider plugin that + * runs in-cluster (e.g. `@paperclipai/plugin-kubernetes` with inCluster=true) + * builds its API client via `KubeConfig.loadFromCluster()`, which reads these + * to construct the apiserver URL. Without them the worker fails with "Invalid + * URL" at lease acquisition. The CA + token are files under + * /var/run/secrets/kubernetes.io/serviceaccount and are readable directly. + * Gated, like ADAPTER_ENV_PASSTHROUGH, on environment-driver registration. + */ +const K8S_IN_CLUSTER_ENV_PASSTHROUGH = [ + "KUBERNETES_SERVICE_HOST", + "KUBERNETES_SERVICE_PORT", + "KUBERNETES_SERVICE_PORT_HTTPS", +]; + export function buildPluginWorkerEnv(input: { manifest: Pick; instanceInfo: { deploymentMode?: string | null; deploymentExposure?: string | null }; @@ -101,7 +126,7 @@ export function buildPluginWorkerEnv(input: { && input.manifest.capabilities.includes("environment.drivers.register"); if (!canRegisterEnvironmentDrivers) return env; - for (const key of ADAPTER_ENV_PASSTHROUGH) { + for (const key of [...ADAPTER_ENV_PASSTHROUGH, ...K8S_IN_CLUSTER_ENV_PASSTHROUGH]) { const value = processEnv[key]; if (value && value.trim().length > 0) { env[key] = value; diff --git a/ui/src/components/AgentConfigForm.test.ts b/ui/src/components/AgentConfigForm.test.ts index e532c8eb..09905880 100644 --- a/ui/src/components/AgentConfigForm.test.ts +++ b/ui/src/components/AgentConfigForm.test.ts @@ -1,5 +1,7 @@ import { describe, expect, it } from "vitest"; +import type { Environment } from "@paperclipai/shared"; import { supportsAdapterModelRefresh } from "./AgentConfigForm"; +import { resolveForcedKubernetesEnvironment } from "../lib/forced-kubernetes-environment"; describe("supportsAdapterModelRefresh", () => { it("enables the model refresh action for Claude, Codex, and ACPX adapters", () => { @@ -13,3 +15,58 @@ describe("supportsAdapterModelRefresh", () => { expect(supportsAdapterModelRefresh("process")).toBe(false); }); }); + +function makeEnvironment(overrides: Partial): Environment { + return { + id: "env-1", + companyId: "co-1", + name: "Env", + description: null, + driver: "local", + status: "active", + config: {}, + metadata: null, + createdAt: new Date(0), + updatedAt: new Date(0), + ...overrides, + }; +} + +const localEnv = makeEnvironment({ id: "local-1", name: "Local", driver: "local" }); +const k8sEnv = makeEnvironment({ + id: "k8s-1", + name: "Managed K8s", + driver: "sandbox", + config: { provider: "kubernetes" }, +}); + +describe("resolveForcedKubernetesEnvironment", () => { + it("does not force when executionMode is 'any' (full picker / unchanged)", () => { + const result = resolveForcedKubernetesEnvironment("any", [localEnv, k8sEnv]); + expect(result.forced).toBe(false); + expect(result.kubernetesEnvironment).toBeNull(); + }); + + it("does not force when executionMode is absent (self-hoster default)", () => { + const result = resolveForcedKubernetesEnvironment(undefined, [localEnv, k8sEnv]); + expect(result.forced).toBe(false); + expect(result.kubernetesEnvironment).toBeNull(); + }); + + it("forces and selects the Kubernetes sandbox when executionMode is 'kubernetes'", () => { + const result = resolveForcedKubernetesEnvironment("kubernetes", [localEnv, k8sEnv]); + expect(result.forced).toBe(true); + expect(result.kubernetesEnvironment?.id).toBe("k8s-1"); + }); + + it("forces but reports no environment when none is the Kubernetes sandbox", () => { + const fakeSandbox = makeEnvironment({ + id: "fake-1", + driver: "sandbox", + config: { provider: "fake" }, + }); + const result = resolveForcedKubernetesEnvironment("kubernetes", [localEnv, fakeSandbox]); + expect(result.forced).toBe(true); + expect(result.kubernetesEnvironment).toBeNull(); + }); +}); diff --git a/ui/src/components/AgentConfigForm.tsx b/ui/src/components/AgentConfigForm.tsx index 264e61e9..342a7583 100644 --- a/ui/src/components/AgentConfigForm.tsx +++ b/ui/src/components/AgentConfigForm.tsx @@ -55,6 +55,7 @@ import { useDisabledAdaptersSync } from "../adapters/use-disabled-adapters"; import { buildAgentUpdatePatch, type AgentConfigOverlay } from "../lib/agent-config-patch"; import { useAdapterCapabilities } from "../adapters/use-adapter-capabilities"; import { filterAcpxModelsByAgent } from "../lib/acpx-model-filter"; +import { resolveForcedKubernetesEnvironment } from "../lib/forced-kubernetes-environment"; /* ---- Create mode values ---- */ @@ -223,11 +224,33 @@ export function AgentConfigForm(props: AgentConfigFormProps) { }); const environmentsEnabled = experimentalSettings?.enableEnvironments === true; + // Instance execution policy (general settings). When `executionMode` is + // "kubernetes" the instance FORCES all execution onto the managed Kubernetes + // sandbox; "any"/absent leaves the full environment/adapter choice intact. + // Reuses the same general-settings query the rest of the UI uses. + const { data: generalSettings } = useQuery({ + queryKey: queryKeys.instance.generalSettings, + queryFn: () => instanceSettingsApi.getGeneral(), + retry: false, + }); + const { data: environments = [] } = useQuery({ queryKey: selectedCompanyId ? queryKeys.environments.list(selectedCompanyId) : ["environments", "none"], queryFn: () => environmentsApi.list(selectedCompanyId!), - enabled: Boolean(selectedCompanyId) && environmentsEnabled, + // Load environments when the picker is enabled OR when execution is forced + // onto Kubernetes (so we can resolve and default to the managed K8s env even + // when the experimental environments picker is otherwise hidden). + enabled: + Boolean(selectedCompanyId) && + (environmentsEnabled || generalSettings?.executionMode === "kubernetes"), }); + + // Setting-driven: resolve whether the instance forces Kubernetes execution and + // which loaded environment is the managed Kubernetes sandbox. + const { forced: forcedKubernetes, kubernetesEnvironment } = useMemo( + () => resolveForcedKubernetesEnvironment(generalSettings?.executionMode, environments), + [generalSettings?.executionMode, environments], + ); const createSecret = useMutation({ mutationFn: (input: { name: string; value: string }) => { if (!selectedCompanyId) throw new Error("Select a company to create secrets"); @@ -336,6 +359,17 @@ export function AgentConfigForm(props: AgentConfigFormProps) { () => environments.find((environment) => environment.id === currentDefaultEnvironmentId) ?? null, [currentDefaultEnvironmentId, environments], ); + + // When the instance forces Kubernetes execution, new agents must default to the + // managed Kubernetes sandbox environment (never the implicit local default). + // Only applies in create mode and only once the K8s environment is loaded; if + // none is available the UI surfaces a notice instead of silently selecting it. + useEffect(() => { + if (!isCreate || !set || !forcedKubernetes || !kubernetesEnvironment) return; + if (currentDefaultEnvironmentId === kubernetesEnvironment.id) return; + set({ defaultEnvironmentId: kubernetesEnvironment.id }); + }, [isCreate, set, forcedKubernetes, kubernetesEnvironment, currentDefaultEnvironmentId]); + const runnableEnvironments = useMemo( () => environments.filter((environment) => { if (!supportedEnvironmentDrivers.has(environment.driver)) return false; @@ -782,7 +816,35 @@ export function AgentConfigForm(props: AgentConfigFormProps) { )} {/* ---- Execution ---- */} - {environmentsEnabled ? ( + {forcedKubernetes ? ( + // Instance execution policy forces the managed Kubernetes sandbox + // (executionMode=kubernetes): never offer local / non-Kubernetes targets. + // Render the environment read-only instead of the selectable picker. +
+ {cards + ?

Execution

+ :
Execution
+ } +
+ + {kubernetesEnvironment ? ( +
+ {kubernetesEnvironment.name} ยท Kubernetes sandbox +
+ ) : ( +
+ This instance requires the Kubernetes sandbox, but no managed Kubernetes + environment is available for this company yet. Configure one before creating + agents; execution will not fall back to local. +
+ )} +
+
+
+ ) : environmentsEnabled ? (
{cards ?

Execution

diff --git a/ui/src/lib/forced-kubernetes-environment.ts b/ui/src/lib/forced-kubernetes-environment.ts new file mode 100644 index 00000000..61ffd477 --- /dev/null +++ b/ui/src/lib/forced-kubernetes-environment.ts @@ -0,0 +1,56 @@ +import type { Environment, InstanceExecutionMode } from "@paperclipai/shared"; + +/** + * Provider key (== plugin driverKey) of the first-party Kubernetes sandbox + * provider. Mirrors `KUBERNETES_PROVIDER_KEY` in the server-side execution + * allowlist. Kept local to the UI because the allowlist module lives in the + * server package and must not be imported by the client bundle. + */ +export const KUBERNETES_PROVIDER_KEY = "kubernetes" as const; + +/** + * True iff the environment is the Kubernetes sandbox provider, i.e. a core + * `sandbox` driver whose `config.provider` is "kubernetes". Mirrors the + * server-side `isKubernetesSandboxEnvironment` guard so the UI selects exactly + * the environment the server forces execution onto. + */ +export function isKubernetesSandboxEnvironment(environment: Environment): boolean { + if (environment.driver !== "sandbox") return false; + const provider = environment.config?.provider; + return provider === KUBERNETES_PROVIDER_KEY; +} + +export interface ForcedKubernetesEnvironment { + /** + * Whether the instance execution policy forces all execution onto the + * Kubernetes sandbox. Driven entirely by the `executionMode` instance general + * setting: `"kubernetes"` forces; `"any"`/absent does not. A self-hoster who + * keeps the default `"any"` retains the full environment/adapter picker. + */ + forced: boolean; + /** + * The company's managed Kubernetes sandbox environment, if one is present in + * the loaded environment list. `null` when forced but no such environment is + * available yet (the UI should show a clear notice rather than silently + * defaulting to local). + */ + kubernetesEnvironment: Environment | null; +} + +/** + * Resolve whether execution is forced onto Kubernetes and, if so, which loaded + * environment is the Kubernetes sandbox. Pure so it can be unit-tested without + * rendering. + */ +export function resolveForcedKubernetesEnvironment( + executionMode: InstanceExecutionMode | undefined, + environments: readonly Environment[], +): ForcedKubernetesEnvironment { + const forced = executionMode === "kubernetes"; + if (!forced) { + return { forced: false, kubernetesEnvironment: null }; + } + const kubernetesEnvironment = + environments.find((environment) => isKubernetesSandboxEnvironment(environment)) ?? null; + return { forced: true, kubernetesEnvironment }; +} diff --git a/ui/storybook/stories/agent-management.stories.tsx b/ui/storybook/stories/agent-management.stories.tsx index 095b624c..b40512c9 100644 --- a/ui/storybook/stories/agent-management.stories.tsx +++ b/ui/storybook/stories/agent-management.stories.tsx @@ -8,6 +8,7 @@ import { type AgentRuntimeState, type CompanySecret, type EnvBinding, + type Environment, } from "@paperclipai/shared"; import { ActiveAgentsPanel } from "@/components/ActiveAgentsPanel"; import { AgentConfigForm, type CreateConfigValues } from "@/components/AgentConfigForm"; @@ -774,3 +775,88 @@ export default meta; type Story = StoryObj; export const ManagementMatrix: Story = {}; + +/* ---- Forced Kubernetes execution (instance executionMode=kubernetes) ---- */ + +const managedKubernetesEnvironment: Environment = { + id: "env-k8s-storybook", + companyId: COMPANY_ID, + name: "Kubernetes Sandbox", + description: "Managed Kubernetes sandbox environment for hosted tenant execution.", + driver: "sandbox", + status: "active", + config: { + provider: "kubernetes", + backend: "job", + inCluster: true, + runtimeClassName: "gvisor", + egressMode: "cilium", + }, + metadata: { managedByPaperclip: true, managedKubernetesSandbox: true }, + createdAt: recent(2_000), + updatedAt: recent(60), +}; + +function ForcedKubernetesFixtures({ + environmentFixtures, + children, +}: { + environmentFixtures: Environment[]; + children: ReactNode; +}) { + const queryClient = useQueryClient(); + + queryClient.setQueryData(queryKeys.agents.list(COMPANY_ID), agentManagementAgents); + queryClient.setQueryData(queryKeys.secrets.list(COMPANY_ID), storybookSecrets); + queryClient.setQueryData(queryKeys.adapters.all, adapterFixtures); + // The instance-level execution policy that forces all agent execution onto + // the managed Kubernetes sandbox (PAPERCLIP_EXECUTION_MODE=kubernetes). + queryClient.setQueryData(queryKeys.instance.generalSettings, { + censorUsernameInLogs: false, + executionMode: "kubernetes", + }); + queryClient.setQueryData(queryKeys.environments.list(COMPANY_ID), environmentFixtures); + queryClient.setQueryData(queryKeys.agents.adapterModels(COMPANY_ID, "codex_local"), [ + { id: "gpt-5.4", label: "GPT-5.4" }, + { id: "gpt-5.4-mini", label: "GPT-5.4 Mini" }, + ]); + + return children; +} + +function ForcedKubernetesStory({ environmentFixtures }: { environmentFixtures: Environment[] }) { + return ( + +
+
+
+
+ +
+
+
+
+
+ ); +} + +/** + * Instance execution policy forces Kubernetes and the company has a managed + * Kubernetes sandbox environment: the Execution section renders the + * environment read-only (no local/SSH picker). + */ +export const ForcedKubernetesExecution: Story = { + render: () => , +}; + +/** + * Instance execution policy forces Kubernetes but no managed environment is + * available for the company yet: the Execution section shows the warning + * notice instead of silently falling back to local execution. + */ +export const ForcedKubernetesMissingEnvironment: Story = { + render: () => , +};