@tickernelz/paperclip-pro-plugin-kubernetes 2026.925.0

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 (100) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +180 -0
  3. package/dist/adapter-defaults.d.ts +29 -0
  4. package/dist/adapter-defaults.d.ts.map +1 -0
  5. package/dist/adapter-defaults.js +98 -0
  6. package/dist/adapter-defaults.js.map +1 -0
  7. package/dist/adapter-registry.d.ts +64 -0
  8. package/dist/adapter-registry.d.ts.map +1 -0
  9. package/dist/adapter-registry.js +25 -0
  10. package/dist/adapter-registry.js.map +1 -0
  11. package/dist/cilium-network-policy.d.ts +12 -0
  12. package/dist/cilium-network-policy.d.ts.map +1 -0
  13. package/dist/cilium-network-policy.js +60 -0
  14. package/dist/cilium-network-policy.js.map +1 -0
  15. package/dist/file-sync.d.ts +73 -0
  16. package/dist/file-sync.d.ts.map +1 -0
  17. package/dist/file-sync.js +752 -0
  18. package/dist/file-sync.js.map +1 -0
  19. package/dist/image-allowlist.d.ts +18 -0
  20. package/dist/image-allowlist.d.ts.map +1 -0
  21. package/dist/image-allowlist.js +39 -0
  22. package/dist/image-allowlist.js.map +1 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +3 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/job-orchestrator.d.ts +24 -0
  28. package/dist/job-orchestrator.d.ts.map +1 -0
  29. package/dist/job-orchestrator.js +90 -0
  30. package/dist/job-orchestrator.js.map +1 -0
  31. package/dist/kube-client.d.ts +15 -0
  32. package/dist/kube-client.d.ts.map +1 -0
  33. package/dist/kube-client.js +23 -0
  34. package/dist/kube-client.js.map +1 -0
  35. package/dist/lease-lifecycle.d.ts +62 -0
  36. package/dist/lease-lifecycle.d.ts.map +1 -0
  37. package/dist/lease-lifecycle.js +155 -0
  38. package/dist/lease-lifecycle.js.map +1 -0
  39. package/dist/manifest.d.ts +4 -0
  40. package/dist/manifest.d.ts.map +1 -0
  41. package/dist/manifest.js +108 -0
  42. package/dist/manifest.js.map +1 -0
  43. package/dist/network-policy.d.ts +22 -0
  44. package/dist/network-policy.d.ts.map +1 -0
  45. package/dist/network-policy.js +116 -0
  46. package/dist/network-policy.js.map +1 -0
  47. package/dist/plugin.d.ts +3 -0
  48. package/dist/plugin.d.ts.map +1 -0
  49. package/dist/plugin.js +820 -0
  50. package/dist/plugin.js.map +1 -0
  51. package/dist/pod-exec.d.ts +67 -0
  52. package/dist/pod-exec.d.ts.map +1 -0
  53. package/dist/pod-exec.js +401 -0
  54. package/dist/pod-exec.js.map +1 -0
  55. package/dist/pod-spec-builder.d.ts +25 -0
  56. package/dist/pod-spec-builder.d.ts.map +1 -0
  57. package/dist/pod-spec-builder.js +82 -0
  58. package/dist/pod-spec-builder.js.map +1 -0
  59. package/dist/sandbox-cr-builder.d.ts +40 -0
  60. package/dist/sandbox-cr-builder.d.ts.map +1 -0
  61. package/dist/sandbox-cr-builder.js +123 -0
  62. package/dist/sandbox-cr-builder.js.map +1 -0
  63. package/dist/sandbox-cr-orchestrator.d.ts +62 -0
  64. package/dist/sandbox-cr-orchestrator.d.ts.map +1 -0
  65. package/dist/sandbox-cr-orchestrator.js +248 -0
  66. package/dist/sandbox-cr-orchestrator.js.map +1 -0
  67. package/dist/sandbox-orchestrator.d.ts +39 -0
  68. package/dist/sandbox-orchestrator.d.ts.map +1 -0
  69. package/dist/sandbox-orchestrator.js +2 -0
  70. package/dist/sandbox-orchestrator.js.map +1 -0
  71. package/dist/scoped-network-egress.d.ts +19 -0
  72. package/dist/scoped-network-egress.d.ts.map +1 -0
  73. package/dist/scoped-network-egress.js +86 -0
  74. package/dist/scoped-network-egress.js.map +1 -0
  75. package/dist/secret-manager.d.ts +14 -0
  76. package/dist/secret-manager.d.ts.map +1 -0
  77. package/dist/secret-manager.js +39 -0
  78. package/dist/secret-manager.js.map +1 -0
  79. package/dist/tenant-orchestrator.d.ts +35 -0
  80. package/dist/tenant-orchestrator.d.ts.map +1 -0
  81. package/dist/tenant-orchestrator.js +263 -0
  82. package/dist/tenant-orchestrator.js.map +1 -0
  83. package/dist/types.d.ts +279 -0
  84. package/dist/types.d.ts.map +1 -0
  85. package/dist/types.js +65 -0
  86. package/dist/types.js.map +1 -0
  87. package/dist/upload-interceptor.d.ts +44 -0
  88. package/dist/upload-interceptor.d.ts.map +1 -0
  89. package/dist/upload-interceptor.js +114 -0
  90. package/dist/upload-interceptor.js.map +1 -0
  91. package/dist/utils.d.ts +11 -0
  92. package/dist/utils.d.ts.map +1 -0
  93. package/dist/utils.js +51 -0
  94. package/dist/utils.js.map +1 -0
  95. package/dist/worker.d.ts +3 -0
  96. package/dist/worker.d.ts.map +1 -0
  97. package/dist/worker.js +5 -0
  98. package/dist/worker.js.map +1 -0
  99. package/manifests/operator-prerequisites.yaml +22 -0
  100. package/package.json +47 -0
