@intentius/chant-lexicon-gcp 0.44.14 → 0.45.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":"docs.d.ts","sourceRoot":"","sources":["../../src/codegen/docs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4FH;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8uB9E"}
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/codegen/docs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4FH;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB9E"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "87ff9dc3ad075eb6a2f45e1084298909b75702186399fb1666a64b2bd87d348e",
4
+ "manifest.json": "17362bbe86bdedd7a3825faca8213f558c72714c6f6f16ce27dfd207c329b1ea",
5
5
  "meta.json": "475f10909854d059a2e2d4fb541c058803422e38b9c64bd4d6858c0623eedb8c",
6
6
  "types/index.d.ts": "5433b54c04b57d6fda8f3d81ef92ed0aca87f7e8e5dd3ea92d8de6e62a3ccfab",
7
7
  "rules/hardcoded-project.ts": "228631d3159e1ffcce2359c66073d4ae59bb0285f378e46e446f416aec50481c",
@@ -40,5 +40,5 @@
40
40
  "skills/chant-gcp-patterns.md": "a7ef31c1eb2f7244d3f73952c300472ef94c1eb09bd7a1003281b89299b6b704",
41
41
  "skills/chant-gcp-gke.md": "be277019da9a722c851e47cd2dfb9c9536668948c3535fb20db7697e934c4e2b"
42
42
  },
43
- "composite": "3f2aefb5e0c5e95d0f90855acd29cd91bf3d2fbfc96c411e83947c3fb88b9fb3"
43
+ "composite": "5d1b64bafea0ac5f419bf20633a22c2d6a49d498ad6e63aba5d89523492dcc79"
44
44
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gcp",
3
- "version": "0.44.14",
3
+ "version": "0.45.0",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "GCP",
6
6
  "intrinsics": [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-gcp",
3
- "version": "0.44.14",
3
+ "version": "0.45.0",
4
4
  "description": "Google Cloud lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -76,7 +76,7 @@
76
76
  "typescript": "^5.9.3"
77
77
  },
78
78
  "peerDependencies": {
79
- "@intentius/chant": "^0.44.14",
79
+ "@intentius/chant": "^0.45.0",
80
80
  "typescript": "^5.9.3"
81
81
  }
82
82
  }
@@ -111,732 +111,6 @@ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void>
111
111
  serviceFromType,
112
112
  srcDir: join(pkgDir, "src"),
113
113
  basePath: "/chant/lexicons/gcp/",
