@intentius/chant-lexicon-k8s 0.37.2 → 0.38.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.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,0BAA0B,CAAC;AAsBjG,eAAO,MAAM,SAAS,EAAE,aA2mBvB,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,0BAA0B,CAAC;AAuBjG,eAAO,MAAM,SAAS,EAAE,aA4mBvB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAsC,MAAM,6BAA6B,CAAC;AA2IlG;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,UA2I3B,CAAC"}
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAsC,MAAM,6BAA6B,CAAC;AA2IlG;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,UA+I3B,CAAC"}
@@ -128,6 +128,20 @@ export declare class AppProject {
128
128
  readonly uid: string;
129
129
  }
130
130
 
131
+ export declare class Backup {
132
+ constructor(props: {
133
+ /** Specification of the desired behavior of the backup.
134
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
135
+ spec: Record<string, unknown>;
136
+ /** Standard object's metadata. */
137
+ metadata?: ObjectMeta;
138
+ });
139
+ readonly name: string;
140
+ readonly namespace: string;
141
+ readonly status: Record<string, unknown>;
142
+ readonly uid: string;
143
+ }
144
+
131
145
  export declare class BatchJob {
132
146
  constructor(props: {
133
147
  /** Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
@@ -228,6 +242,20 @@ export declare class Challenge {
228
242
  readonly uid: string;
229
243
  }
230
244
 
245
+ export declare class Cluster {
246
+ constructor(props: {
247
+ /** Specification of the desired behavior of the cluster.
248
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
249
+ spec: Record<string, unknown>;
250
+ /** Standard object's metadata. */
251
+ metadata?: ObjectMeta;
252
+ });
253
+ readonly name: string;
254
+ readonly namespace: string;
255
+ readonly status: Record<string, unknown>;
256
+ readonly uid: string;
257
+ }
258
+
231
259
  export declare class ClusterIssuer {
232
260
  constructor(props: {
233
261
  /** Desired state of the ClusterIssuer resource. */
@@ -1101,6 +1129,45 @@ export declare class ImageUpdateAutomation {
1101
1129
  readonly uid: string;
1102
1130
  }
1103
1131
 
1132
+ export declare class InfisicalDynamicSecret {
1133
+ constructor(props: {
1134
+ /** Standard object's metadata. */
1135
+ metadata?: ObjectMeta;
1136
+ /** InfisicalDynamicSecretSpec defines the desired state of InfisicalDynamicSecret. */
1137
+ spec?: Record<string, unknown>;
1138
+ });
1139
+ readonly name: string;
1140
+ readonly namespace: string;
1141
+ readonly status: Record<string, unknown>;
1142
+ readonly uid: string;
1143
+ }
1144
+
1145
+ export declare class InfisicalPushSecret {
1146
+ constructor(props: {
1147
+ /** Standard object's metadata. */
1148
+ metadata?: ObjectMeta;
1149
+ /** InfisicalPushSecretSpec defines the desired state of InfisicalPushSecret */
1150
+ spec?: Record<string, unknown>;
1151
+ });
1152
+ readonly name: string;
1153
+ readonly namespace: string;
1154
+ readonly status: Record<string, unknown>;
1155
+ readonly uid: string;
1156
+ }
1157
+
1158
+ export declare class InfisicalSecret {
1159
+ constructor(props: {
1160
+ /** Standard object's metadata. */
1161
+ metadata?: ObjectMeta;
1162
+ /** InfisicalSecretSpec defines the desired state of InfisicalSecret */
1163
+ spec?: Record<string, unknown>;
1164
+ });
1165
+ readonly name: string;
1166
+ readonly namespace: string;
1167
+ readonly status: Record<string, unknown>;
1168
+ readonly uid: string;
1169
+ }
1170
+
1104
1171
  export declare class Ing {
1105
1172
  constructor(props: {
1106
1173
  /** Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
@@ -1161,6 +1228,42 @@ export declare class IngressList {
1161
1228
  readonly uid: string;
1162
1229
  }
1163
1230
 
1231
+ export declare class IngressRoute {
1232
+ constructor(props: {
1233
+ /** IngressRouteSpec defines the desired state of IngressRoute. */
1234
+ spec: Record<string, unknown>;
1235
+ /** Standard object's metadata. */
1236
+ metadata?: ObjectMeta;
1237
+ });
1238
+ readonly name: string;
1239
+ readonly namespace: string;
1240
+ readonly uid: string;
1241
+ }
1242
+
1243
+ export declare class IngressRouteTCP {
1244
+ constructor(props: {
1245
+ /** IngressRouteTCPSpec defines the desired state of IngressRouteTCP. */
1246
+ spec: Record<string, unknown>;
1247
+ /** Standard object's metadata. */
1248
+ metadata?: ObjectMeta;
1249
+ });
1250
+ readonly name: string;
1251
+ readonly namespace: string;
1252
+ readonly uid: string;
1253
+ }
1254
+
1255
+ export declare class IngressRouteUDP {
1256
+ constructor(props: {
1257
+ /** IngressRouteUDPSpec defines the desired state of a IngressRouteUDP. */
1258
+ spec: Record<string, unknown>;
1259
+ /** Standard object's metadata. */
1260
+ metadata?: ObjectMeta;
1261
+ });
1262
+ readonly name: string;
1263
+ readonly namespace: string;
1264
+ readonly uid: string;
1265
+ }
1266
+
1164
1267
  export declare class IPAddress {
1165
1268
  constructor(props: {
1166
1269
  /** spec is the desired state of the IPAddress. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
@@ -1379,6 +1482,30 @@ export declare class MicroVMReplicaSet {
1379
1482
  readonly uid: string;
1380
1483
  }
1381
1484
 
1485
+ export declare class Middleware {
1486
+ constructor(props: {
1487
+ /** MiddlewareSpec defines the desired state of a Middleware. */
1488
+ spec: Record<string, unknown>;
1489
+ /** Standard object's metadata. */
1490
+ metadata?: ObjectMeta;
1491
+ });
1492
+ readonly name: string;
1493
+ readonly namespace: string;
1494
+ readonly uid: string;
1495
+ }
1496
+
1497
+ export declare class MiddlewareTCP {
1498
+ constructor(props: {
1499
+ /** MiddlewareTCPSpec defines the desired state of a MiddlewareTCP. */
1500
+ spec: Record<string, unknown>;
1501
+ /** Standard object's metadata. */
1502
+ metadata?: ObjectMeta;
1503
+ });
1504
+ readonly name: string;
1505
+ readonly namespace: string;
1506
+ readonly uid: string;
1507
+ }
1508
+
1382
1509
  export declare class MutatingAdmissionPolicy {
1383
1510
  constructor(props: {
1384
1511
  /** metadata is the standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. */
@@ -1547,6 +1674,20 @@ export declare class NS {
1547
1674
  readonly uid: string;
1548
1675
  }
1549
1676
 
1677
+ export declare class ObjectStore {
1678
+ constructor(props: {
1679
+ /** Specification of the desired behavior of the ObjectStore.
1680
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
1681
+ spec: Record<string, unknown>;
1682
+ /** Standard object's metadata. */
1683
+ metadata?: ObjectMeta;
1684
+ });
1685
+ readonly name: string;
1686
+ readonly namespace: string;
1687
+ readonly status: Record<string, unknown>;
1688
+ readonly uid: string;
1689
+ }
1690
+
1550
1691
  export declare class OCIRepository {
1551
1692
  constructor(props: {
1552
1693
  /** Standard object's metadata. */
@@ -1728,6 +1869,20 @@ export declare class PodTemplateList {
1728
1869
  readonly uid: string;
1729
1870
  }
1730
1871
 
1872
+ export declare class Pooler {
1873
+ constructor(props: {
1874
+ /** Specification of the desired behavior of the Pooler.
1875
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
1876
+ spec: Record<string, unknown>;
1877
+ /** Standard object's metadata. */
1878
+ metadata?: ObjectMeta;
1879
+ });
1880
+ readonly name: string;
1881
+ readonly namespace: string;
1882
+ readonly status: Record<string, unknown>;
1883
+ readonly uid: string;
1884
+ }
1885
+
1731
1886
  export declare class PriorityClass {
1732
1887
  constructor(props: {
1733
1888
  /** description is an arbitrary string that usually provides guidelines on when this priority class should be used. */
@@ -2172,6 +2327,20 @@ export declare class Scale {
2172
2327
  readonly uid: string;
2173
2328
  }
2174
2329
 
2330
+ export declare class ScheduledBackup {
2331
+ constructor(props: {
2332
+ /** Specification of the desired behavior of the ScheduledBackup.
2333
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
2334
+ spec: Record<string, unknown>;
2335
+ /** Standard object's metadata. */
2336
+ metadata?: ObjectMeta;
2337
+ });
2338
+ readonly name: string;
2339
+ readonly namespace: string;
2340
+ readonly status: Record<string, unknown>;
2341
+ readonly uid: string;
2342
+ }
2343
+
2175
2344
  export declare class Sec {
2176
2345
  constructor(props: {
2177
2346
  /** Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 */
@@ -2254,6 +2423,30 @@ export declare class SelfSubjectRulesReview {
2254
2423
  readonly uid: string;
2255
2424
  }
2256
2425
 
2426
+ export declare class ServersTransport {
2427
+ constructor(props: {
2428
+ /** ServersTransportSpec defines the desired state of a ServersTransport. */
2429
+ spec: Record<string, unknown>;
2430
+ /** Standard object's metadata. */
2431
+ metadata?: ObjectMeta;
2432
+ });
2433
+ readonly name: string;
2434
+ readonly namespace: string;
2435
+ readonly uid: string;
2436
+ }
2437
+
2438
+ export declare class ServersTransportTCP {
2439
+ constructor(props: {
2440
+ /** ServersTransportTCPSpec defines the desired state of a ServersTransportTCP. */
2441
+ spec: Record<string, unknown>;
2442
+ /** Standard object's metadata. */
2443
+ metadata?: ObjectMeta;
2444
+ });
2445
+ readonly name: string;
2446
+ readonly namespace: string;
2447
+ readonly uid: string;
2448
+ }
2449
+
2257
2450
  export declare class Service {
2258
2451
  constructor(props: {
2259
2452
  /** Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
@@ -2469,6 +2662,30 @@ export declare class SubjectAccessReview {
2469
2662
  readonly uid: string;
2470
2663
  }
2471
2664
 
2665
+ export declare class TLSOption {
2666
+ constructor(props: {
2667
+ /** TLSOptionSpec defines the desired state of a TLSOption. */
2668
+ spec: Record<string, unknown>;
2669
+ /** Standard object's metadata. */
2670
+ metadata?: ObjectMeta;
2671
+ });
2672
+ readonly name: string;
2673
+ readonly namespace: string;
2674
+ readonly uid: string;
2675
+ }
2676
+
2677
+ export declare class TLSStore {
2678
+ constructor(props: {
2679
+ /** TLSStoreSpec defines the desired state of a TLSStore. */
2680
+ spec: Record<string, unknown>;
2681
+ /** Standard object's metadata. */
2682
+ metadata?: ObjectMeta;
2683
+ });
2684
+ readonly name: string;
2685
+ readonly namespace: string;
2686
+ readonly uid: string;
2687
+ }
2688
+
2472
2689
  export declare class TokenRequest {
2473
2690
  constructor(props: {
2474
2691
  /** metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
@@ -2493,6 +2710,18 @@ export declare class TokenReview {
2493
2710
  readonly uid: string;
2494
2711
  }
2495
2712
 
2713
+ export declare class TraefikService {
2714
+ constructor(props: {
2715
+ /** TraefikServiceSpec defines the desired state of a TraefikService. */
2716
+ spec: Record<string, unknown>;
2717
+ /** Standard object's metadata. */
2718
+ metadata?: ObjectMeta;
2719
+ });
2720
+ readonly name: string;
2721
+ readonly namespace: string;
2722
+ readonly uid: string;
2723
+ }
2724
+
2496
2725
  export declare class ValidatingAdmissionPolicy {
2497
2726
  constructor(props: {
2498
2727
  /** metadata is the standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-k8s",
3
- "version": "0.37.2",
3
+ "version": "0.38.0",
4
4
  "description": "Kubernetes lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -78,7 +78,7 @@
78
78
  "typescript": "^5.9.3"
79
79
  },
80
80
  "peerDependencies": {
81
- "@intentius/chant": "^0.37.2",
81
+ "@intentius/chant": "^0.38.0",
82
82
  "typescript": "^5.9.3"
83
83
  }
84
84
  }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * CNPG acceptance test.
3
+ *
4
+ * The bar set by #1319 is that fountain's real `k8s/` overlay — postgres.yaml,
5
+ * scheduledbackup.yaml, objectstore.yaml — is reproducible from typed chant
6
+ * source. So these assertions are transcribed from that overlay rather than
7
+ * from a fixture invented to pass, and every value here is one a running
8
+ * cluster has.
9
+ */
10
+
11
+ import { describe, test, expect } from "vitest";
12
+ import { Cluster, ScheduledBackup, ObjectStore } from "../generated";
13
+ import { k8sSerializer } from "../serializer";
14
+ import { parseYAML } from "@intentius/chant/yaml";
15
+
16
+ /** Serialize one declaration the way `chant build` would, and read it back. */
17
+ function synth(logicalName: string, resource: unknown): any {
18
+ const yaml = k8sSerializer.serialize(new Map([[logicalName, resource as never]]));
19
+ return parseYAML(yaml);
20
+ }
21
+
22
+ describe("CNPG Cluster", () => {
23
+ const cluster = new Cluster({
24
+ metadata: { name: "fountain-pg", namespace: "fountain", labels: { app: "fountain" } },
25
+ spec: {
26
+ instances: 1,
27
+ imageName: "ghcr.io/cloudnative-pg/postgresql:18.4-standard-trixie",
28
+ plugins: [
29
+ {
30
+ name: "barman-cloud.cloudnative-pg.io",
31
+ isWALArchiver: true,
32
+ parameters: { barmanObjectName: "fountain-backups" },
33
+ },
34
+ ],
35
+ bootstrap: {
36
+ initdb: {
37
+ database: "fountain",
38
+ owner: "fountain",
39
+ postInitTemplateSQL: ["CREATE EXTENSION IF NOT EXISTS vector;"],
40
+ },
41
+ },
42
+ storage: { storageClass: "longhorn", size: "10Gi" },
43
+ resources: {
44
+ requests: { cpu: "100m", memory: "512Mi" },
45
+ limits: { memory: "1Gi" },
46
+ },
47
+ },
48
+ });
49
+
50
+ test("carries the CNPG apiVersion and kind", () => {
51
+ const doc = synth("fountainPg", cluster);
52
+ expect(doc.apiVersion).toBe("postgresql.cnpg.io/v1");
53
+ expect(doc.kind).toBe("Cluster");
54
+ expect(doc.metadata.name).toBe("fountain-pg");
55
+ expect(doc.metadata.namespace).toBe("fountain");
56
+ });
57
+
58
+ test("reproduces fountain's postgres.yaml spec", () => {
59
+ const { spec } = synth("fountainPg", cluster);
60
+ expect(spec.instances).toBe(1);
61
+ expect(spec.imageName).toBe("ghcr.io/cloudnative-pg/postgresql:18.4-standard-trixie");
62
+ expect(spec.storage).toEqual({ storageClass: "longhorn", size: "10Gi" });
63
+ expect(spec.bootstrap.initdb.database).toBe("fountain");
64
+ expect(spec.bootstrap.initdb.owner).toBe("fountain");
65
+ expect(spec.bootstrap.initdb.postInitTemplateSQL).toEqual([
66
+ "CREATE EXTENSION IF NOT EXISTS vector;",
67
+ ]);
68
+ // A memory limit with no CPU limit is deliberate upstream: a CPU limit
69
+ // throttles a database. It has to survive serialization as written.
70
+ expect(spec.resources).toEqual({
71
+ requests: { cpu: "100m", memory: "512Mi" },
72
+ limits: { memory: "1Gi" },
73
+ });
74
+ });
75
+
76
+ test("wires WAL archiving to the ObjectStore by name", () => {
77
+ const { spec } = synth("fountainPg", cluster);
78
+ // This block is the whole link between the two CRDs. `isWALArchiver` must
79
+ // stay a boolean -- quoted, the plugin ignores it and archiving is silently
80
+ // off, which looks exactly like a healthy cluster until a restore.
81
+ expect(spec.plugins).toEqual([
82
+ {
83
+ name: "barman-cloud.cloudnative-pg.io",
84
+ isWALArchiver: true,
85
+ parameters: { barmanObjectName: "fountain-backups" },
86
+ },
87
+ ]);
88
+ expect(typeof spec.plugins[0].isWALArchiver).toBe("boolean");
89
+ });
90
+ });
91
+
92
+ describe("CNPG ScheduledBackup", () => {
93
+ const backup = new ScheduledBackup({
94
+ metadata: { name: "fountain-pg-base", namespace: "fountain", labels: { app: "fountain" } },
95
+ spec: {
96
+ schedule: "0 47 2 * * *",
97
+ backupOwnerReference: "self",
98
+ cluster: { name: "fountain-pg" },
99
+ method: "plugin",
100
+ pluginConfiguration: { name: "barman-cloud.cloudnative-pg.io" },
101
+ },
102
+ });
103
+
104
+ test("reproduces fountain's scheduledbackup.yaml", () => {
105
+ const doc = synth("fountainPgBase", backup);
106
+ expect(doc.apiVersion).toBe("postgresql.cnpg.io/v1");
107
+ expect(doc.kind).toBe("ScheduledBackup");
108
+ expect(doc.spec.backupOwnerReference).toBe("self");
109
+ expect(doc.spec.cluster).toEqual({ name: "fountain-pg" });
110
+ expect(doc.spec.method).toBe("plugin");
111
+ expect(doc.spec.pluginConfiguration).toEqual({ name: "barman-cloud.cloudnative-pg.io" });
112
+ });
113
+
114
+ test("round-trips a six-field schedule", () => {
115
+ const { spec } = synth("fountainPgBase", backup);
116
+ // CNPG schedules lead with seconds, so this is six fields where a
117
+ // Kubernetes CronJob takes five. The schema types it as a plain string, so
118
+ // nothing here or upstream rejects the five-field form -- it just means a
119
+ // different time. The count is the only thing that catches it.
120
+ expect(spec.schedule).toBe("0 47 2 * * *");
121
+ expect(spec.schedule.trim().split(/\s+/)).toHaveLength(6);
122
+ });
123
+ });
124
+
125
+ describe("barman-cloud ObjectStore", () => {
126
+ const store = new ObjectStore({
127
+ metadata: { name: "fountain-backups", namespace: "fountain", labels: { app: "fountain" } },
128
+ spec: {
129
+ retentionPolicy: "14d",
130
+ configuration: {
131
+ destinationPath: "s3://fountain-backups/barman",
132
+ endpointURL: "http://s3.garage.svc.cluster.local:3900",
133
+ s3Credentials: {
134
+ accessKeyId: { name: "fountain-backup-s3-credentials", key: "AWS_ACCESS_KEY_ID" },
135
+ secretAccessKey: { name: "fountain-backup-s3-credentials", key: "AWS_SECRET_ACCESS_KEY" },
136
+ },
137
+ wal: { compression: "gzip" },
138
+ data: { compression: "gzip" },
139
+ },
140
+ },
141
+ });
142
+
143
+ test("reproduces fountain's objectstore.yaml", () => {
144
+ const doc = synth("fountainBackups", store);
145
+ // Its own group, mapped onto the same `Cnpg` namespace as the Cluster.
146
+ expect(doc.apiVersion).toBe("barmancloud.cnpg.io/v1");
147
+ expect(doc.kind).toBe("ObjectStore");
148
+ expect(doc.spec.retentionPolicy).toBe("14d");
149
+ expect(doc.spec.configuration.destinationPath).toBe("s3://fountain-backups/barman");
150
+ expect(doc.spec.configuration.endpointURL).toBe("http://s3.garage.svc.cluster.local:3900");
151
+ expect(doc.spec.configuration.wal).toEqual({ compression: "gzip" });
152
+ expect(doc.spec.configuration.data).toEqual({ compression: "gzip" });
153
+ });
154
+
155
+ test("keeps credentials as secret references, never values", () => {
156
+ const { spec } = synth("fountainBackups", store);
157
+ expect(spec.configuration.s3Credentials).toEqual({
158
+ accessKeyId: { name: "fountain-backup-s3-credentials", key: "AWS_ACCESS_KEY_ID" },
159
+ secretAccessKey: { name: "fountain-backup-s3-credentials", key: "AWS_SECRET_ACCESS_KEY" },
160
+ });
161
+ });
162
+
163
+ test("the Cluster's barmanObjectName matches this store's name", () => {
164
+ // The two CRDs are joined by a string. Nothing upstream checks it: a typo
165
+ // leaves the cluster running with archiving pointed at a store that does
166
+ // not exist.
167
+ const clusterDoc = synth(
168
+ "fountainPg",
169
+ new Cluster({
170
+ metadata: { name: "fountain-pg", namespace: "fountain" },
171
+ spec: {
172
+ instances: 1,
173
+ plugins: [
174
+ {
175
+ name: "barman-cloud.cloudnative-pg.io",
176
+ isWALArchiver: true,
177
+ parameters: { barmanObjectName: "fountain-backups" },
178
+ },
179
+ ],
180
+ },
181
+ }),
182
+ );
183
+ const storeDoc = synth("fountainBackups", store);
184
+ expect(clusterDoc.spec.plugins[0].parameters.barmanObjectName).toBe(storeDoc.metadata.name);
185
+ });
186
+ });
@@ -93,6 +93,111 @@ const COCKROACH_OPERATOR_CRD_BASE = `https://raw.githubusercontent.com/cockroach
93
93
  const CERT_MANAGER_VERSION = "v1.16.2";
94
94
  const CERT_MANAGER_CRD_BUNDLE = `https://github.com/cert-manager/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.crds.yaml`;
95
95
 
96
+ /**
97
+ * CloudNativePG CRDs — postgresql.cnpg.io/v1
98
+ *
99
+ * The Postgres operator. Produces, under the `Cnpg` namespace (both groups are
100
+ * mapped there explicitly in parser.ts; the first-segment rule would otherwise
101
+ * split them into `Postgresql` and `Barmancloud`):
102
+ * K8s::Cnpg::Cluster → postgresql.cnpg.io/v1
103
+ * K8s::Cnpg::ScheduledBackup → postgresql.cnpg.io/v1
104
+ * K8s::Cnpg::Backup → postgresql.cnpg.io/v1
105
+ * K8s::Cnpg::Pooler → postgresql.cnpg.io/v1
106
+ *
107
+ * Pinned to 1.29.1 rather than latest (1.30.0) because that is the operator a
108
+ * real consumer runs — BinaryBourbon/fountain's k8s overlay.
109
+ *
110
+ * Note on ScheduledBackup.schedule: it is a **six**-field cron with leading
111
+ * seconds, not the five-field form Kubernetes CronJob takes. The schema types
112
+ * it as a plain string, so a five-field value passes every check here and
113
+ * silently means something else on the cluster.
114
+ *
115
+ * Database, Publication and Subscription are deliberately left out — no known
116
+ * consumer needs them, and pulling a whole provider is what the note at the top
117
+ * of this file warns against.
118
+ *
119
+ * Operator install: kubectl apply --server-side -f
120
+ * https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.29/releases/cnpg-1.29.1.yaml
121
+ */
122
+ const CNPG_VERSION = "v1.29.1";
123
+ const CNPG_CRD_BASE = `https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/${CNPG_VERSION}/config/crd/bases`;
124
+
125
+ /**
126
+ * barman-cloud plugin CRD — barmancloud.cnpg.io/v1
127
+ *
128
+ * CNPG's WAL archiving / object-storage backend, shipped as a separate plugin
129
+ * with its own release train. Produces:
130
+ * K8s::Cnpg::ObjectStore → barmancloud.cnpg.io/v1
131
+ *
132
+ * A CNPG Cluster reaches it through `spec.plugins[]` — `name:
133
+ * barman-cloud.cloudnative-pg.io`, `isWALArchiver: true`,
134
+ * `parameters.barmanObjectName` naming the ObjectStore — so the two are only
135
+ * ever useful together.
136
+ *
137
+ * Pinned to 0.14.0 (latest). Its ObjectStore schema is a superset of 0.7.0's:
138
+ * same four spec properties, more detail inside them.
139
+ *
140
+ * Plugin install: kubectl apply -f
141
+ * https://github.com/cloudnative-pg/plugin-barman-cloud/releases/download/v0.14.0/manifest.yaml
142
+ */
143
+ const BARMAN_PLUGIN_VERSION = "v0.14.0";
144
+ const BARMAN_PLUGIN_CRD_BASE = `https://raw.githubusercontent.com/cloudnative-pg/plugin-barman-cloud/${BARMAN_PLUGIN_VERSION}/config/crd/bases`;
145
+ /**
146
+ * Traefik proxy CRDs — traefik.io/v1alpha1
147
+ *
148
+ * Traefik's own routing surface. An `IngressRoute` is not a
149
+ * `networking.k8s.io` Ingress with annotations — it is a distinct CRD with its
150
+ * own matcher grammar, so an estate fronted by Traefik has no expressible edge
151
+ * without these. Produces, under the `Traefik` namespace (first-segment rule,
152
+ * no override needed):
153
+ * K8s::Traefik::IngressRoute K8s::Traefik::Middleware
154
+ * K8s::Traefik::IngressRouteTCP K8s::Traefik::MiddlewareTCP
155
+ * K8s::Traefik::IngressRouteUDP K8s::Traefik::ServersTransport
156
+ * K8s::Traefik::TLSOption K8s::Traefik::ServersTransportTCP
157
+ * K8s::Traefik::TLSStore K8s::Traefik::TraefikService
158
+ *
159
+ * Only the `traefik.io` group. The chart's crds/ directory also ships
160
+ * `hub.traefik.io_*` (Traefik Hub, a different commercial product, ~12 kinds,
161
+ * no known consumer) and a vendored copy of the Gateway API, which is already
162
+ * generated here from its upstream repo and would collide.
163
+ *
164
+ * Version footgun: the pin below is the **chart** version, and the chart
165
+ * version is not the Traefik version. Chart v41.1.0 ships Traefik v3.7.9.
166
+ * When bumping, record both.
167
+ *
168
+ * Controller install: helm repo add traefik https://traefik.github.io/charts
169
+ * && helm install traefik traefik/traefik --version 41.1.0
170
+ */
171
+ const TRAEFIK_CHART_VERSION = "v41.1.0";
172
+ const TRAEFIK_CRD_BASE = `https://raw.githubusercontent.com/traefik/traefik-helm-chart/${TRAEFIK_CHART_VERSION}/traefik/crds`;
173
+ /**
174
+ * Infisical operator CRDs — secrets.infisical.com/v1alpha1
175
+ *
176
+ * The declarative form of chant's own secrets boundary. An `InfisicalSecret`
177
+ * says where a secret comes from and who may fetch it; it never carries a
178
+ * value. Without it an estate can declare the Deployment that consumes a
179
+ * Secret but not the thing that makes the Secret exist. Produces, under the
180
+ * `Infisical` namespace:
181
+ * K8s::Infisical::InfisicalSecret
182
+ * K8s::Infisical::InfisicalPushSecret
183
+ * K8s::Infisical::InfisicalDynamicSecret
184
+ *
185
+ * The group is overridden to `Infisical` in parser.ts. The first-segment rule
186
+ * would give `K8s::Secrets::InfisicalSecret`, which reads like a core Secret
187
+ * next to the `K8s::Core::Secret` that already exists.
188
+ *
189
+ * Two things about the URL, both easy to lose an hour to:
190
+ * - The operator lives in its own repo, `Infisical/kubernetes-operator`.
191
+ * The path under the `Infisical/infisical` monorepo 404s.
192
+ * - The tag is path-shaped — `infisical-k8-operator/v0.11.7`. Not a typo,
193
+ * and not a directory.
194
+ *
195
+ * Operator install: helm repo add infisical https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/
196
+ * && helm install infisical-secrets-operator infisical/secrets-operator
197
+ */
198
+ const INFISICAL_OPERATOR_VERSION = "infisical-k8-operator/v0.11.7";
199
+ const INFISICAL_CRD_BASE = `https://raw.githubusercontent.com/Infisical/kubernetes-operator/${INFISICAL_OPERATOR_VERSION}/config/crd/bases`;
200
+
96
201
  /**
97
202
  * Prometheus Operator CRDs — monitoring.coreos.com/v1
98
203
  *
@@ -188,6 +293,24 @@ export const CRD_SOURCES: CRDSource[] = [
188
293
  { type: "url", url: CERT_MANAGER_CRD_BUNDLE },
189
294
  { type: "url", url: `${PROM_OPERATOR_CRD_BASE}/monitoring.coreos.com_servicemonitors.yaml` },
190
295
  { type: "url", url: `${PROM_OPERATOR_CRD_BASE}/monitoring.coreos.com_prometheusrules.yaml` },
296
+ { type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_clusters.yaml` },
297
+ { type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_scheduledbackups.yaml` },
298
+ { type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_backups.yaml` },
299
+ { type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_poolers.yaml` },
300
+ { type: "url", url: `${BARMAN_PLUGIN_CRD_BASE}/barmancloud.cnpg.io_objectstores.yaml` },
301
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_ingressroutes.yaml` },
302
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_ingressroutetcps.yaml` },
303
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_ingressrouteudps.yaml` },
304
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_middlewares.yaml` },
305
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_middlewaretcps.yaml` },
306
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_serverstransports.yaml` },
307
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_serverstransporttcps.yaml` },
308
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_tlsoptions.yaml` },
309
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_tlsstores.yaml` },
310
+ { type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_traefikservices.yaml` },
311
+ { type: "url", url: `${INFISICAL_CRD_BASE}/secrets.infisical.com_infisicalsecrets.yaml` },
312
+ { type: "url", url: `${INFISICAL_CRD_BASE}/secrets.infisical.com_infisicalpushsecrets.yaml` },
313
+ { type: "url", url: `${INFISICAL_CRD_BASE}/secrets.infisical.com_infisicaldynamicsecrets.yaml` },
191
314
  {
192
315
  type: "url",
193
316
  url: FLUX_TOOLKIT_INSTALL,