@@ -0,0 +1,19 @@
1
+ import type { KubeClients } from "./kube-client.js";
2
+ export declare const NETWORK_EGRESS_GRANT_PATH = "executionWorkspaceSettings.networkEgress";
3
+ export interface ScopedNetworkEgressGrant {
4
+ allowFqdns: string[];
5
+ allowCidrs: string[];
6
+ }
7
+ export declare function parseScopedNetworkEgressGrant(settings: unknown): ScopedNetworkEgressGrant;
8
+ export declare function createScopedNetworkEgressPolicy(input: {
9
+ clients: KubeClients;
10
+ namespace: string;
11
+ mode: "standard" | "cilium";
12
+ runId: string;
13
+ workloadName: string;
14
+ ownerReference: Record<string, unknown>;
15
+ grant: ScopedNetworkEgressGrant;
16
+ }): Promise<string | null>;
17
+ export declare function createScopedNetworkEgressPolicyOrReleaseWorkload(input: Parameters<typeof createScopedNetworkEgressPolicy>[0], releaseWorkload: () => Promise<void>): Promise<string | null>;
18
+ export declare function appendNetworkEgressDenyHint(stderr: string, grant: ScopedNetworkEgressGrant): string;
19
+ //# sourceMappingURL=scoped-network-egress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-network-egress.d.ts","sourceRoot":"","sources":["../src/scoped-network-egress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,eAAO,MAAM,yBAAyB,6CAA6C,CAAC;AAEpF,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,OAAO,GAAG,wBAAwB,CAgBzF;AAED,wBAAsB,+BAA+B,CAAC,KAAK,EAAE;IAC3D,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,KAAK,EAAE,wBAAwB,CAAC;CACjC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwCzB;AAED,wBAAsB,gDAAgD,CACpE,KAAK,EAAE,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAAC,CAAC,CAAC,EAC5D,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACnC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,wBAAwB,GAAG,MAAM,CAOnG"}
@@ -0,0 +1,86 @@
1
+ import { buildNetworkPolicyManifests } from "./network-policy.js";
2
+ import { buildCiliumNetworkPolicyManifest } from "./cilium-network-policy.js";
3
+ export const NETWORK_EGRESS_GRANT_PATH = "executionWorkspaceSettings.networkEgress";
4
+ export function parseScopedNetworkEgressGrant(settings) {
5
+ if (!settings || typeof settings !== "object" || Array.isArray(settings)) {
6
+ return { allowFqdns: [], allowCidrs: [] };
7
+ }
8
+ const networkEgress = settings.networkEgress;
9
+ if (!networkEgress || typeof networkEgress !== "object" || Array.isArray(networkEgress)) {
10
+ return { allowFqdns: [], allowCidrs: [] };
11
+ }
12
+ const record = networkEgress;
13
+ const strings = (value) => Array.isArray(value)
14
+ ? [...new Set(value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean))]
15
+ : [];
16
+ return {
17
+ allowFqdns: strings(record.allowFqdns).map((fqdn) => fqdn.toLowerCase()),
18
+ allowCidrs: strings(record.allowCidrs),
19
+ };
20
+ }
21
+ export async function createScopedNetworkEgressPolicy(input) {
22
+ if (input.grant.allowFqdns.length === 0 && input.grant.allowCidrs.length === 0)
23
+ return null;
24
+ const suffix = "-egress";
25
+ const maxWorkloadLength = 253 - suffix.length;
26
+ const workloadName = input.workloadName.length <= maxWorkloadLength
27
+ ? input.workloadName
28
+ : `${input.workloadName.slice(0, maxWorkloadLength - 26)}-${input.workloadName.slice(-25)}`;
29
+ const name = `${workloadName}${suffix}`;
30
+ if (input.mode === "cilium") {
31
+ const manifest = buildCiliumNetworkPolicyManifest({
32
+ namespace: input.namespace,
33
+ paperclipServerNamespace: "",
34
+ egressAllowFqdns: input.grant.allowFqdns,
35
+ egressAllowCidrs: input.grant.allowCidrs,
36
+ name,
37
+ endpointSelector: { "paperclip.io/run-id": input.runId },
38
+ includeBaseRules: false,
39
+ ownerReferences: [input.ownerReference],
40
+ });
41
+ await input.clients.custom.createNamespacedCustomObject({
42
+ group: "cilium.io",
43
+ version: "v2",
44
+ namespace: input.namespace,
45
+ plural: "ciliumnetworkpolicies",
46
+ body: manifest,
47
+ });
48
+ }
49
+ else {
50
+ const [, manifest] = buildNetworkPolicyManifests({
51
+ namespace: input.namespace,
52
+ paperclipServerNamespace: "",
53
+ egressAllowFqdns: input.grant.allowFqdns,
54
+ egressAllowCidrs: input.grant.allowCidrs,
55
+ name,
56
+ podSelector: { "paperclip.io/run-id": input.runId },
57
+ includeBaseRules: false,
58
+ ownerReferences: [input.ownerReference],
59
+ });
60
+ await input.clients.networking.createNamespacedNetworkPolicy({ namespace: input.namespace, body: manifest });
61
+ }
62
+ return name;
63
+ }
64
+ export async function createScopedNetworkEgressPolicyOrReleaseWorkload(input, releaseWorkload) {
65
+ try {
66
+ return await createScopedNetworkEgressPolicy(input);
67
+ }
68
+ catch (policyError) {
69
+ try {
70
+ await releaseWorkload();
71
+ }
72
+ catch (releaseError) {
73
+ throw new AggregateError([policyError, releaseError], "Failed to create scoped network egress policy and release its workload");
74
+ }
75
+ throw policyError;
76
+ }
77
+ }
78
+ export function appendNetworkEgressDenyHint(stderr, grant) {
79
+ if (!/(could not resolve host|network is unreachable|connection timed out|failed to connect|temporary failure in name resolution)/i.test(stderr)) {
80
+ return stderr;
81
+ }
82
+ const allowed = [...grant.allowFqdns, ...grant.allowCidrs];
83
+ const detail = allowed.length > 0 ? ` Current task grant: ${allowed.join(", ")}.` : " No task-scoped destinations are granted.";
84
+ return `${stderr.trimEnd()}\nPaperclip network policy denied or could not route this request.${detail} Request access through ${NETWORK_EGRESS_GRANT_PATH}.\n`;
85
+ }
86
+ //# sourceMappingURL=scoped-network-egress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-network-egress.js","sourceRoot":"","sources":["../src/scoped-network-egress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { KubeClients } from "./kube-client.js";
2
+ export interface CreatePerRunSecretInput {
3
+ namespace: string;
4
+ secretName: string;
5
+ runId: string;
6
+ ownerKind: string;
7
+ ownerApiVersion: string;
8
+ ownerName: string;
9
+ ownerUid: string;
10
+ bootstrapToken: string;
11
+ adapterEnv: Record<string, string>;
12
+ }
13
+ export declare function createPerRunSecret(clients: KubeClients, input: CreatePerRunSecretInput): Promise<void>;
14
+ //# sourceMappingURL=secret-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-manager.d.ts","sourceRoot":"","sources":["../src/secret-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC5G"}
@@ -0,0 +1,39 @@
1
+ export async function createPerRunSecret(clients, input) {
2
+ if (!input.ownerUid) {
3
+ throw new Error("createPerRunSecret requires a non-empty ownerUid");
4
+ }
5
+ if ("BOOTSTRAP_TOKEN" in input.adapterEnv) {
6
+ throw new Error("adapterEnv must not contain BOOTSTRAP_TOKEN (reserved key)");
7
+ }
8
+ await clients.core.createNamespacedSecret({
9
+ namespace: input.namespace,
10
+ body: {
11
+ apiVersion: "v1",
12
+ kind: "Secret",
13
+ type: "Opaque",
14
+ metadata: {
15
+ name: input.secretName,
16
+ namespace: input.namespace,
17
+ labels: {
18
+ "paperclip.io/run-id": input.runId,
19
+ "paperclip.io/managed-by": "paperclip-k8s-plugin",
20
+ },
21
+ ownerReferences: [
22
+ {
23
+ apiVersion: input.ownerApiVersion,
24
+ kind: input.ownerKind,
25
+ name: input.ownerName,
26
+ uid: input.ownerUid,
27
+ controller: true,
28
+ blockOwnerDeletion: true,
29
+ },
30
+ ],
31
+ },
32
+ stringData: {
33
+ BOOTSTRAP_TOKEN: input.bootstrapToken,
34
+ ...input.adapterEnv,
35
+ },
36
+ },
37
+ });
38
+ }
39
+ //# sourceMappingURL=secret-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-manager.js","sourceRoot":"","sources":["../src/secret-manager.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAoB,EAAE,KAA8B;IAC3F,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,iBAAiB,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC;QACxC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,IAAI,EAAE;YACJ,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE;gBACR,IAAI,EAAE,KAAK,CAAC,UAAU;gBACtB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,MAAM,EAAE;oBACN,qBAAqB,EAAE,KAAK,CAAC,KAAK;oBAClC,yBAAyB,EAAE,sBAAsB;iBAClD;gBACD,eAAe,EAAE;oBACf;wBACE,UAAU,EAAE,KAAK,CAAC,eAAe;wBACjC,IAAI,EAAE,KAAK,CAAC,SAAS;wBACrB,IAAI,EAAE,KAAK,CAAC,SAAS;wBACrB,GAAG,EAAE,KAAK,CAAC,QAAQ;wBACnB,UAAU,EAAE,IAAI;wBAChB,kBAAkB,EAAE,IAAI;qBACzB;iBACF;aACF;YACD,UAAU,EAAE;gBACV,eAAe,EAAE,KAAK,CAAC,cAAc;gBACrC,GAAG,KAAK,CAAC,UAAU;aACpB;SACF;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { KubeClients } from "./kube-client.js";
2
+ export interface EnsureTenantInput {
3
+ namespace: string;
4
+ companyId: string;
5
+ paperclipServerNamespace: string;
6
+ serviceAccountAnnotations: Record<string, string>;
7
+ egressMode: "standard" | "cilium";
8
+ egressAllowFqdns: string[];
9
+ egressAllowCidrs: string[];
10
+ resourceQuota: {
11
+ pods: string;
12
+ requestsCpu: string;
13
+ requestsMemory: string;
14
+ limitsCpu: string;
15
+ limitsMemory: string;
16
+ };
17
+ }
18
+ /**
19
+ * Lazy, first-write-wins tenant provisioning. Each helper checks if the named
20
+ * resource exists and creates it only on 404; if it already exists, it is
21
+ * left as-is — config-driven values (quota limits, RBAC permissions, network
22
+ * policies, egress allow-list) are FROZEN at first provisioning time.
23
+ *
24
+ * V1 limitation: changing KubernetesProviderConfig after a tenant namespace
25
+ * is provisioned does NOT update the in-cluster resources. To apply config
26
+ * changes, an operator must delete the per-tenant resources manually (or
27
+ * the namespace itself). A future iteration should add strategic-merge
28
+ * reconciliation here.
29
+ *
30
+ * Particular gotcha: switching egressMode "standard" → "cilium" leaves the
31
+ * old paperclip-egress-allow NetworkPolicy in place alongside the new
32
+ * CiliumNetworkPolicy. Both apply; the effective egress is the intersection.
33
+ */
34
+ export declare function ensureTenant(clients: KubeClients, input: EnsureTenantInput): Promise<void>;
35
+ //# sourceMappingURL=tenant-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-orchestrator.d.ts","sourceRoot":"","sources":["../src/tenant-orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB,EAAE,MAAM,CAAC;IACjC,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAC;IAClC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAQD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhG"}
@@ -0,0 +1,263 @@
1
+ import { buildNetworkPolicyManifests } from "./network-policy.js";
2
+ import { buildCiliumNetworkPolicyManifest } from "./cilium-network-policy.js";
3
+ const SERVICE_ACCOUNT_NAME = "paperclip-tenant-sa";
4
+ const ROLE_NAME = "paperclip-tenant-role";
5
+ const ROLE_BINDING_NAME = "paperclip-tenant-rb";
6
+ const RESOURCE_QUOTA_NAME = "paperclip-quota";
7
+ const LIMIT_RANGE_NAME = "paperclip-limits";
8
+ /**
9
+ * Lazy, first-write-wins tenant provisioning. Each helper checks if the named
10
+ * resource exists and creates it only on 404; if it already exists, it is
11
+ * left as-is — config-driven values (quota limits, RBAC permissions, network
12
+ * policies, egress allow-list) are FROZEN at first provisioning time.
13
+ *
14
+ * V1 limitation: changing KubernetesProviderConfig after a tenant namespace
15
+ * is provisioned does NOT update the in-cluster resources. To apply config
16
+ * changes, an operator must delete the per-tenant resources manually (or
17
+ * the namespace itself). A future iteration should add strategic-merge
18
+ * reconciliation here.
19
+ *
20
+ * Particular gotcha: switching egressMode "standard" → "cilium" leaves the
21
+ * old paperclip-egress-allow NetworkPolicy in place alongside the new
22
+ * CiliumNetworkPolicy. Both apply; the effective egress is the intersection.
23
+ */
24
+ export async function ensureTenant(clients, input) {
25
+ await ensureNamespace(clients, input);
26
+ await ensureServiceAccount(clients, input);
27
+ await ensureRole(clients, input);
28
+ await ensureRoleBinding(clients, input);
29
+ await ensureResourceQuota(clients, input);
30
+ await ensureLimitRange(clients, input);
31
+ await ensureNetworkPolicies(clients, input);
32
+ }
33
+ async function ensureNamespace(clients, input) {
34
+ try {
35
+ await clients.core.readNamespace({ name: input.namespace });
36
+ return;
37
+ }
38
+ catch (err) {
39
+ if (!isNotFound(err))
40
+ throw err;
41
+ }
42
+ await createIgnoringAlreadyExists(clients.core.createNamespace({
43
+ body: {
44
+ apiVersion: "v1",
45
+ kind: "Namespace",
46
+ metadata: {
47
+ name: input.namespace,
48
+ labels: {
49
+ "paperclip.io/company-id": input.companyId,
50
+ "paperclip.io/managed-by": "paperclip-k8s-plugin",
51
+ "pod-security.kubernetes.io/enforce": "restricted",
52
+ "pod-security.kubernetes.io/audit": "restricted",
53
+ "pod-security.kubernetes.io/warn": "restricted",
54
+ },
55
+ },
56
+ },
57
+ }));
58
+ }
59
+ async function ensureServiceAccount(clients, input) {
60
+ try {
61
+ await clients.core.readNamespacedServiceAccount({ name: SERVICE_ACCOUNT_NAME, namespace: input.namespace });
62
+ return;
63
+ }
64
+ catch (err) {
65
+ if (!isNotFound(err))
66
+ throw err;
67
+ }
68
+ await createIgnoringAlreadyExists(clients.core.createNamespacedServiceAccount({
69
+ namespace: input.namespace,
70
+ body: {
71
+ apiVersion: "v1",
72
+ kind: "ServiceAccount",
73
+ metadata: {
74
+ name: SERVICE_ACCOUNT_NAME,
75
+ namespace: input.namespace,
76
+ annotations: input.serviceAccountAnnotations,
77
+ labels: { "paperclip.io/managed-by": "paperclip-k8s-plugin" },
78
+ },
79
+ },
80
+ }));
81
+ }
82
+ async function ensureRole(clients, input) {
83
+ try {
84
+ await clients.rbac.readNamespacedRole({ name: ROLE_NAME, namespace: input.namespace });
85
+ return;
86
+ }
87
+ catch (err) {
88
+ if (!isNotFound(err))
89
+ throw err;
90
+ }
91
+ await createIgnoringAlreadyExists(clients.rbac.createNamespacedRole({
92
+ namespace: input.namespace,
93
+ body: {
94
+ apiVersion: "rbac.authorization.k8s.io/v1",
95
+ kind: "Role",
96
+ metadata: { name: ROLE_NAME, namespace: input.namespace },
97
+ rules: [
98
+ { apiGroups: [""], resources: ["pods/log"], verbs: ["get"] },
99
+ ],
100
+ },
101
+ }));
102
+ }
103
+ async function ensureRoleBinding(clients, input) {
104
+ try {
105
+ await clients.rbac.readNamespacedRoleBinding({ name: ROLE_BINDING_NAME, namespace: input.namespace });
106
+ return;
107
+ }
108
+ catch (err) {
109
+ if (!isNotFound(err))
110
+ throw err;
111
+ }
112
+ await createIgnoringAlreadyExists(clients.rbac.createNamespacedRoleBinding({
113
+ namespace: input.namespace,
114
+ body: {
115
+ apiVersion: "rbac.authorization.k8s.io/v1",
116
+ kind: "RoleBinding",
117
+ metadata: { name: ROLE_BINDING_NAME, namespace: input.namespace },
118
+ roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "Role", name: ROLE_NAME },
119
+ subjects: [{ kind: "ServiceAccount", name: SERVICE_ACCOUNT_NAME, namespace: input.namespace }],
120
+ },
121
+ }));
122
+ }
123
+ async function ensureResourceQuota(clients, input) {
124
+ try {
125
+ await clients.core.readNamespacedResourceQuota({ name: RESOURCE_QUOTA_NAME, namespace: input.namespace });
126
+ return;
127
+ }
128
+ catch (err) {
129
+ if (!isNotFound(err))
130
+ throw err;
131
+ }
132
+ await createIgnoringAlreadyExists(clients.core.createNamespacedResourceQuota({
133
+ namespace: input.namespace,
134
+ body: {
135
+ apiVersion: "v1",
136
+ kind: "ResourceQuota",
137
+ metadata: { name: RESOURCE_QUOTA_NAME, namespace: input.namespace },
138
+ spec: {
139
+ hard: {
140
+ pods: input.resourceQuota.pods,
141
+ "requests.cpu": input.resourceQuota.requestsCpu,
142
+ "requests.memory": input.resourceQuota.requestsMemory,
143
+ "limits.cpu": input.resourceQuota.limitsCpu,
144
+ "limits.memory": input.resourceQuota.limitsMemory,
145
+ },
146
+ },
147
+ },
148
+ }));
149
+ }
150
+ async function ensureLimitRange(clients, input) {
151
+ try {
152
+ await clients.core.readNamespacedLimitRange({ name: LIMIT_RANGE_NAME, namespace: input.namespace });
153
+ return;
154
+ }
155
+ catch (err) {
156
+ if (!isNotFound(err))
157
+ throw err;
158
+ }
159
+ await createIgnoringAlreadyExists(clients.core.createNamespacedLimitRange({
160
+ namespace: input.namespace,
161
+ body: {
162
+ apiVersion: "v1",
163
+ kind: "LimitRange",
164
+ metadata: { name: LIMIT_RANGE_NAME, namespace: input.namespace },
165
+ spec: {
166
+ limits: [
167
+ {
168
+ type: "Container",
169
+ max: { cpu: "4", memory: "8Gi" },
170
+ min: { cpu: "100m", memory: "128Mi" },
171
+ // The k8s client-node type names this `_default` but the actual
172
+ // Kubernetes API field is `default`. We produce a JSON-shape
173
+ // manifest so the cast is safe.
174
+ default: { cpu: "1", memory: "2Gi" },
175
+ defaultRequest: { cpu: "250m", memory: "512Mi" },
176
+ },
177
+ ],
178
+ },
179
+ },
180
+ }));
181
+ }
182
+ async function ensureNetworkPolicies(clients, input) {
183
+ const [denyAll, egressStd] = buildNetworkPolicyManifests({
184
+ namespace: input.namespace,
185
+ paperclipServerNamespace: input.paperclipServerNamespace,
186
+ egressAllowCidrs: input.egressAllowCidrs,
187
+ egressAllowFqdns: input.egressAllowFqdns,
188
+ });
189
+ await ensureNetworkPolicy(clients, input.namespace, denyAll);
190
+ if (input.egressMode === "cilium") {
191
+ const cnp = buildCiliumNetworkPolicyManifest({
192
+ namespace: input.namespace,
193
+ paperclipServerNamespace: input.paperclipServerNamespace,
194
+ egressAllowFqdns: input.egressAllowFqdns,
195
+ egressAllowCidrs: input.egressAllowCidrs,
196
+ });
197
+ await ensureCiliumNetworkPolicy(clients, input.namespace, cnp);
198
+ }
199
+ else {
200
+ await ensureNetworkPolicy(clients, input.namespace, egressStd);
201
+ }
202
+ }
203
+ async function ensureNetworkPolicy(clients, namespace, manifest) {
204
+ const name = manifest.metadata.name;
205
+ try {
206
+ await clients.networking.readNamespacedNetworkPolicy({ name, namespace });
207
+ return;
208
+ }
209
+ catch (err) {
210
+ if (!isNotFound(err))
211
+ throw err;
212
+ }
213
+ await createIgnoringAlreadyExists(clients.networking.createNamespacedNetworkPolicy({ namespace, body: manifest }));
214
+ }
215
+ async function ensureCiliumNetworkPolicy(clients, namespace, manifest) {
216
+ const name = manifest.metadata.name;
217
+ try {
218
+ await clients.custom.getNamespacedCustomObject({
219
+ group: "cilium.io",
220
+ version: "v2",
221
+ namespace,
222
+ plural: "ciliumnetworkpolicies",
223
+ name,
224
+ });
225
+ return;
226
+ }
227
+ catch (err) {
228
+ if (!isNotFound(err))
229
+ throw err;
230
+ }
231
+ await createIgnoringAlreadyExists(clients.custom.createNamespacedCustomObject({
232
+ group: "cilium.io",
233
+ version: "v2",
234
+ namespace,
235
+ plural: "ciliumnetworkpolicies",
236
+ body: manifest,
237
+ }));
238
+ }
239
+ function isNotFound(err) {
240
+ if (typeof err !== "object" || err === null)
241
+ return false;
242
+ const e = err;
243
+ return e.code === 404 || e.statusCode === 404;
244
+ }
245
+ function isAlreadyExists(err) {
246
+ if (typeof err !== "object" || err === null)
247
+ return false;
248
+ const e = err;
249
+ return e.code === 409 || e.statusCode === 409;
250
+ }
251
+ // Two concurrent lease acquisitions for a brand-new tenant can both observe
252
+ // the 404 read and race the create; a 409 AlreadyExists from the loser means
253
+ // the desired state already exists, which is exactly what ensure* wants.
254
+ async function createIgnoringAlreadyExists(create) {
255
+ try {
256
+ await create;
257
+ }
258
+ catch (err) {
259
+ if (!isAlreadyExists(err))
260
+ throw err;
261
+ }
262
+ }
263
+ //# sourceMappingURL=tenant-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-orchestrator.js","sourceRoot":"","sources":["../src/tenant-orchestrator.ts"],"names":[],"mappings":"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"}