114
- extraPages: [
115
- {
116
- slug: "getting-started",
117
- title: "Getting Started",
118
- description: "Install chant and deploy your first GCP resource in 5 minutes",
119
- content: `## What is chant?
120
-
121
- Chant is a TypeScript-to-YAML compiler. You write typed TypeScript declarations, and chant outputs Config Connector YAML manifests that can be applied to a GKE cluster with Config Connector installed.
122
-
123
- ## Prerequisites
124
-
125
- 1. A GKE cluster with [Config Connector](https://cloud.google.com/config-connector/docs/overview) installed
126
- 2. A \`ConfigConnectorContext\` resource configured per namespace
127
- 3. A GCP Service Account bound to the Config Connector controller
128
-
129
- ## Install
130
-
131
- \`\`\`bash
132
- npm install --save-dev @intentius/chant @intentius/chant-lexicon-gcp
133
- \`\`\`
134
-
135
- ## Your first resource
136
-
137
- The fastest path is the **GcsBucket** composite — one function call that produces a properly configured Storage bucket:
138
-
139
- \`\`\`typescript
140
- // src/infra.gcp.ts
141
- import { GcsBucket } from "@intentius/chant-lexicon-gcp";
142
- import { defaultAnnotations, GCP } from "@intentius/chant-lexicon-gcp";
143
-
144
- export const annotations = defaultAnnotations({
145
- "cnrm.cloud.google.com/project-id": GCP.ProjectId,
146
- });
147
-
148
- const { bucket } = GcsBucket({
149
- name: "my-data-bucket",
150
- location: "US",
151
- versioning: true,
152
- });
153
-
154
- export { bucket };
155
- \`\`\`
156
-
157
- ## Build and deploy
158
-
159
- \`\`\`bash
160
- # Generate Config Connector YAML
161
- chant build --output dist/manifests.yaml
162
-
163
- # Validate against the cluster API (no changes applied)
164
- kubectl apply -f dist/manifests.yaml --dry-run=server
165
-
166
- # Apply
167
- kubectl apply -f dist/manifests.yaml
168
- \`\`\`
169
-
170
- ## Using resource constructors
171
-
172
- \`\`\`typescript
173
- import { StorageBucket, IAMPolicyMember, GCP } from "@intentius/chant-lexicon-gcp";
174
-
175
- export const bucket = new StorageBucket({
176
- location: "US",
177
- storageClass: "STANDARD",
178
- uniformBucketLevelAccess: true,
179
- versioning: { enabled: true },
180
- });
181
-
182
- export const reader = new IAMPolicyMember({
183
- member: "serviceAccount:app@my-project.iam.gserviceaccount.com",
184
- role: "roles/storage.objectViewer",
185
- resourceRef: {
186
- apiVersion: "storage.cnrm.cloud.google.com/v1beta1",
187
- kind: "StorageBucket",
188
- name: bucket,
189
- },
190
- });
191
- \`\`\`
192
-
193
- ## Next steps
194
-
195
- - [Config Connector Concepts](/chant/lexicons/gcp/config-connector-concepts/) — resource structure, references, project binding
196
- - [Examples](/chant/lexicons/gcp/examples/) — StorageBucket, ComputeInstance, CloudSQL, IAM
197
- - [Lint Rules](/chant/lexicons/gcp/lint-rules/) — built-in checks for security and best practices`,
198
- },
199
- {
200
- slug: "config-connector-concepts",
201
- title: "Config Connector Concepts",
202
- description: "Resource structure, resourceRef, project binding, reconciliation lifecycle",
203
- content: `import Diagram from '../../components/Diagram.astro';
204
-
205
- Every exported resource declaration becomes a Config Connector manifest document in the generated YAML.
206
-
207
- ## Resource structure
208
-
209
- Every Config Connector resource has four standard fields:
210
-
211
- | Field | Source | Example |
212
- |-------|--------|---------|
213
- | \`apiVersion\` | Resolved from resource type | \`storage.cnrm.cloud.google.com/v1beta1\` |
214
- | \`kind\` | Resolved from resource type | \`StorageBucket\` |
215
- | \`metadata\` | From \`metadata\` property | \`{ name: "my-bucket", labels: {...} }\` |
216
- | \`spec\` | From remaining props | Resource-specific configuration |
217
-
218
- ## Resource references
219
-
220
- Config Connector resources reference each other using \`resourceRef\`:
221
-
222
- \`\`\`yaml
223
- # By name (same namespace)
224
- resourceRef:
225
- name: my-network
226
-
227
- # By external reference (cross-project)
228
- resourceRef:
229
- external: projects/my-project/global/networks/my-network
230
- \`\`\`
231
-
232
- In chant, resource references resolve automatically:
233
-
234
- \`\`\`typescript
235
- export const network = new ComputeNetwork({ autoCreateSubnetworks: false });
236
-
237
- export const subnet = new ComputeSubnetwork({
238
- networkRef: { name: network }, // Resolves to metadata.name of network
239
- ipCidrRange: "10.0.0.0/24",
240
- region: "us-central1",
241
- });
242
- \`\`\`
243
-
244
- ## Project binding
245
-
246
- Bind resources to a GCP project via annotations:
247
-
248
- \`\`\`typescript
249
- import { defaultAnnotations, GCP } from "@intentius/chant-lexicon-gcp";
250
-
251
- export const annotations = defaultAnnotations({
252
- "cnrm.cloud.google.com/project-id": GCP.ProjectId,
253
- });
254
- \`\`\`
255
-
256
- This injects the project annotation into every resource. Without it, Config Connector uses the namespace's default project.
257
-
258
- ## Reconciliation lifecycle
259
-
260
- Config Connector resources go through a reconciliation lifecycle:
261
-
262
- <Diagram name="config-connector-lifecycle" alt="Config Connector state machine: YAML applied to kubectl, then Pending → Reconciling → UpToDate, UpdateFailed, or DependencyNotReady with retry paths" caption="Config Connector reconciliation lifecycle" />
263
-
264
- | Status | Meaning |
265
- |--------|---------|
266
- | UpToDate | Resource matches desired state |
267
- | Updating | Controller is applying changes |
268
- | UpdateFailed | GCP API returned an error |
269
- | DependencyNotReady | Waiting for a referenced resource |
270
- | DeletionFailed | Cannot delete the GCP resource |
271
-
272
- Check status with: \`kubectl get gcp -A\` or \`kubectl describe <resource>\`
273
-
274
- ## Default labels and annotations
275
-
276
- Use \`defaultLabels()\` and \`defaultAnnotations()\` to inject metadata into all resources:
277
-
278
- \`\`\`typescript
279
- import { defaultLabels, defaultAnnotations } from "@intentius/chant-lexicon-gcp";
280
-
281
- export const labels = defaultLabels({
282
- "app.kubernetes.io/managed-by": "chant",
283
- "env": "production",
284
- });
285
- \`\`\`
286
-
287
- Explicit labels on individual resources take precedence over defaults.`,
288
- },
289
- {
290
- slug: "lint-rules",
291
- title: "Lint Rules",
292
- description: "Built-in lint rules and post-synth checks for GCP Config Connector manifests",
293
- content: `The GCP lexicon ships lint rules that run during \`chant lint\` and post-synth checks that validate the serialized YAML after \`chant build\`.
294
-
295
- ## Lint rules
296
-
297
- Lint rules analyze your TypeScript source code before build.
298
-
299
- | Rule | Description |
300
- |------|-------------|
301
- | WGC001 | Hardcoded project ID in resource constructors |
302
- | WGC002 | Hardcoded region in resource constructors |
303
- | WGC003 | Public IAM member (allUsers/allAuthenticatedUsers) |
304
-
305
- ## Post-synth checks
306
-
307
- Post-synth checks run against the serialized YAML after build.
308
-
309
- ### Security
310
-
311
- | Rule | Description |
312
- |------|-------------|
313
- | WGC101 | Missing encryption on StorageBucket or SQLInstance |
314
- | WGC102 | Public IAM member detected in output |
315
- | WGC104 | Missing uniform bucket-level access |
316
- | WGC105 | Cloud SQL with public 0.0.0.0/0 in authorizedNetworks |
317
- | WGC109 | ComputeFirewall allowing all sources (0.0.0.0/0) |
318
- | WGC110 | KMS CryptoKey without rotation period |
319
-
320
- ### Best practices
321
-
322
- | Rule | Description |
323
- |------|-------------|
324
- | WGC103 | Missing project annotation (uses namespace default) |
325
- | WGC106 | Missing deletion policy annotation |
326
- | WGC107 | StorageBucket without versioning |
327
- | WGC108 | SQLInstance without backup configuration |
328
- | WGC201 | Missing managed-by label |
329
- | WGC202 | GKE cluster without workload identity |
330
- | WGC203 | GKE node pool with overly broad cloud-platform OAuth scope |
331
- | WGC204 | ComputeInstance without shielded VM config |
332
-
333
- ### Correctness
334
-
335
- | Rule | Description |
336
- |------|-------------|
337
- | WGC111 | Resource reference points to a name not defined in the output |
338
- | WGC112 | Config Connector resource has missing or invalid apiVersion |
339
- | WGC113 | Config Connector resource uses an alpha API version |
340
-
341
- ### Schema validation
342
-
343
- Checks each Config Connector resource's \`spec\` against the CRD schema it is
344
- generated from.
345
-
346
- | Rule | Description |
347
- |------|-------------|
348
- | WGC401 | Config Connector resource spec contains unknown field |
349
- | WGC402 | Config Connector resource is missing a required spec field |
350
- | WGC403 | Config Connector resource spec field has wrong type or structure |
351
-
352
- ### Compliance
353
-
354
- | Rule | Description |
355
- |------|-------------|
356
- | WGC301 | No IAMAuditConfig resource in output |
357
- | WGC302 | No Service (API enablement) resource in output |
358
- | WGC303 | No VPC Service Controls perimeter |
359
-
360
- ## Running lint
361
-
362
- \`\`\`bash
363
- # Lint your chant project
364
- chant lint
365
-
366
- # Build (also runs post-synth checks)
367
- chant build
368
- \`\`\`
369
-
370
- To suppress a rule on a specific line:
371
-
372
- \`\`\`typescript
373
- // chant-disable-next-line WGC001
374
- const bucket = new StorageBucket({ metadata: { annotations: { "cnrm.cloud.google.com/project-id": "my-project" } } });
375
- \`\`\``,
376
- },
377
- {
378
- slug: "examples",
379
- title: "Examples: Resources",
380
- description: "GCP Config Connector resource examples — StorageBucket, ComputeInstance, CloudSQL, IAM",
381
- content: `## StorageBucket
382
-
383
- A Storage bucket with encryption, versioning, and lifecycle rules:
384
-
385
- \`\`\`typescript
386
- import { StorageBucket, GCP } from "@intentius/chant-lexicon-gcp";
387
-
388
- export const bucket = new StorageBucket({
389
- location: "US",
390
- storageClass: "STANDARD",
391
- uniformBucketLevelAccess: true,
392
- versioning: { enabled: true },
393
- encryption: {
394
- defaultKmsKeyName: "projects/p/locations/us/keyRings/kr/cryptoKeys/key",
395
- },
396
- lifecycleRule: [
397
- { action: { type: "Delete" }, condition: { age: 365 } },
398
- { action: { type: "SetStorageClass", storageClass: "NEARLINE" }, condition: { age: 30 } },
399
- ],
400
- });
401
- \`\`\`
402
-
403
- ## ComputeInstance
404
-
405
- A Compute Engine VM with shielded VM configuration:
406
-
407
- \`\`\`typescript
408
- import { ComputeInstance, GCP } from "@intentius/chant-lexicon-gcp";
409
-
410
- export const vm = new ComputeInstance({
411
- machineType: "e2-medium",
412
- zone: "us-central1-a",
413
- bootDisk: {
414
- initializeParams: {
415
- sourceImageRef: {
416
- external: "projects/debian-cloud/global/images/debian-12",
417
- },
418
- },
419
- },
420
- networkInterface: [{
421
- networkRef: { name: "my-network" },
422
- subnetworkRef: { name: "my-subnet" },
423
- }],
424
- shieldedInstanceConfig: {
425
- enableSecureBoot: true,
426
- enableVtpm: true,
427
- enableIntegrityMonitoring: true,
428
- },
429
- });
430
- \`\`\`
431
-
432
- ## Cloud SQL
433
-
434
- A PostgreSQL instance with backups and high availability:
435
-
436
- \`\`\`typescript
437
- import { CloudSqlInstance } from "@intentius/chant-lexicon-gcp";
438
-
439
- const { instance, database, user } = CloudSqlInstance({
440
- name: "app-db",
441
- databaseVersion: "POSTGRES_15",
442
- tier: "db-custom-2-8192",
443
- region: "us-central1",
444
- backupEnabled: true,
445
- highAvailability: true,
446
- diskSize: 50,
447
- });
448
-
449
- export { instance, database, user };
450
- \`\`\`
451
-
452
- ## IAM Binding
453
-
454
- Grant a service account access to a resource:
455
-
456
- \`\`\`typescript
457
- import { IAMPolicyMember } from "@intentius/chant-lexicon-gcp";
458
-
459
- export const binding = new IAMPolicyMember({
460
- member: "serviceAccount:app@my-project.iam.gserviceaccount.com",
461
- role: "roles/storage.objectViewer",
462
- resourceRef: {
463
- apiVersion: "storage.cnrm.cloud.google.com/v1beta1",
464
- kind: "StorageBucket",
465
- name: "my-bucket",
466
- },
467
- });
468
- \`\`\``,
469
- },
470
- {
471
- slug: "composite-examples",
472
- title: "Examples: Composites",
473
- description: "All 10 GCP composites with full code and deployment workflow",
474
- content: `Composites are higher-level constructs that produce multiple coordinated Config Connector resources from a single function call.
475
-
476
- ## GkeCluster
477
-
478
- GKE cluster with node pool and workload identity:
479
-
480
- \`\`\`typescript
481
- import { GkeCluster } from "@intentius/chant-lexicon-gcp";
482
-
483
- const { cluster, nodePool } = GkeCluster({
484
- name: "my-cluster",
485
- location: "us-central1",
486
- machineType: "e2-standard-4",
487
- minNodeCount: 1,
488
- maxNodeCount: 10,
489
- workloadIdentity: true,
490
- });
491
-
492
- export { cluster, nodePool };
493
- \`\`\`
494
-
495
- ## CloudRunService
496
-
497
- Cloud Run service with optional public access:
498
-
499
- \`\`\`typescript
500
- import { CloudRunService } from "@intentius/chant-lexicon-gcp";
501
-
502
- const { service, publicIam } = CloudRunService({
503
- name: "my-api",
504
- image: "gcr.io/my-project/api:1.0",
505
- port: 8080,
506
- publicAccess: true,
507
- minInstanceCount: 1,
508
- maxInstanceCount: 10,
509
- });
510
-
511
- export { service, publicIam };
512
- \`\`\`
513
-
514
- ## CloudSqlInstance
515
-
516
- PostgreSQL with database and user:
517
-
518
- \`\`\`typescript
519
- import { CloudSqlInstance } from "@intentius/chant-lexicon-gcp";
520
-
521
- const { instance, database, user } = CloudSqlInstance({
522
- name: "app-db",
523
- tier: "db-custom-2-8192",
524
- backupEnabled: true,
525
- highAvailability: true,
526
- });
527
-
528
- export { instance, database, user };
529
- \`\`\`
530
-
531
- ## GcsBucket
532
-
533
- Storage bucket with encryption and lifecycle:
534
-
535
- \`\`\`typescript
536
- import { GcsBucket } from "@intentius/chant-lexicon-gcp";
537
-
538
- const { bucket } = GcsBucket({
539
- name: "data-lake",
540
- location: "US",
541
- versioning: true,
542
- kmsKeyName: "projects/p/locations/us/keyRings/kr/cryptoKeys/key",
543
- lifecycleDeleteAfterDays: 365,
544
- lifecycleNearlineAfterDays: 30,
545
- });
546
-
547
- export { bucket };
548
- \`\`\`
549
-
550
- ## VpcNetwork
551
-
552
- VPC with subnets, firewalls, and Cloud NAT:
553
-
554
- \`\`\`typescript
555
- import { VpcNetwork } from "@intentius/chant-lexicon-gcp";
556
-
557
- const { network, subnets, firewalls, router, routerNat } = VpcNetwork({
558
- name: "production",
559
- subnets: [
560
- { name: "app", ipCidrRange: "10.0.0.0/24", region: "us-central1" },
561
- { name: "data", ipCidrRange: "10.0.1.0/24", region: "us-central1" },
562
- ],
563
- enableNat: true,
564
- natRegion: "us-central1",
565
- allowIapSsh: true,
566
- });
567
-
568
- export { network, subnets, firewalls, router, routerNat };
569
- \`\`\`
570
-
571
- ## PubSubPipeline
572
-
573
- Topic + Subscription + optional dead-letter queue:
574
-
575
- \`\`\`typescript
576
- import { PubSubPipeline } from "@intentius/chant-lexicon-gcp";
577
-
578
- const { topic, subscription, deadLetterTopic, subscriberIam } = PubSubPipeline({
579
- name: "order-events",
580
- enableDeadLetterQueue: true,
581
- maxDeliveryAttempts: 5,
582
- subscriberServiceAccount: "worker@my-project.iam.gserviceaccount.com",
583
- });
584
-
585
- export { topic, subscription, deadLetterTopic, subscriberIam };
586
- \`\`\`
587
-
588
- ## CloudFunctionWithTrigger
589
-
590
- Cloud Function + source bucket + optional public invoker IAM:
591
-
592
- \`\`\`typescript
593
- import { CloudFunctionWithTrigger } from "@intentius/chant-lexicon-gcp";
594
-
595
- const { function: fn, sourceBucket, invokerIam } = CloudFunctionWithTrigger({
596
- name: "process-upload",
597
- runtime: "nodejs20",
598
- entryPoint: "handler",
599
- triggerType: "pubsub",
600
- triggerTopic: "file-uploads",
601
- region: "us-central1",
602
- });
603
-
604
- export { fn, sourceBucket, invokerIam };
605
- \`\`\`
606
-
607
- ## PrivateService
608
-
609
- Private service networking (VPC peering):
610
-
611
- \`\`\`typescript
612
- import { PrivateService } from "@intentius/chant-lexicon-gcp";
613
-
614
- const { globalAddress, serviceConnection, dnsZone } = PrivateService({
615
- name: "db-peering",
616
- networkName: "production",
617
- enableDns: true,
618
- });
619
-
620
- export { globalAddress, serviceConnection, dnsZone };
621
- \`\`\`
622
-
623
- ## ManagedCertificate
624
-
625
- Google-managed SSL certificate + optional HTTPS proxy:
626
-
627
- \`\`\`typescript
628
- import { ManagedCertificate } from "@intentius/chant-lexicon-gcp";
629
-
630
- const { certificate, targetHttpsProxy, urlMap } = ManagedCertificate({
631
- name: "web-cert",
632
- domains: ["example.com", "www.example.com"],
633
- createProxy: true,
634
- backendServiceName: "web-backend",
635
- });
636
-
637
- export { certificate, targetHttpsProxy, urlMap };
638
- \`\`\`
639
-
640
- ## SecureProject
641
-
642
- Project with audit logging, API enablement, and IAM:
643
-
644
- \`\`\`typescript
645
- import { SecureProject } from "@intentius/chant-lexicon-gcp";
646
-
647
- const { project, auditConfig, services, ownerIam, loggingSink } = SecureProject({
648
- name: "my-project",
649
- orgId: "123456789",
650
- billingAccountRef: "ABCDEF-123456-ABCDEF",
651
- owner: "user:admin@example.com",
652
- loggingSinkDestination: "bigquery.googleapis.com/projects/audit/datasets/logs",
653
- });
654
-
655
- export { project, auditConfig, services, ownerIam, loggingSink };
656
- \`\`\`
657
-
658
- ## Deploying composites
659
-
660
- \`\`\`bash
661
- # Build YAML manifests
662
- chant build src/ --output manifests.yaml
663
-
664
- # Lint for common issues
665
- chant lint src/
666
-
667
- # Dry run
668
- kubectl apply -f manifests.yaml --dry-run=server
669
-
670
- # Apply
671
- kubectl apply -f manifests.yaml
672
- \`\`\``,
673
- },
674
- {
675
- slug: "operational-playbook",
676
- title: "Operational Playbook",
677
- description: "Build, lint, apply, troubleshoot Config Connector resources",
678
- content: `This playbook covers the full lifecycle of chant-produced Config Connector manifests.
679
-
680
- ## Build & validate
681
-
682
- | Step | Command | What it catches |
683
- |------|---------|-----------------|
684
- | Lint source | \`chant lint src/\` | Hardcoded project IDs (WGC001), regions (WGC002), public IAM (WGC003) |
685
- | Build manifests | \`chant build src/ --output manifests.yaml\` | Post-synth: missing encryption (WGC101), public IAM (WGC102), missing project annotation (WGC103), 14 more checks |
686
- | Server dry-run | \`kubectl apply -f manifests.yaml --dry-run=server\` | K8s API validation: CRD schema errors, admission webhooks |
687
-
688
- ## Deploy to Kubernetes
689
-
690
- \`\`\`bash
691
- # Build
692
- chant build src/ --output manifests.yaml
693
-
694
- # Diff before applying
695
- kubectl diff -f manifests.yaml
696
-
697
- # Dry run
698
- kubectl apply -f manifests.yaml --dry-run=server
699
-
700
- # Apply
701
- kubectl apply -f manifests.yaml
702
- \`\`\`
703
-
704
- ## Monitoring reconciliation
705
-
706
- \`\`\`bash
707
- # List all Config Connector resources
708
- kubectl get gcp -A
709
-
710
- # Check specific resource status
711
- kubectl describe storagebuckets.storage.cnrm.cloud.google.com my-bucket
712
-
713
- # Watch for status changes
714
- kubectl get gcp -A -w
715
- \`\`\`
716
-
717
- ## Troubleshooting
718
-
719
- | Status | Meaning | Diagnostic | Fix |
720
- |--------|---------|------------|-----|
721
- | UpToDate | Resource in sync | None needed | — |
722
- | Updating | Applying changes | \`kubectl describe\` → Events | Wait for completion |
723
- | UpdateFailed | GCP API error | \`kubectl describe\` → Events | Check IAM permissions, quota, API enablement |
724
- | DependencyNotReady | Waiting for ref | \`kubectl get gcp\` | Ensure referenced resource exists and is UpToDate |
725
- | DeletionFailed | Cannot delete | \`kubectl describe\` → Events | Check IAM permissions, child resource dependencies |
726
-
727
- ## Common issues
728
-
729
- | Symptom | Cause | Resolution |
730
- |---------|-------|------------|
731
- | Resource stuck in Updating | Missing GCP API | Enable API: add Service resource or \`gcloud services enable\` |
732
- | Permission denied | Service account lacks IAM role | Grant role to Config Connector SA |
733
- | Resource recreated on every apply | Missing deletion-policy annotation | Add \`cnrm.cloud.google.com/deletion-policy: abandon\` |
734
- | Namespace not found | ConfigConnectorContext missing | Create ConfigConnectorContext in namespace |
735
- | Cross-project reference fails | Missing project annotation | Add \`cnrm.cloud.google.com/project-id\` annotation |
736
-
737
- ## Quick reference
738
-
739
- | Command | Description |
740
- |---------|-------------|
741
- | \`chant build src/\` | Synthesize manifests |
742
- | \`chant lint src/\` | Check for anti-patterns |
743
- | \`kubectl apply -f manifests.yaml\` | Apply to cluster |
744
- | \`kubectl get gcp -A\` | List all Config Connector resources |
745
- | \`kubectl describe <resource>\` | Check reconciliation status |
746
- | \`kubectl delete -f manifests.yaml\` | Remove resources |`,
747
- },
748
- {
749
- slug: "importing-yaml",
750
- title: "Importing Existing YAML",
751
- description: "Convert existing Config Connector YAML into typed TypeScript",
752
- content: `Chant can parse existing Config Connector YAML manifests and generate typed TypeScript source files.
753
-
754
- ## How it works
755
-
756
- \`\`\`
757
- Input YAML → parse → generate TypeScript → export typed resources
758
- \`\`\`
759
-
760
- The importer reads multi-document YAML, identifies Config Connector resources by their \`cnrm.cloud.google.com\` apiVersion, and generates corresponding typed constructor calls.
761
-
762
- ## Example
763
-
764
- Input YAML:
765
-
766
- \`\`\`yaml
767
- apiVersion: storage.cnrm.cloud.google.com/v1beta1
768
- kind: StorageBucket
769
- metadata:
770
- name: my-bucket
771
- spec:
772
- location: US
773
- uniformBucketLevelAccess: true
774
- \`\`\`
775
-
776
- Generated TypeScript:
777
-
778
- \`\`\`typescript
779
- import { Bucket } from "@intentius/chant-lexicon-gcp";
780
-
781
- export const myBucket = new Bucket({
782
- metadata: { name: "my-bucket" },
783
- location: "US",
784
- uniformBucketLevelAccess: true,
785
- });
786
- \`\`\`
787
-
788
- ## Limitations
789
-
790
- The import pipeline:
791
-
792
- - Only handles Config Connector resources (\`cnrm.cloud.google.com\` apiVersion)
793
- - Non-CC resources (standard K8s Deployments, Services) are filtered out
794
- - Resource references are preserved as literal values, not typed refs
795
- - Multi-document YAML is fully supported`,
796
- },
797
- {
798
- slug: "skills",
799
- title: "AI Skills",
800
- description: "AI agent skills bundled with the GCP lexicon",
801
- content: `The GCP lexicon ships an AI skill called **chant-gcp** that teaches AI coding agents how to build, validate, and deploy Config Connector manifests from a chant project.
802
-
803
- ## What are skills?
804
-
805
- Skills are structured markdown documents bundled with a lexicon. When an AI agent works in a chant project, it discovers and loads relevant skills automatically.
806
-
807
- ## Installation
808
-
809
- When you scaffold a new project with \`chant init --lexicon gcp\`, the skill is installed to \`skills/chant-gcp/SKILL.md\`.
810
-
811
- ## Skill: chant-gcp
812
-
813
- The \`chant-gcp\` skill covers:
814
-
815
- - **Build** — \`chant build src/ --output manifests.yaml\`
816
- - **Lint** — \`chant lint src/\` + 23 post-synth checks
817
- - **Apply** — \`kubectl apply -f manifests.yaml\`
818
- - **Status** — \`kubectl get gcp -A\`
819
- - **Troubleshooting** — reconciliation status, events, common error patterns
820
-
821
- ## MCP integration
822
-
823
- | MCP tool | Description |
824
- |----------|-------------|
825
- | \`diff\` | Compare current build output against previous |
826
-
827
- | MCP resource | Description |
828
- |--------------|-------------|
829
- | \`resource-catalog\` | JSON list of all supported Config Connector resource types |
830
- | \`examples/basic-bucket\` | Example StorageBucket code |`,
831
- },
832
- ],
833
- // `lint-rules` is gcp's rules documentation, so the generated `rules`
834
- // table is a duplicate — and buildSidebar already declines to link it when
835
- // a `lint-rules` page exists, which left it emitted but unreachable
836
- // (#1312). aws, k8s, gitlab and github suppress it for the same reason.
837
- sidebarExtra: [
838
- { label: "Deploying to GKE", slug: "gke-kubernetes" },
839
- ],
840
114
  };
