@paperclipai/plugin-kubernetes 0.1.0 → 2026.620.0-canary.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapter-defaults.d.ts +29 -0
  3. package/dist/adapter-defaults.d.ts.map +1 -0
  4. package/dist/adapter-defaults.js +104 -0
  5. package/dist/adapter-defaults.js.map +1 -0
  6. package/dist/adapter-registry.d.ts +64 -0
  7. package/dist/adapter-registry.d.ts.map +1 -0
  8. package/dist/adapter-registry.js +25 -0
  9. package/dist/adapter-registry.js.map +1 -0
  10. package/dist/cilium-network-policy.d.ts +8 -0
  11. package/dist/cilium-network-policy.d.ts.map +1 -0
  12. package/dist/cilium-network-policy.js +57 -0
  13. package/dist/cilium-network-policy.js.map +1 -0
  14. package/dist/image-allowlist.d.ts +18 -0
  15. package/dist/image-allowlist.d.ts.map +1 -0
  16. package/dist/image-allowlist.js +39 -0
  17. package/dist/image-allowlist.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +3 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/job-orchestrator.d.ts +24 -0
  23. package/dist/job-orchestrator.d.ts.map +1 -0
  24. package/dist/job-orchestrator.js +90 -0
  25. package/dist/job-orchestrator.js.map +1 -0
  26. package/dist/kube-client.d.ts +15 -0
  27. package/dist/kube-client.d.ts.map +1 -0
  28. package/dist/kube-client.js +23 -0
  29. package/dist/kube-client.js.map +1 -0
  30. package/dist/lease-lifecycle.d.ts +62 -0
  31. package/dist/lease-lifecycle.d.ts.map +1 -0
  32. package/dist/lease-lifecycle.js +155 -0
  33. package/dist/lease-lifecycle.js.map +1 -0
  34. package/dist/manifest.d.ts +4 -0
  35. package/dist/manifest.d.ts.map +1 -0
  36. package/dist/manifest.js +108 -0
  37. package/dist/manifest.js.map +1 -0
  38. package/dist/network-policy.d.ts +18 -0
  39. package/dist/network-policy.d.ts.map +1 -0
  40. package/dist/network-policy.js +113 -0
  41. package/dist/network-policy.js.map +1 -0
  42. package/dist/plugin.d.ts +3 -0
  43. package/dist/plugin.d.ts.map +1 -0
  44. package/dist/plugin.js +687 -0
  45. package/dist/plugin.js.map +1 -0
  46. package/dist/pod-exec.d.ts +28 -0
  47. package/dist/pod-exec.d.ts.map +1 -0
  48. package/dist/pod-exec.js +164 -0
  49. package/dist/pod-exec.js.map +1 -0
  50. package/dist/pod-spec-builder.d.ts +25 -0
  51. package/dist/pod-spec-builder.d.ts.map +1 -0
  52. package/dist/pod-spec-builder.js +82 -0
  53. package/dist/pod-spec-builder.js.map +1 -0
  54. package/dist/sandbox-cr-builder.d.ts +40 -0
  55. package/dist/sandbox-cr-builder.d.ts.map +1 -0
  56. package/dist/sandbox-cr-builder.js +123 -0
  57. package/dist/sandbox-cr-builder.js.map +1 -0
  58. package/dist/sandbox-cr-orchestrator.d.ts +62 -0
  59. package/dist/sandbox-cr-orchestrator.d.ts.map +1 -0
  60. package/dist/sandbox-cr-orchestrator.js +248 -0
  61. package/dist/sandbox-cr-orchestrator.js.map +1 -0
  62. package/dist/sandbox-orchestrator.d.ts +39 -0
  63. package/dist/sandbox-orchestrator.d.ts.map +1 -0
  64. package/dist/sandbox-orchestrator.js +2 -0
  65. package/dist/sandbox-orchestrator.js.map +1 -0
  66. package/dist/secret-manager.d.ts +14 -0
  67. package/dist/secret-manager.d.ts.map +1 -0
  68. package/dist/secret-manager.js +39 -0
  69. package/dist/secret-manager.js.map +1 -0
  70. package/dist/tenant-orchestrator.d.ts +35 -0
  71. package/dist/tenant-orchestrator.d.ts.map +1 -0
  72. package/dist/tenant-orchestrator.js +263 -0
  73. package/dist/tenant-orchestrator.js.map +1 -0
  74. package/dist/types.d.ts +264 -0
  75. package/dist/types.d.ts.map +1 -0
  76. package/dist/types.js +65 -0
  77. package/dist/types.js.map +1 -0
  78. package/dist/upload-interceptor.d.ts +44 -0
  79. package/dist/upload-interceptor.d.ts.map +1 -0
  80. package/dist/upload-interceptor.js +114 -0
  81. package/dist/upload-interceptor.js.map +1 -0
  82. package/dist/utils.d.ts +11 -0
  83. package/dist/utils.d.ts.map +1 -0
  84. package/dist/utils.js +51 -0
  85. package/dist/utils.js.map +1 -0
  86. package/dist/worker.d.ts +3 -0
  87. package/dist/worker.d.ts.map +1 -0
  88. package/dist/worker.js +5 -0
  89. package/dist/worker.js.map +1 -0
  90. package/package.json +4 -12
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Resume + destroy lifecycle helpers for Kubernetes sandbox leases.
3
+ *
4
+ * Resume semantics: a lease is resumable only while its workload resource
5
+ * (Sandbox CR or Job) still exists and its pod is Running/Ready (or becomes
6
+ * Ready within a short bounded wait). Unlike Daytona — where a stopped sandbox
7
+ * can be started again by ID — Kubernetes pods are NOT restartable: once the
8
+ * pod backing a lease is gone or terminally failed, the lease can never be
9
+ * revived in place. That asymmetry is intentional; the plugin reports the
10
+ * lease as expired and the server falls back to a fresh acquireLease, which
11
+ * provisions a new pod.
12
+ *
13
+ * Destroy semantics: the forced cleanup path. Deletes every resource
14
+ * acquireLease created (Sandbox CR / Job, its pod, the per-run Secret),
15
+ * treating 404s as success so it is idempotent and safe to call against
16
+ * half-deleted leases.
17
+ */
18
+ import type { KubeClients } from "./kube-client.js";
19
+ /** True when a Kubernetes API error means "resource not found" (HTTP 404). */
20
+ export declare function isKubeNotFoundError(err: unknown): boolean;
21
+ export type ResumeCheckResult = {
22
+ resumable: true;
23
+ podName: string | null;
24
+ phase: "Pending" | "Running";
25
+ } | {
26
+ resumable: false;
27
+ reason: string;
28
+ };
29
+ export interface ResumeCheckInput {
30
+ namespace: string;
31
+ /** Workload resource name (Sandbox CR name or Job name) == providerLeaseId. */
32
+ name: string;
33
+ backend: "sandbox-cr" | "job";
34
+ /** Bounded wait for an existing Sandbox pod to report Ready. */
35
+ readyTimeoutMs?: number;
36
+ pollMs?: number;
37
+ }
38
+ /**
39
+ * Check whether the workload behind a lease is still alive and exec-able.
40
+ * Returns `resumable: false` (never throws "expected" states) when the
41
+ * resource is gone (404), terminally failed, terminating, or doesn't become
42
+ * Ready within the bounded wait — all of which mean the caller should fall
43
+ * back to a fresh acquireLease.
44
+ */
45
+ export declare function checkLeaseResumable(clients: KubeClients, input: ResumeCheckInput): Promise<ResumeCheckResult>;
46
+ export interface DestroyLeaseInput {
47
+ namespace: string;
48
+ /** Workload resource name (Sandbox CR name or Job name) == providerLeaseId. */
49
+ name: string;
50
+ backend: "sandbox-cr" | "job";
51
+ podName: string | null;
52
+ secretName: string | null;
53
+ }
54
+ /**
55
+ * Forcibly delete every resource acquireLease created for this lease.
56
+ * Workload first (its deletion cascades to the pod and, via ownerReferences,
57
+ * the per-run Secret in the normal case); then the pod and Secret explicitly
58
+ * so a wedged controller or broken ownerRef cannot strand them. Every delete
59
+ * treats 404 as success — destroy is idempotent.
60
+ */
61
+ export declare function destroyLeaseResources(clients: KubeClients, input: DestroyLeaseInput): Promise<void>;
62
+ //# sourceMappingURL=lease-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-lifecycle.d.ts","sourceRoot":"","sources":["../src/lease-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQpD,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAIzD;AAUD,MAAM,MAAM,iBAAiB,GACzB;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,GACzE;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,GAAG,KAAK,CAAC;IAC9B,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAoF5B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,GAAG,KAAK,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,IAAI,CAAC,CAsBf"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Resume + destroy lifecycle helpers for Kubernetes sandbox leases.
3
+ *
4
+ * Resume semantics: a lease is resumable only while its workload resource
5
+ * (Sandbox CR or Job) still exists and its pod is Running/Ready (or becomes
6
+ * Ready within a short bounded wait). Unlike Daytona — where a stopped sandbox
7
+ * can be started again by ID — Kubernetes pods are NOT restartable: once the
8
+ * pod backing a lease is gone or terminally failed, the lease can never be
9
+ * revived in place. That asymmetry is intentional; the plugin reports the
10
+ * lease as expired and the server falls back to a fresh acquireLease, which
11
+ * provisions a new pod.
12
+ *
13
+ * Destroy semantics: the forced cleanup path. Deletes every resource
14
+ * acquireLease created (Sandbox CR / Job, its pod, the per-run Secret),
15
+ * treating 404s as success so it is idempotent and safe to call against
16
+ * half-deleted leases.
17
+ */
18
+ import { deleteJob, findPodForJob, getJobStatus } from "./job-orchestrator.js";
19
+ import { deleteSandboxCr, findPodForSandbox, waitForSandboxReady, } from "./sandbox-cr-orchestrator.js";
20
+ /** True when a Kubernetes API error means "resource not found" (HTTP 404). */
21
+ export function isKubeNotFoundError(err) {
22
+ const code = err.code
23
+ ?? err.statusCode;
24
+ return code === 404;
25
+ }
26
+ async function ignoreNotFound(promise) {
27
+ try {
28
+ await promise;
29
+ }
30
+ catch (err) {
31
+ if (!isKubeNotFoundError(err))
32
+ throw err;
33
+ }
34
+ }
35
+ /**
36
+ * Check whether the workload behind a lease is still alive and exec-able.
37
+ * Returns `resumable: false` (never throws "expected" states) when the
38
+ * resource is gone (404), terminally failed, terminating, or doesn't become
39
+ * Ready within the bounded wait — all of which mean the caller should fall
40
+ * back to a fresh acquireLease.
41
+ */
42
+ export async function checkLeaseResumable(clients, input) {
43
+ if (input.backend === "sandbox-cr") {
44
+ // Bounded wait for the Sandbox to report Ready. waitForSandboxReady fails
45
+ // fast on Failed/Terminating; a timeout means the pod never came up. None
46
+ // of those states are resumable — k8s pods cannot be restarted in place.
47
+ try {
48
+ await waitForSandboxReady(clients, input.namespace, input.name, {
49
+ timeoutMs: input.readyTimeoutMs ?? 30_000,
50
+ pollMs: input.pollMs ?? 1_000,
51
+ });
52
+ }
53
+ catch (err) {
54
+ if (isKubeNotFoundError(err)) {
55
+ return { resumable: false, reason: "Sandbox CR no longer exists" };
56
+ }
57
+ return {
58
+ resumable: false,
59
+ reason: err instanceof Error ? err.message : String(err),
60
+ };
61
+ }
62
+ let podName;
63
+ try {
64
+ podName = await findPodForSandbox(clients, input.namespace, input.name);
65
+ }
66
+ catch (err) {
67
+ // CR deleted between the readiness check and the pod lookup.
68
+ if (isKubeNotFoundError(err)) {
69
+ return { resumable: false, reason: "Sandbox CR no longer exists" };
70
+ }
71
+ throw err;
72
+ }
73
+ if (!podName) {
74
+ return {
75
+ resumable: false,
76
+ reason: "Sandbox is Ready but no backing pod was found",
77
+ };
78
+ }
79
+ // Confirm the pod itself is Running and not being torn down — the CR
80
+ // status can lag pod deletion.
81
+ let pod;
82
+ try {
83
+ pod = await clients.core.readNamespacedPod({
84
+ namespace: input.namespace,
85
+ name: podName,
86
+ });
87
+ }
88
+ catch (err) {
89
+ if (isKubeNotFoundError(err)) {
90
+ return { resumable: false, reason: `Pod ${podName} no longer exists` };
91
+ }
92
+ throw err;
93
+ }
94
+ const podPhase = pod.status?.phase;
95
+ const terminating = Boolean(pod.metadata?.deletionTimestamp);
96
+ if (podPhase !== "Running" || terminating) {
97
+ return {
98
+ resumable: false,
99
+ reason: `Pod ${podName} is ${terminating ? "terminating" : podPhase ?? "in an unknown phase"}`,
100
+ };
101
+ }
102
+ return { resumable: true, podName, phase: "Running" };
103
+ }
104
+ // ── Job backend ───────────────────────────────────────────────────────────
105
+ let status;
106
+ try {
107
+ status = await getJobStatus(clients, input.namespace, input.name);
108
+ }
109
+ catch (err) {
110
+ if (isKubeNotFoundError(err)) {
111
+ return { resumable: false, reason: "Job no longer exists" };
112
+ }
113
+ throw err;
114
+ }
115
+ if (status.phase === "Succeeded" || status.phase === "Failed") {
116
+ // Terminal Jobs cannot be re-run in place.
117
+ return { resumable: false, reason: `Job is ${status.phase}` };
118
+ }
119
+ // Pending/Running Jobs are resumable: execute() waits for completion
120
+ // itself, so a not-yet-scheduled pod (podName null) is fine here.
121
+ const podName = await findPodForJob(clients, input.namespace, input.name);
122
+ return {
123
+ resumable: true,
124
+ podName,
125
+ phase: status.phase === "Running" ? "Running" : "Pending",
126
+ };
127
+ }
128
+ /**
129
+ * Forcibly delete every resource acquireLease created for this lease.
130
+ * Workload first (its deletion cascades to the pod and, via ownerReferences,
131
+ * the per-run Secret in the normal case); then the pod and Secret explicitly
132
+ * so a wedged controller or broken ownerRef cannot strand them. Every delete
133
+ * treats 404 as success — destroy is idempotent.
134
+ */
135
+ export async function destroyLeaseResources(clients, input) {
136
+ if (input.backend === "sandbox-cr") {
137
+ await ignoreNotFound(deleteSandboxCr(clients, input.namespace, input.name));
138
+ }
139
+ else {
140
+ await ignoreNotFound(deleteJob(clients, input.namespace, input.name));
141
+ }
142
+ if (input.podName) {
143
+ await ignoreNotFound(clients.core.deleteNamespacedPod({
144
+ namespace: input.namespace,
145
+ name: input.podName,
146
+ }));
147
+ }
148
+ if (input.secretName) {
149
+ await ignoreNotFound(clients.core.deleteNamespacedSecret({
150
+ namespace: input.namespace,
151
+ name: input.secretName,
152
+ }));
153
+ }
154
+ }
155
+ //# sourceMappingURL=lease-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-lifecycle.js","sourceRoot":"","sources":["../src/lease-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { PaperclipPluginManifestV1 } from "@paperclipai/plugin-sdk";
2
+ declare const manifest: PaperclipPluginManifestV1;
3
+ export default manifest;
4
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAKzE,QAAA,MAAM,QAAQ,EAAE,yBAiHf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,108 @@
1
+ const PLUGIN_ID = "paperclip.kubernetes-sandbox-provider";
2
+ const PLUGIN_VERSION = "0.1.0-alpha.1";
3
+ const manifest = {
4
+ id: PLUGIN_ID,
5
+ apiVersion: 1,
6
+ version: PLUGIN_VERSION,
7
+ displayName: "Kubernetes Sandbox (alpha)",
8
+ description: "Built on kubernetes-sigs/agent-sandbox (v1alpha1). ALPHA — expect breaking changes as the upstream CRD evolves. Falls back to stable batch/v1 Job mode for clusters without agent-sandbox installed. First-party Paperclip sandbox-provider plugin for Kubernetes.",
9
+ author: "Paperclip",
10
+ categories: ["automation"],
11
+ capabilities: ["environment.drivers.register"],
12
+ entrypoints: {
13
+ worker: "./dist/worker.js",
14
+ },
15
+ environmentDrivers: [
16
+ {
17
+ driverKey: "kubernetes",
18
+ kind: "sandbox_provider",
19
+ displayName: "Kubernetes",
20
+ description: "Dispatches agent runs in per-tenant Kubernetes namespaces. Default backend (sandbox-cr, alpha) uses kubernetes-sigs/agent-sandbox for multi-command exec; fallback backend (job) uses stable batch/v1 Job for clusters without agent-sandbox installed.",
21
+ configSchema: {
22
+ type: "object",
23
+ properties: {
24
+ inCluster: {
25
+ type: "boolean",
26
+ description: "When true, the plugin uses the in-pod ServiceAccount credentials. Requires paperclip-server to be running inside the target cluster.",
27
+ },
28
+ kubeconfig: {
29
+ type: "string",
30
+ format: "secret-ref",
31
+ description: "Inline kubeconfig YAML. Paste a kubeconfig or an existing Paperclip secret reference; pasted values are stored as company secrets.",
32
+ },
33
+ namespacePrefix: {
34
+ type: "string",
35
+ description: "Prefix for the per-company tenant namespace (default: paperclip-).",
36
+ },
37
+ companySlug: {
38
+ type: "string",
39
+ description: "Override the auto-derived company slug used in the tenant namespace name.",
40
+ },
41
+ imageRegistry: {
42
+ type: "string",
43
+ description: "Override the default registry for agent runtime images (default: ghcr.io/paperclipai).",
44
+ },
45
+ imageAllowList: {
46
+ type: "array",
47
+ items: { type: "string" },
48
+ description: "Glob patterns of allowed `target.imageOverride` values. Empty list = no override permitted.",
49
+ },
50
+ imagePullSecrets: {
51
+ type: "array",
52
+ items: { type: "string" },
53
+ description: "Names of pre-created Docker image pull secrets in the tenant namespace.",
54
+ },
55
+ egressAllowFqdns: {
56
+ type: "array",
57
+ items: { type: "string" },
58
+ description: "Additional FQDNs to allow egress to from agent pods. Adapter-default FQDNs (e.g. api.anthropic.com) are added automatically.",
59
+ },
60
+ egressAllowCidrs: {
61
+ type: "array",
62
+ items: { type: "string" },
63
+ description: "Additional CIDRs to allow egress to from agent pods.",
64
+ },
65
+ egressMode: {
66
+ type: "string",
67
+ enum: ["standard", "cilium"],
68
+ description: "Network policy mode. `cilium` enables FQDN-based egress filtering via CiliumNetworkPolicy.",
69
+ },
70
+ runtimeClassName: {
71
+ type: "string",
72
+ description: "Optional RuntimeClass for pod isolation (e.g. `kata-fc` for Firecracker-backed microVMs). Cluster must have the RuntimeClass installed.",
73
+ },
74
+ serviceAccountAnnotations: {
75
+ type: "object",
76
+ additionalProperties: { type: "string" },
77
+ description: "Annotations applied to the per-tenant ServiceAccount (e.g. `eks.amazonaws.com/role-arn` for IRSA).",
78
+ },
79
+ jobTtlSecondsAfterFinished: {
80
+ type: "integer",
81
+ minimum: 0,
82
+ description: "Seconds after a Job completes before it is garbage-collected (default: 900).",
83
+ },
84
+ podActivityDeadlineSec: {
85
+ type: "integer",
86
+ minimum: 1,
87
+ description: "Hard ceiling on a single run's wall-clock time (default: 3600).",
88
+ },
89
+ adapterType: {
90
+ type: "string",
91
+ description: "The adapter type that Jobs in this environment will run (e.g. `claude_local`, `codex_local`). Defaults to `claude_local`. Each environment is bound to one adapter; create multiple environments for different adapters.",
92
+ },
93
+ backend: {
94
+ type: "string",
95
+ enum: ["sandbox-cr", "job"],
96
+ description: "sandbox-cr (default, alpha — requires kubernetes-sigs/agent-sandbox installed) | job (stable fallback — batch/v1 Job, one-shot entrypoint, no multi-command exec)",
97
+ },
98
+ },
99
+ anyOf: [
100
+ { required: ["inCluster"] },
101
+ { required: ["kubeconfig"] },
102
+ ],
103
+ },
104
+ },
105
+ ],
106
+ };
107
+ export default manifest;
108
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,uCAAuC,CAAC;AAC1D,MAAM,cAAc,GAAG,eAAe,CAAC;AAEvC,MAAM,QAAQ,GAA8B;IAC1C,EAAE,EAAE,SAAS;IACb,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,cAAc;IACvB,WAAW,EAAE,4BAA4B;IACzC,WAAW,EACT,oQAAoQ;IACtQ,MAAM,EAAE,WAAW;IACnB,UAAU,EAAE,CAAC,YAAY,CAAC;IAC1B,YAAY,EAAE,CAAC,8BAA8B,CAAC;IAC9C,WAAW,EAAE;QACX,MAAM,EAAE,kBAAkB;KAC3B;IACD,kBAAkB,EAAE;QAClB;YACE,SAAS,EAAE,YAAY;YACvB,IAAI,EAAE,kBAAkB;YACxB,WAAW,EAAE,YAAY;YACzB,WAAW,EACT,yPAAyP;YAC3P,YAAY,EAAE;gBACZ,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,SAAS,EAAE;wBACT,IAAI,EAAE,SAAS;wBACf,WAAW,EACT,sIAAsI;qBACzI;oBACD,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,MAAM,EAAE,YAAY;wBACpB,WAAW,EACT,oIAAoI;qBACvI;oBACD,eAAe,EAAE;wBACf,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,oEAAoE;qBAClF;oBACD,WAAW,EAAE;wBACX,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,2EAA2E;qBACzF;oBACD,aAAa,EAAE;wBACb,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,wFAAwF;qBACtG;oBACD,cAAc,EAAE;wBACd,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,WAAW,EACT,6FAA6F;qBAChG;oBACD,gBAAgB,EAAE;wBAChB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,WAAW,EAAE,yEAAyE;qBACvF;oBACD,gBAAgB,EAAE;wBAChB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,WAAW,EACT,8HAA8H;qBACjI;oBACD,gBAAgB,EAAE;wBAChB,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,WAAW,EAAE,sDAAsD;qBACpE;oBACD,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC;wBAC5B,WAAW,EAAE,4FAA4F;qBAC1G;oBACD,gBAAgB,EAAE;wBAChB,IAAI,EAAE,QAAQ;wBACd,WAAW,EACT,yIAAyI;qBAC5I;oBACD,yBAAyB,EAAE;wBACzB,IAAI,EAAE,QAAQ;wBACd,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACxC,WAAW,EACT,oGAAoG;qBACvG;oBACD,0BAA0B,EAAE;wBAC1B,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,CAAC;wBACV,WAAW,EAAE,8EAA8E;qBAC5F;oBACD,sBAAsB,EAAE;wBACtB,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,CAAC;wBACV,WAAW,EAAE,iEAAiE;qBAC/E;oBACD,WAAW,EAAE;wBACX,IAAI,EAAE,QAAQ;wBACd,WAAW,EACT,0NAA0N;qBAC7N;oBACD,OAAO,EAAE;wBACP,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;wBAC3B,WAAW,EACT,mKAAmK;qBACtK;iBACF;gBACD,KAAK,EAAE;oBACL,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE;oBAC3B,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE;iBAC7B;aACF;SACF;KACF;CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface BuildNetworkPolicyInput {
2
+ namespace: string;
3
+ paperclipServerNamespace: string;
4
+ egressAllowCidrs: string[];
5
+ /**
6
+ * Adapter-configured FQDNs (e.g. `api.anthropic.com`). Standard
7
+ * NetworkPolicy cannot express FQDNs natively — only Cilium can.
8
+ * When this list is non-empty AND no explicit `egressAllowCidrs`
9
+ * was provided, the standard NetworkPolicy falls back to "public
10
+ * IPv4 except RFC1918/link-local/loopback/multicast" so the
11
+ * configured FQDNs at least become reachable. This is broader
12
+ * than the operator probably wants — switch to `egressMode:
13
+ * "cilium"` for exact FQDN allow-listing in production.
14
+ */
15
+ egressAllowFqdns?: string[];
16
+ }
17
+ export declare function buildNetworkPolicyManifests(input: BuildNetworkPolicyInput): Record<string, unknown>[];
18
+ //# sourceMappingURL=network-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-policy.d.ts","sourceRoot":"","sources":["../src/network-policy.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB,EAAE,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AA2BD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAyFrG"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * IPv4 ranges to carve out of `0.0.0.0/0` when we apply the
3
+ * public-internet fallback. Keeps agent pods from reaching cluster
4
+ * internals (RFC1918), node link-local + AWS IMDS (169.254.0.0/16),
5
+ * cluster loopback (127.0.0.0/8), CGNAT (100.64.0.0/10), this-network
6
+ * (0.0.0.0/8), and multicast (224.0.0.0/4).
7
+ */
8
+ const PRIVATE_AND_LINK_LOCAL_EXCEPT_CIDRS = [
9
+ "0.0.0.0/8",
10
+ "10.0.0.0/8",
11
+ "100.64.0.0/10",
12
+ "127.0.0.0/8",
13
+ "169.254.0.0/16",
14
+ "172.16.0.0/12",
15
+ "192.168.0.0/16",
16
+ "224.0.0.0/4",
17
+ ];
18
+ // Design note: the deny-all baseline blocks all ingress to agent pods.
19
+ // Paperclip-server does NOT push to agent pods — the agent shim makes
20
+ // outbound calls to paperclip-server via the egress allow-list (port 3100).
21
+ // This pull/callback model means no ingress rule is needed. If a future
22
+ // feature requires server→agent push (e.g. forced shutdown, live exec),
23
+ // add a targeted ingress rule here scoped to the paperclip-server pod
24
+ // selector.
25
+ export function buildNetworkPolicyManifests(input) {
26
+ const denyAll = {
27
+ apiVersion: "networking.k8s.io/v1",
28
+ kind: "NetworkPolicy",
29
+ metadata: {
30
+ name: "paperclip-deny-all",
31
+ namespace: input.namespace,
32
+ labels: { "paperclip.io/managed-by": "paperclip-k8s-plugin" },
33
+ },
34
+ spec: {
35
+ podSelector: {},
36
+ policyTypes: ["Ingress", "Egress"],
37
+ },
38
+ };
39
+ const egressAllow = {
40
+ apiVersion: "networking.k8s.io/v1",
41
+ kind: "NetworkPolicy",
42
+ metadata: {
43
+ name: "paperclip-egress-allow",
44
+ namespace: input.namespace,
45
+ labels: { "paperclip.io/managed-by": "paperclip-k8s-plugin" },
46
+ },
47
+ spec: {
48
+ podSelector: { matchLabels: { "paperclip.io/role": "agent" } },
49
+ policyTypes: ["Egress"],
50
+ egress: [
51
+ {
52
+ to: [
53
+ {
54
+ namespaceSelector: { matchLabels: { "kubernetes.io/metadata.name": "kube-system" } },
55
+ podSelector: { matchLabels: { "k8s-app": "kube-dns" } },
56
+ },
57
+ ],
58
+ ports: [
59
+ { protocol: "UDP", port: 53 },
60
+ { protocol: "TCP", port: 53 },
61
+ ],
62
+ },
63
+ {
64
+ to: [
65
+ {
66
+ namespaceSelector: { matchLabels: { "kubernetes.io/metadata.name": input.paperclipServerNamespace } },
67
+ podSelector: { matchLabels: { app: "paperclip-server" } },
68
+ },
69
+ ],
70
+ ports: [{ protocol: "TCP", port: 3100 }],
71
+ },
72
+ // NOTE: operator-supplied CIDRs are intentionally NOT port-scoped —
73
+ // operators may need them for non-HTTP services (e.g. private VCS
74
+ // mirrors, S3 endpoints, internal artifact registries). Operators
75
+ // should keep CIDRs as specific as possible. For HTTP/HTTPS-only
76
+ // LLM endpoints, the public-IPv4 fallback below is port-scoped
77
+ // (TCP 80/443).
78
+ ...input.egressAllowCidrs.map((cidr) => ({
79
+ to: [{ ipBlock: { cidr } }],
80
+ })),
81
+ // Standard-NetworkPolicy fallback for FQDN-based egress. If the
82
+ // adapter requires FQDNs (e.g. api.anthropic.com) and the
83
+ // operator didn't supply explicit CIDRs, allow public IPv4 with
84
+ // private/link-local/loopback/multicast carved out. This makes
85
+ // the default `egressMode: "standard"` config functional out of
86
+ // the box for cloud LLM APIs without inadvertently exposing
87
+ // cluster internals or link-local metadata endpoints. Operators
88
+ // who want exact FQDN enforcement should use `egressMode: "cilium"`.
89
+ ...(input.egressAllowCidrs.length === 0 &&
90
+ (input.egressAllowFqdns?.length ?? 0) > 0
91
+ ? [
92
+ {
93
+ to: [
94
+ {
95
+ ipBlock: {
96
+ cidr: "0.0.0.0/0",
97
+ except: PRIVATE_AND_LINK_LOCAL_EXCEPT_CIDRS,
98
+ },
99
+ },
100
+ ],
101
+ ports: [
102
+ { protocol: "TCP", port: 443 },
103
+ { protocol: "TCP", port: 80 },
104
+ ],
105
+ },
106
+ ]
107
+ : []),
108
+ ],
109
+ },
110
+ };
111
+ return [denyAll, egressAllow];
112
+ }
113
+ //# sourceMappingURL=network-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-policy.js","sourceRoot":"","sources":["../src/network-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const plugin: import("@paperclipai/plugin-sdk").PaperclipPlugin;
2
+ export default plugin;
3
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AA+GA,QAAA,MAAM,MAAM,mDA8uBV,CAAC;AAEH,eAAe,MAAM,CAAC"}