forked from farhoodlabs/paperclip
fix(plugin): warn on missing kubernetes adapter env
This commit is contained in:
@@ -68,7 +68,7 @@ Common optional fields:
|
||||
| `imageAllowList` | `[]` | Glob patterns of allowed `target.imageOverride` values. Empty = no override permitted. |
|
||||
| `imagePullSecrets` | `[]` | Names of pre-created Docker image pull secrets in the tenant namespace. |
|
||||
| `egressAllowFqdns` | `[]` | Additional FQDNs (beyond adapter defaults like `api.anthropic.com`). |
|
||||
| `egressAllowCidrs` | `[]` | Additional CIDRs to allow egress to. |
|
||||
| `egressAllowCidrs` | `[]` | Additional CIDRs to allow HTTPS egress to. CIDR egress is restricted to TCP port 443. |
|
||||
| `egressMode` | `"standard"` | `standard` (NetworkPolicy + CIDRs, plus public HTTPS fallback when adapter FQDNs are configured) or `cilium` (CiliumNetworkPolicy + exact FQDN allow-list). |
|
||||
| `runtimeClassName` | (none) | e.g. `kata-fc` for Firecracker-backed microVMs. Cluster must have the RuntimeClass installed. |
|
||||
| `serviceAccountAnnotations` | `{}` | Annotations applied to per-tenant ServiceAccount (e.g. IRSA `eks.amazonaws.com/role-arn`). |
|
||||
|
||||
@@ -72,7 +72,7 @@ const manifest: PaperclipPluginManifestV1 = {
|
||||
egressAllowCidrs: {
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
description: "Additional CIDRs to allow egress to from agent pods.",
|
||||
description: "Additional CIDRs to allow HTTPS egress to from agent pods. CIDR egress is restricted to TCP port 443.",
|
||||
},
|
||||
egressMode: {
|
||||
type: "string",
|
||||
|
||||
@@ -72,11 +72,24 @@ function deriveTenantNamespace(config: KubernetesProviderConfig, companyId: stri
|
||||
* TODO: future milestones may thread per-run secrets differently (e.g. via
|
||||
* a secret store reference on the environment config).
|
||||
*/
|
||||
function extractAdapterEnvFromProcess(envKeys: string[]): Record<string, string> {
|
||||
export function extractAdapterEnvFromProcess(
|
||||
envKeys: string[],
|
||||
warn: (message: string) => void = console.warn,
|
||||
): Record<string, string> {
|
||||
const out: Record<string, string> = {};
|
||||
const missing: string[] = [];
|
||||
for (const k of envKeys) {
|
||||
const v = process.env[k];
|
||||
if (v) out[k] = v;
|
||||
if (v) {
|
||||
out[k] = v;
|
||||
} else {
|
||||
missing.push(k);
|
||||
}
|
||||
}
|
||||
if (missing.length > 0) {
|
||||
warn(
|
||||
`[plugin-kubernetes] adapter environment variable(s) missing from plugin worker process: ${missing.join(", ")}. Agent pods may fail provider authentication unless these keys are optional for the selected adapter.`,
|
||||
);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import manifest from "../../src/manifest.js";
|
||||
|
||||
describe("manifest", () => {
|
||||
const configSchema = manifest.environmentDrivers[0]?.configSchema as {
|
||||
properties: Record<string, { const?: unknown; maxLength?: number; pattern?: string }>;
|
||||
properties: Record<string, { const?: unknown; description?: string; maxLength?: number; pattern?: string }>;
|
||||
anyOf: Array<{
|
||||
properties?: Record<string, { const?: unknown }>;
|
||||
required?: string[];
|
||||
@@ -23,4 +23,8 @@ describe("manifest", () => {
|
||||
});
|
||||
expect(configSchema.anyOf).toContainEqual({ required: ["kubeconfig"] });
|
||||
});
|
||||
|
||||
it("documents that CIDR egress is HTTPS-only", () => {
|
||||
expect(configSchema.properties.egressAllowCidrs.description).toContain("TCP port 443");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import plugin from "../../src/plugin.js";
|
||||
import plugin, { extractAdapterEnvFromProcess } from "../../src/plugin.js";
|
||||
|
||||
describe("plugin", () => {
|
||||
it("exports the kubernetes driver", () => {
|
||||
@@ -91,4 +91,33 @@ describe("plugin", () => {
|
||||
expect(result.ok).toBe(true);
|
||||
expect(result.warnings).toBeUndefined();
|
||||
});
|
||||
|
||||
it("warns when adapter env keys are missing from the worker process", () => {
|
||||
const warnMessages: string[] = [];
|
||||
const originalPresent = process.env.PAPERCLIP_TEST_PRESENT_KEY;
|
||||
const originalMissing = process.env.PAPERCLIP_TEST_MISSING_KEY;
|
||||
process.env.PAPERCLIP_TEST_PRESENT_KEY = "secret-value";
|
||||
delete process.env.PAPERCLIP_TEST_MISSING_KEY;
|
||||
try {
|
||||
const result = extractAdapterEnvFromProcess(
|
||||
["PAPERCLIP_TEST_PRESENT_KEY", "PAPERCLIP_TEST_MISSING_KEY"],
|
||||
(message) => warnMessages.push(message),
|
||||
);
|
||||
expect(result).toEqual({ PAPERCLIP_TEST_PRESENT_KEY: "secret-value" });
|
||||
expect(warnMessages).toHaveLength(1);
|
||||
expect(warnMessages[0]).toContain("PAPERCLIP_TEST_MISSING_KEY");
|
||||
expect(warnMessages[0]).not.toContain("secret-value");
|
||||
} finally {
|
||||
if (originalPresent === undefined) {
|
||||
delete process.env.PAPERCLIP_TEST_PRESENT_KEY;
|
||||
} else {
|
||||
process.env.PAPERCLIP_TEST_PRESENT_KEY = originalPresent;
|
||||
}
|
||||
if (originalMissing === undefined) {
|
||||
delete process.env.PAPERCLIP_TEST_MISSING_KEY;
|
||||
} else {
|
||||
process.env.PAPERCLIP_TEST_MISSING_KEY = originalMissing;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user