841
115
 
842
116
  const result = docsPipeline(config);
@@ -1,4 +1,5 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc101 } from "./wgc101";
3
4
  import { wgc102 } from "./wgc102";
4
5
  import { wgc103 } from "./wgc103";
@@ -24,9 +25,7 @@ import { wgc402 } from "./wgc402";
24
25
  import { wgc403 } from "./wgc403";
25
26
 
26
27
  function makeCtx(yaml: string) {
27
- return {
28
- outputs: new Map([["gcp", yaml]]),
29
- };
28
+ return makePostSynthCtx("gcp", yaml);
30
29
  }
31
30
 
32
31
  // ── WGC101: Missing encryption ─────────────────────────────────────
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc101 } from "./wgc101";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC101: missing encryption", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc102 } from "./wgc102";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC102: public IAM in output", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc103 } from "./wgc103";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC103: missing project annotation", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc104 } from "./wgc104";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC104: missing uniform bucket access", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc105 } from "./wgc105";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC105: public Cloud SQL", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc106 } from "./wgc106";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC106: missing deletion policy", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc107 } from "./wgc107";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC107: missing versioning", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc108 } from "./wgc108";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC108: missing backup configuration", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc109 } from "./wgc109";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC109: open firewall", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc110 } from "./wgc110";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC110: missing key rotation", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc111 } from "./wgc111";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC111: dangling resource reference", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc112 } from "./wgc112";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC112: missing or invalid apiVersion", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc113 } from "./wgc113";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC113: alpha API version", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc201 } from "./wgc201";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC201: missing managed-by label", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc202 } from "./wgc202";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC202: missing workload identity", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc203 } from "./wgc203";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC203: cloud-platform OAuth scope", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc204 } from "./wgc204";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC204: missing shielded VM config", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc301 } from "./wgc301";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC301: no audit logging", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc302 } from "./wgc302";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC302: service API not enabled", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc303 } from "./wgc303";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC303: missing VPC Service Controls", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc401 } from "./wgc401";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC401: unknown spec field", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc402 } from "./wgc402";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC402: missing required field", () => {
@@ -1,10 +1,9 @@
1
1
  import { describe, test, expect } from "vitest";
2
+ import { makePostSynthCtx } from "@intentius/chant-test-utils";
2
3
  import { wgc403 } from "./wgc403";
3
4
 
4
5
  function makeCtx(yaml: string) {
5
- return {
6
- outputs: new Map([["gcp", yaml]]),
7
- };
6
+ return makePostSynthCtx("gcp", yaml);
8
7
  }
9
8
 
10
9
  describe("WGC403: type/structure mismatch", () => {
@@ -216,7 +216,7 @@ describe("gcpSerializer", () => {
216
216
  }),
217
217
  );
218
218
 
219
- const result = gcpSerializer.serialize(entities);
219
+ const result = gcpSerializer.serialize(entities) as string;
220
220
  expect(result).toContain("env: prod");
221
221
  // Should not contain "dev" since explicit overrides
222
222
  const envLines = result.split("\n").filter((l: string) => l.includes("env:"));
@@ -233,7 +233,7 @@ describe("gcpSerializer", () => {
233
233
  }),
234
234
  );
235
235
 
236
- const result = gcpSerializer.serialize(entities);
236
+ const result = gcpSerializer.serialize(entities) as string;
237
237
  // Only one document — property entities should not appear as separate docs
238
238
  expect(result.split("---").length).toBeLessThanOrEqual(2);
239
239
  });
@@ -264,7 +264,7 @@ describe("gcpSerializer", () => {
264
264
  }),
265
265
  );
266
266
 
267
- const result = gcpSerializer.serialize(entities);
267
+ const result = gcpSerializer.serialize(entities) as string;
268
268
  const lines = result.split("\n");
269
269
  const keyLines = lines.filter((l: string) => /^\w+:/.test(l));
270
270
  const keys = keyLines.map((l: string) => l.split(":")[0]);