@intentius/chant-lexicon-cpln 0.53.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.
- package/README.md +85 -0
- package/dist/api.d.ts +77 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/codegen/docs-cli.d.ts +3 -0
- package/dist/codegen/docs-cli.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts +17 -0
- package/dist/codegen/docs.d.ts.map +1 -0
- package/dist/codegen/generate-cli.d.ts +6 -0
- package/dist/codegen/generate-cli.d.ts.map +1 -0
- package/dist/codegen/generate-lexicon.d.ts +36 -0
- package/dist/codegen/generate-lexicon.d.ts.map +1 -0
- package/dist/codegen/generate-typescript.d.ts +11 -0
- package/dist/codegen/generate-typescript.d.ts.map +1 -0
- package/dist/codegen/generate.d.ts +15 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/naming.d.ts +30 -0
- package/dist/codegen/naming.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +17 -0
- package/dist/codegen/package.d.ts.map +1 -0
- package/dist/composites/cron-job.d.ts +60 -0
- package/dist/composites/cron-job.d.ts.map +1 -0
- package/dist/composites/gvc-environment.d.ts +47 -0
- package/dist/composites/gvc-environment.d.ts.map +1 -0
- package/dist/composites/index.d.ts +13 -0
- package/dist/composites/index.d.ts.map +1 -0
- package/dist/composites/public-domain.d.ts +68 -0
- package/dist/composites/public-domain.d.ts.map +1 -0
- package/dist/composites/secret-access.d.ts +78 -0
- package/dist/composites/secret-access.d.ts.map +1 -0
- package/dist/composites/serverless-service.d.ts +78 -0
- package/dist/composites/serverless-service.d.ts.map +1 -0
- package/dist/composites/stateful-service.d.ts +79 -0
- package/dist/composites/stateful-service.d.ts.map +1 -0
- package/dist/coverage.d.ts +59 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/describe-resources.d.ts +71 -0
- package/dist/describe-resources.d.ts.map +1 -0
- package/dist/detect.d.ts +14 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/entity-props.d.ts +34 -0
- package/dist/entity-props.d.ts.map +1 -0
- package/dist/generated/index.d.ts +151 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/runtime.d.ts +5 -0
- package/dist/generated/runtime.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/init-templates.d.ts +16 -0
- package/dist/init-templates.d.ts.map +1 -0
- package/dist/integrity.json +35 -0
- package/dist/kinds.d.ts +70 -0
- package/dist/kinds.d.ts.map +1 -0
- package/dist/lint/audit-catalog.d.ts +19 -0
- package/dist/lint/audit-catalog.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl010-unrestricted-outbound.d.ts +12 -0
- package/dist/lint/post-synth/cpl010-unrestricted-outbound.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl011-internal-firewall-scope.d.ts +11 -0
- package/dist/lint/post-synth/cpl011-internal-firewall-scope.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl012-no-literal-credential-env.d.ts +11 -0
- package/dist/lint/post-synth/cpl012-no-literal-credential-env.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl013-qualified-identity-principal.d.ts +11 -0
- package/dist/lint/post-synth/cpl013-qualified-identity-principal.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl014-qualified-secret-ref.d.ts +14 -0
- package/dist/lint/post-synth/cpl014-qualified-secret-ref.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl020-serverless-single-port.d.ts +10 -0
- package/dist/lint/post-synth/cpl020-serverless-single-port.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl021-cron-job-shape.d.ts +11 -0
- package/dist/lint/post-synth/cpl021-cron-job-shape.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl022-container-ports.d.ts +10 -0
- package/dist/lint/post-synth/cpl022-container-ports.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl023-container-resources.d.ts +12 -0
- package/dist/lint/post-synth/cpl023-container-resources.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl024-probe-handler.d.ts +10 -0
- package/dist/lint/post-synth/cpl024-probe-handler.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl025-autoscaling-shape.d.ts +11 -0
- package/dist/lint/post-synth/cpl025-autoscaling-shape.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl026-scale-to-zero.d.ts +11 -0
- package/dist/lint/post-synth/cpl026-scale-to-zero.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl027-capacity-ai-conflict.d.ts +13 -0
- package/dist/lint/post-synth/cpl027-capacity-ai-conflict.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl028-volume-set.d.ts +3 -0
- package/dist/lint/post-synth/cpl028-volume-set.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl029-link-targets.d.ts +3 -0
- package/dist/lint/post-synth/cpl029-link-targets.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl030-domain-routing.d.ts +3 -0
- package/dist/lint/post-synth/cpl030-domain-routing.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl040-pinned-image.d.ts +11 -0
- package/dist/lint/post-synth/cpl040-pinned-image.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl041-image-reference-form.d.ts +12 -0
- package/dist/lint/post-synth/cpl041-image-reference-form.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl042-gvc-placement.d.ts +10 -0
- package/dist/lint/post-synth/cpl042-gvc-placement.d.ts.map +1 -0
- package/dist/lint/post-synth/cpl043-policy-scope.d.ts +16 -0
- package/dist/lint/post-synth/cpl043-policy-scope.d.ts.map +1 -0
- package/dist/lint/post-synth/helpers.d.ts +45 -0
- package/dist/lint/post-synth/helpers.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts +3 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -0
- package/dist/lint/rules/cpl001-no-secret-literals.d.ts +3 -0
- package/dist/lint/rules/cpl001-no-secret-literals.d.ts.map +1 -0
- package/dist/lint/rules/cpl002-prefer-resource-reference.d.ts +3 -0
- package/dist/lint/rules/cpl002-prefer-resource-reference.d.ts.map +1 -0
- package/dist/lint/rules/index.d.ts +6 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lsp/completions.d.ts +7 -0
- package/dist/lsp/completions.d.ts.map +1 -0
- package/dist/lsp/hover.d.ts +4 -0
- package/dist/lsp/hover.d.ts.map +1 -0
- package/dist/manifest.json +6 -0
- package/dist/meta.json +2110 -0
- package/dist/okf/index.md +39 -0
- package/dist/okf/rules/CPL001.md +22 -0
- package/dist/okf/rules/CPL002.md +22 -0
- package/dist/okf/rules/CPL010.md +15 -0
- package/dist/okf/rules/CPL011.md +15 -0
- package/dist/okf/rules/CPL012.md +15 -0
- package/dist/okf/rules/CPL013.md +15 -0
- package/dist/okf/rules/CPL014.md +16 -0
- package/dist/okf/rules/CPL020.md +11 -0
- package/dist/okf/rules/CPL021.md +15 -0
- package/dist/okf/rules/CPL022.md +15 -0
- package/dist/okf/rules/CPL023.md +15 -0
- package/dist/okf/rules/CPL024.md +15 -0
- package/dist/okf/rules/CPL025.md +15 -0
- package/dist/okf/rules/CPL026.md +15 -0
- package/dist/okf/rules/CPL027.md +15 -0
- package/dist/okf/rules/CPL028.md +15 -0
- package/dist/okf/rules/CPL029.md +15 -0
- package/dist/okf/rules/CPL030.md +16 -0
- package/dist/okf/rules/CPL040.md +15 -0
- package/dist/okf/rules/CPL041.md +15 -0
- package/dist/okf/rules/CPL042.md +11 -0
- package/dist/okf/rules/CPL043.md +15 -0
- package/dist/okf/types/Domain.md +22 -0
- package/dist/okf/types/Gvc.md +21 -0
- package/dist/okf/types/Identity.md +29 -0
- package/dist/okf/types/IpSet.md +21 -0
- package/dist/okf/types/Policy.md +28 -0
- package/dist/okf/types/Secret.md +23 -0
- package/dist/okf/types/VolumeSet.md +22 -0
- package/dist/okf/types/Workload.md +38 -0
- package/dist/ownership.d.ts +23 -0
- package/dist/ownership.d.ts.map +1 -0
- package/dist/package-cli.d.ts +3 -0
- package/dist/package-cli.d.ts.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/reference-catalog.d.ts +24 -0
- package/dist/reference-catalog.d.ts.map +1 -0
- package/dist/rules/cpl001-no-secret-literals.ts +83 -0
- package/dist/rules/cpl002-prefer-resource-reference.ts +71 -0
- package/dist/rules/cpl010-unrestricted-outbound.ts +41 -0
- package/dist/rules/cpl011-internal-firewall-scope.ts +38 -0
- package/dist/rules/cpl012-no-literal-credential-env.ts +58 -0
- package/dist/rules/cpl013-qualified-identity-principal.ts +45 -0
- package/dist/rules/cpl014-qualified-secret-ref.ts +54 -0
- package/dist/rules/cpl020-serverless-single-port.ts +58 -0
- package/dist/rules/cpl021-cron-job-shape.ts +64 -0
- package/dist/rules/cpl022-container-ports.ts +64 -0
- package/dist/rules/cpl023-container-resources.ts +87 -0
- package/dist/rules/cpl024-probe-handler.ts +51 -0
- package/dist/rules/cpl025-autoscaling-shape.ts +100 -0
- package/dist/rules/cpl026-scale-to-zero.ts +67 -0
- package/dist/rules/cpl027-capacity-ai-conflict.ts +78 -0
- package/dist/rules/cpl028-volume-set.ts +183 -0
- package/dist/rules/cpl029-link-targets.ts +155 -0
- package/dist/rules/cpl030-domain-routing.ts +137 -0
- package/dist/rules/cpl040-pinned-image.ts +48 -0
- package/dist/rules/cpl041-image-reference-form.ts +60 -0
- package/dist/rules/cpl042-gvc-placement.ts +57 -0
- package/dist/rules/cpl043-policy-scope.ts +0 -0
- package/dist/rules/helpers.ts +114 -0
- package/dist/serializer.d.ts +69 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/skills/chant-cpln-secrets.md +110 -0
- package/dist/skills/chant-cpln-workloads.md +78 -0
- package/dist/skills/chant-cpln.md +103 -0
- package/dist/spec/fetch.d.ts +43 -0
- package/dist/spec/fetch.d.ts.map +1 -0
- package/dist/spec/parse.d.ts +79 -0
- package/dist/spec/parse.d.ts.map +1 -0
- package/dist/spec/snapshot-cli.d.ts +18 -0
- package/dist/spec/snapshot-cli.d.ts.map +1 -0
- package/dist/types/index.d.ts +1649 -0
- package/dist/validate-cli.d.ts +3 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate.d.ts +26 -0
- package/dist/validate.d.ts.map +1 -0
- package/package.json +74 -0
- package/src/api.ts +134 -0
- package/src/codegen/docs-cli.ts +7 -0
- package/src/codegen/docs.ts +94 -0
- package/src/codegen/generate-cli.ts +34 -0
- package/src/codegen/generate-lexicon.ts +88 -0
- package/src/codegen/generate-typescript.ts +71 -0
- package/src/codegen/generate.ts +110 -0
- package/src/codegen/naming.ts +61 -0
- package/src/codegen/package.ts +35 -0
- package/src/composites/composites.test.ts +252 -0
- package/src/composites/cron-job.ts +124 -0
- package/src/composites/gvc-environment.ts +104 -0
- package/src/composites/index.ts +17 -0
- package/src/composites/public-domain.ts +144 -0
- package/src/composites/secret-access.ts +136 -0
- package/src/composites/serverless-service.ts +143 -0
- package/src/composites/stateful-service.ts +179 -0
- package/src/coverage.ts +149 -0
- package/src/describe-resources.test.ts +252 -0
- package/src/describe-resources.ts +310 -0
- package/src/detect.ts +58 -0
- package/src/entity-props.ts +98 -0
- package/src/generated/index.d.ts +1649 -0
- package/src/generated/index.ts +156 -0
- package/src/generated/lexicon-cpln.json +2110 -0
- package/src/generated/runtime.ts +4 -0
- package/src/index.ts +31 -0
- package/src/init-templates.ts +131 -0
- package/src/kinds.ts +173 -0
- package/src/lint/audit-catalog.ts +230 -0
- package/src/lint/post-synth/cpl010-unrestricted-outbound.ts +41 -0
- package/src/lint/post-synth/cpl011-internal-firewall-scope.ts +38 -0
- package/src/lint/post-synth/cpl012-no-literal-credential-env.ts +58 -0
- package/src/lint/post-synth/cpl013-qualified-identity-principal.ts +45 -0
- package/src/lint/post-synth/cpl014-qualified-secret-ref.ts +54 -0
- package/src/lint/post-synth/cpl020-serverless-single-port.ts +58 -0
- package/src/lint/post-synth/cpl021-cron-job-shape.ts +64 -0
- package/src/lint/post-synth/cpl022-container-ports.ts +64 -0
- package/src/lint/post-synth/cpl023-container-resources.ts +87 -0
- package/src/lint/post-synth/cpl024-probe-handler.ts +51 -0
- package/src/lint/post-synth/cpl025-autoscaling-shape.ts +100 -0
- package/src/lint/post-synth/cpl026-scale-to-zero.ts +67 -0
- package/src/lint/post-synth/cpl027-capacity-ai-conflict.ts +78 -0
- package/src/lint/post-synth/cpl028-volume-set.ts +183 -0
- package/src/lint/post-synth/cpl029-link-targets.ts +155 -0
- package/src/lint/post-synth/cpl030-domain-routing.ts +137 -0
- package/src/lint/post-synth/cpl040-pinned-image.ts +48 -0
- package/src/lint/post-synth/cpl041-image-reference-form.ts +60 -0
- package/src/lint/post-synth/cpl042-gvc-placement.ts +57 -0
- package/src/lint/post-synth/cpl043-policy-scope.ts +0 -0
- package/src/lint/post-synth/helpers.ts +114 -0
- package/src/lint/post-synth/index.ts +45 -0
- package/src/lint/post-synth/post-synth.test.ts +737 -0
- package/src/lint/rules/cpl001-no-secret-literals.ts +83 -0
- package/src/lint/rules/cpl002-prefer-resource-reference.ts +71 -0
- package/src/lint/rules/index.ts +9 -0
- package/src/lint/rules/rules.test.ts +108 -0
- package/src/lsp/completions.test.ts +44 -0
- package/src/lsp/completions.ts +27 -0
- package/src/lsp/hover.test.ts +53 -0
- package/src/lsp/hover.ts +130 -0
- package/src/ownership.ts +28 -0
- package/src/package-cli.ts +25 -0
- package/src/plugin.test.ts +131 -0
- package/src/plugin.ts +187 -0
- package/src/reference-catalog.ts +110 -0
- package/src/serializer.test.ts +233 -0
- package/src/serializer.ts +253 -0
- package/src/skills/chant-cpln-secrets.md +110 -0
- package/src/skills/chant-cpln-workloads.md +78 -0
- package/src/skills/chant-cpln.md +103 -0
- package/src/spec/cpln-openapi.snapshot.json +10651 -0
- package/src/spec/fetch.ts +77 -0
- package/src/spec/parse.ts +451 -0
- package/src/spec/snapshot-cli.ts +71 -0
- package/src/validate-cli.ts +8 -0
- package/src/validate.ts +102 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: chant-cpln-secrets
|
|
3
|
+
description: Wire Control Plane secrets, identities and policies so a workload can actually read them — the three-step path and its silent failures
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Control Plane Secrets, Identities and Policies
|
|
8
|
+
|
|
9
|
+
Control Plane's own documentation calls a partial version of this its **number one support issue**. The reason is worth stating up front: every way of getting it wrong fails *silently at runtime*. The API accepts the broken form, the workload starts, and the failure surfaces later as an application error.
|
|
10
|
+
|
|
11
|
+
## The three steps
|
|
12
|
+
|
|
13
|
+
All three are required. Missing any one produces no apply-time error.
|
|
14
|
+
|
|
15
|
+
**1. The workload has an identity.**
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export const identity = new Identity({ name: "web-identity", gvc: "prod" });
|
|
19
|
+
|
|
20
|
+
export const web = new Workload({
|
|
21
|
+
name: "web",
|
|
22
|
+
gvc: "prod",
|
|
23
|
+
spec: { identityLink: identity, /* ... */ },
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**2. A policy grants that identity `reveal` on the secret.**
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
export const policy = new Policy({
|
|
31
|
+
name: "web-secrets",
|
|
32
|
+
targetKind: "secret",
|
|
33
|
+
targetLinks: ["//secret/db-password"],
|
|
34
|
+
bindings: [{
|
|
35
|
+
permissions: ["reveal"],
|
|
36
|
+
principalLinks: ["//gvc/prod/identity/web-identity"],
|
|
37
|
+
}],
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**3. The reference is field-qualified.**
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
env: [{ name: "DATABASE_PASSWORD", value: "cpln://secret/db-password.payload" }]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`SecretAccess` does steps 1 and 2, and `secretRef()` does step 3:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { SecretAccess, secretRef } from "@intentius/chant-lexicon-cpln";
|
|
51
|
+
|
|
52
|
+
export const { identity, policy } = SecretAccess({
|
|
53
|
+
name: "web-identity",
|
|
54
|
+
gvc: "prod",
|
|
55
|
+
secrets: ["db-password"],
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// → "cpln://secret/db-password.payload"
|
|
59
|
+
secretRef("db-password", "payload");
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## The two silent failures
|
|
63
|
+
|
|
64
|
+
**The principal link must be GVC-qualified.** `//identity/NAME` is accepted and ignored. Only `//gvc/GVC/identity/NAME` grants anything. (CPL013)
|
|
65
|
+
|
|
66
|
+
**The secret reference must name a field.** `cpln://secret/db` resolves to nothing:
|
|
67
|
+
|
|
68
|
+
| Type | Field |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `opaque` | `.payload` |
|
|
71
|
+
| `dictionary` | `.KEY` — one env var per key, or volume-mount the whole thing as a directory |
|
|
72
|
+
| `userpass` | `.username`, `.password` |
|
|
73
|
+
| `tls` | `.cert`, `.key` |
|
|
74
|
+
| `keypair` | `.publicKey`, `.privateKey` |
|
|
75
|
+
| `aws` | `.accessKey`, `.secretKey`, `.roleArn` |
|
|
76
|
+
| `gcp` | unqualified — conventionally a volume-mounted JSON file |
|
|
77
|
+
|
|
78
|
+
(CPL014)
|
|
79
|
+
|
|
80
|
+
## Identities
|
|
81
|
+
|
|
82
|
+
- **GVC-scoped and not shareable.** An identity cannot be used from another GVC — declare one per GVC with the same spec (CPL029).
|
|
83
|
+
- A workload has **at most one**.
|
|
84
|
+
- One cloud account per provider: one AWS + one GCP + one Azure, not two AWS.
|
|
85
|
+
- Provider sections have XOR rules: AWS `roleName` ⊻ `policyRefs`, GCP `serviceAccount` ⊻ `bindings`. Network resources `IPs` ⊻ `FQDN`.
|
|
86
|
+
- **Do not assign one unless the workload needs it** — secret access, credential-free cloud access, or private network access. An empty identity assignment complicates audit traces for no benefit.
|
|
87
|
+
|
|
88
|
+
## Policies
|
|
89
|
+
|
|
90
|
+
- `targetKind` is singular and lowercase.
|
|
91
|
+
- Pick exactly one scope: `target: "all"`, `targetLinks`, or `targetQuery`.
|
|
92
|
+
- `ipset`, `mk8s` and `workloadreplica` are **not** valid targets — they are governed through their parent.
|
|
93
|
+
- Max 50 bindings per policy, 200 principal links per binding. Permissions must be sorted alphabetically and unique.
|
|
94
|
+
- Never set `origin` — the system sets it, and a declared value reads as drift on every plan. `builtin` policies cannot be modified at all.
|
|
95
|
+
|
|
96
|
+
Principal forms: `//user/EMAIL`, `//group/NAME`, `//serviceaccount/NAME`, `//gvc/GVC/identity/NAME`.
|
|
97
|
+
|
|
98
|
+
(CPL043)
|
|
99
|
+
|
|
100
|
+
## Secret values in source
|
|
101
|
+
|
|
102
|
+
There are 12 secret types. `cpln secret create` does not exist — the CLI has a `create-<type>` variant for each.
|
|
103
|
+
|
|
104
|
+
Never put credential material in a chant declaration. CPL001 fires on recognisable credential shapes — private keys, cloud access keys, JWTs, database URLs with inline passwords — at author time, where the finding has a file and a line and the credential has not yet reached git history. CPL012 catches the rest from the model: a credential-named env var set to any literal.
|
|
105
|
+
|
|
106
|
+
Read the value from the environment at build time, or set it out of band with `cpln secret edit` and leave chant managing only the secret's existence and its type.
|
|
107
|
+
|
|
108
|
+
## Pull secrets are GVC-level
|
|
109
|
+
|
|
110
|
+
`spec.pullSecretLinks` on the GVC, not on the workload. Only `docker`, `ecr` and `gcp` types are valid as pull secrets. Images from your own org's registry need none.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: chant-cpln-workloads
|
|
3
|
+
description: Choose a Control Plane workload type and configure autoscaling, Capacity AI, resources and probes correctly
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Control Plane Workloads
|
|
8
|
+
|
|
9
|
+
## Pick the type first — it is immutable
|
|
10
|
+
|
|
11
|
+
Changing `type` means delete and recreate. Almost every other constraint follows from it.
|
|
12
|
+
|
|
13
|
+
| | Serverless | Standard | Stateful | Cron |
|
|
14
|
+
|---|:---:|:---:|:---:|:---:|
|
|
15
|
+
| Ports | **exactly 1 HTTP** | 0 or more | 0 or more | **none** |
|
|
16
|
+
| Scale to zero | `rps` / `concurrency` | KEDA only | KEDA only | no |
|
|
17
|
+
| Persistent volumes | no | no | **yes** | no |
|
|
18
|
+
| Multi-metric autoscaling | no | yes | yes | n/a |
|
|
19
|
+
| `spec.job` | forbidden | forbidden | forbidden | **required** |
|
|
20
|
+
| `timeoutSeconds` max | 600 | 3600 | 3600 | n/a |
|
|
21
|
+
|
|
22
|
+
- **Serverless** must expose exactly one HTTP port. Zero is the common mistake and the confusing one: it deploys, reports healthy, and serves nothing (CPL020).
|
|
23
|
+
- **Cron** must not expose ports and must set `spec.job.schedule`. Probes, autoscaling, `timeoutSeconds` and `debug` are all accepted and ignored, so setting them is a silent no-op (CPL021).
|
|
24
|
+
- **Stateful** is the only type that mounts `ext4`/`xfs` volume sets, and the only one that supports `replicaDirect` load balancing or `workloadLink` domain routing.
|
|
25
|
+
|
|
26
|
+
Max 8 containers per workload. Workload names are ≤ 49 characters and cannot end in `-headless`. Container names cannot start with `cpln-` or `debugger-`.
|
|
27
|
+
|
|
28
|
+
## Resources: the ratio is the surprise
|
|
29
|
+
|
|
30
|
+
Defaults are `cpu: 50m`, `memory: 128Mi`.
|
|
31
|
+
|
|
32
|
+
- CPU ≥ 25 millicores, memory ≥ 32 MiB.
|
|
33
|
+
- **`memory(MiB) / cpu(millicores)` ≤ 8.** So `2Gi` needs at least 256m of CPU. A memory-heavy, CPU-light workload is rejected — which surprises people coming from Kubernetes, where the two are independent. The `cpln/relaxMemoryToCpuRatio` tag raises the ceiling to 32.
|
|
34
|
+
|
|
35
|
+
CPL023 checks all three, using the defaults when a value is omitted, so an unset field is checked as what it will actually become.
|
|
36
|
+
|
|
37
|
+
## Autoscaling
|
|
38
|
+
|
|
39
|
+
`metric` and `multi` are alternatives, not layers. `target` belongs to the single-metric form and is capped at 100 for `cpu`/`memory` (it is a utilization percentage).
|
|
40
|
+
|
|
41
|
+
Scale to zero is the one worth being careful with. `minScale: 0` is accepted on any type and only *takes effect* for serverless under `rps`/`concurrency`, or standard/stateful under KEDA. Everywhere else the workload holds at one replica and the cost saving never arrives, with nothing reported (CPL026).
|
|
42
|
+
|
|
43
|
+
KEDA has to be enabled on the GVC before a workload in it can use it.
|
|
44
|
+
|
|
45
|
+
## Capacity AI is on by default
|
|
46
|
+
|
|
47
|
+
For serverless, standard and cron. It resizes CPU and memory from observed usage, and it is **mutually exclusive** with:
|
|
48
|
+
|
|
49
|
+
- CPU-utilization autoscaling — dynamic CPU moves the baseline the metric scales against.
|
|
50
|
+
- Multi-metric autoscaling — needs stable baselines.
|
|
51
|
+
- GPUs — GPU allocation is fixed.
|
|
52
|
+
|
|
53
|
+
These conflicts are usually reached by *adding* CPU scaling or a GPU to a workload that never opted into Capacity AI, so CPL027 says which of the two it is. Turn it off with `spec.defaultOptions.capacityAI: false`.
|
|
54
|
+
|
|
55
|
+
## Probes
|
|
56
|
+
|
|
57
|
+
Exactly one of `exec`, `grpc`, `tcpSocket`, `httpGet` per probe. A probe with only timing fields set looks configured and checks nothing (CPL024).
|
|
58
|
+
|
|
59
|
+
Defaults differ by type: readiness is TCP-on-port for serverless and **disabled** for standard, stateful and cron. And `spec.containers[].port` must match the port the process actually binds, or health checks fail.
|
|
60
|
+
|
|
61
|
+
## Firewalls start closed
|
|
62
|
+
|
|
63
|
+
Both directions of the external firewall are disabled by default, and the internal one is `none`.
|
|
64
|
+
|
|
65
|
+
- Inbound: add CIDRs (`0.0.0.0/0` for the internet).
|
|
66
|
+
- Outbound: CIDRs, or hostnames with a wildcard prefix (`*.amazonaws.com`). Hostname rules allow ports 80/443/445 only unless `outboundAllowPort` says otherwise.
|
|
67
|
+
- CIDR rules take precedence over hostname rules; blocked rules take precedence over allowed ones.
|
|
68
|
+
|
|
69
|
+
CPL010 flags outbound `0.0.0.0/0` — it is rarely needed and is the egress path for anything that gets a foothold. CPL011 flags internal `same-org`, which crosses the boundary the GVC exists to draw.
|
|
70
|
+
|
|
71
|
+
Internal traffic between workloads in a GVC is automatically mTLS-encrypted at `WORKLOAD.GVC.cpln.local:PORT`; there is nothing to configure.
|
|
72
|
+
|
|
73
|
+
## Images
|
|
74
|
+
|
|
75
|
+
- Never prefix a public image with `docker.io/` — `nginx:1.27`, not `docker.io/library/nginx:1.27` (CPL041).
|
|
76
|
+
- Your own org's images are `//image/NAME:TAG` in a workload spec. `<org>.registry.cpln.io` is for `docker login`/`push` only.
|
|
77
|
+
- Images must be `linux/amd64` — the wrong platform is an `exec format error` at runtime, not at apply.
|
|
78
|
+
- Pin a tag or digest. A scale-from-zero cold start re-pulls, so `:latest` means two replicas of one deploy can be different builds (CPL040).
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: chant-cpln
|
|
3
|
+
description: Declare Control Plane (cpln) infrastructure from chant — the kinds, GVC scoping, links, and what the serializer emits
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Control Plane with chant
|
|
8
|
+
|
|
9
|
+
## The shape
|
|
10
|
+
|
|
11
|
+
Control Plane's hierarchy is two levels, and it decides almost everything else:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Org (immutable, cannot be deleted)
|
|
15
|
+
├── org-scoped: Secret, Policy, Domain, IpSet
|
|
16
|
+
└── GVC — the placement and networking boundary
|
|
17
|
+
├── Workload
|
|
18
|
+
├── Identity
|
|
19
|
+
└── VolumeSet
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This lexicon models those eight kinds. `Gvc`, `Secret`, `Policy`, `Domain` and `IpSet` are org-scoped; `Workload`, `Identity` and `VolumeSet` take a required `gvc`.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Gvc, Workload } from "@intentius/chant-lexicon-cpln";
|
|
26
|
+
|
|
27
|
+
export const gvc = new Gvc({
|
|
28
|
+
name: "prod",
|
|
29
|
+
spec: {
|
|
30
|
+
staticPlacement: {
|
|
31
|
+
locationLinks: ["/org/acme/location/aws-us-east-1"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const web = new Workload({
|
|
37
|
+
name: "web",
|
|
38
|
+
gvc: "prod",
|
|
39
|
+
spec: {
|
|
40
|
+
type: "serverless",
|
|
41
|
+
containers: [{ name: "main", image: "nginx:1.27", ports: [{ number: 8080, protocol: "http" }] }],
|
|
42
|
+
firewallConfig: { external: { inboundAllowCIDR: ["0.0.0.0/0"] } },
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`chant build` emits multi-document YAML for `cpln apply --file`. The `gvc` property becomes the manifest's own `gvc:` key, so the file is self-contained and does not depend on a `--gvc` flag.
|
|
48
|
+
|
|
49
|
+
## Pass resources, not link strings
|
|
50
|
+
|
|
51
|
+
Control Plane addresses resources by link. Pass the declared resource where a link is expected and the serializer emits the right one for its kind:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
export const identity = new Identity({ name: "web-identity", gvc: "prod" });
|
|
55
|
+
|
|
56
|
+
export const web = new Workload({
|
|
57
|
+
name: "web",
|
|
58
|
+
gvc: "prod",
|
|
59
|
+
spec: { identityLink: identity, /* → //gvc/prod/identity/web-identity */ ... },
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This matters most for identities. The bare `//identity/NAME` form reads perfectly naturally, is accepted by the API, and is **silently ignored** — the policy applies cleanly and grants nothing. Only `//gvc/GVC/identity/NAME` works. Passing the resource is how you stop having to remember that (CPL013 catches it if you write the string by hand).
|
|
64
|
+
|
|
65
|
+
Link forms, when you do need to write one:
|
|
66
|
+
|
|
67
|
+
| Kind | Link |
|
|
68
|
+
|---|---|
|
|
69
|
+
| GVC | `//gvc/NAME` |
|
|
70
|
+
| Workload / Identity / VolumeSet | `//gvc/GVC/<kind>/NAME` |
|
|
71
|
+
| Secret / Policy / Domain / IpSet | `//<kind>/NAME` |
|
|
72
|
+
| Location | `/org/ORG/location/<provider>-<region>` |
|
|
73
|
+
| Own org's image | `//image/NAME:TAG` |
|
|
74
|
+
|
|
75
|
+
`cpln://secret/NAME.FIELD` and `cpln://volumeset/NAME` are different things — runtime resolution URIs the container reads, not links between resources.
|
|
76
|
+
|
|
77
|
+
## Composites
|
|
78
|
+
|
|
79
|
+
Five, each encoding rules that are easy to violate by omission:
|
|
80
|
+
|
|
81
|
+
- `GvcEnvironment` — GVC with locations and pull secrets. Pull secrets are GVC-level, not per workload.
|
|
82
|
+
- `ServerlessService` — one HTTP port, explicit firewall, autoscaling defaults.
|
|
83
|
+
- `CronJob` — schedule, no ports, no knobs cron ignores.
|
|
84
|
+
- `StatefulService` — workload + volume set, mounted, with the capacity floor checked.
|
|
85
|
+
- `SecretAccess` — identity + policy, GVC-qualified.
|
|
86
|
+
|
|
87
|
+
## Live state
|
|
88
|
+
|
|
89
|
+
Every kind carries a free-form `tags` map, and chant stamps its ownership marker there — `chant.intentius.io/managed-by: chant` plus stack and env. That is what makes `chant plan` precise without a state file: a resource carrying the marker is this stack's, one without it is never auto-deleted.
|
|
90
|
+
|
|
91
|
+
Reading live state needs `CPLN_ORG` and `CPLN_TOKEN` (a service account key, or a JWT). Use the env var, not `--token` — the flag leaks into process listings and logs.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
CPLN_ORG=acme CPLN_TOKEN=$(cat key) chant plan
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Things that are immutable
|
|
98
|
+
|
|
99
|
+
Worth settling before the first apply, because the fix afterwards is delete-and-recreate:
|
|
100
|
+
|
|
101
|
+
- Workload `type` and `name`.
|
|
102
|
+
- VolumeSet `fileSystemType` and `performanceClass` — recreating means data loss.
|
|
103
|
+
- The org itself, which cannot be deleted at all without Control Plane support.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control Plane Core API OpenAPI 3.0.3 spec.
|
|
3
|
+
*
|
|
4
|
+
* `https://api.cpln.io/openapi.json` is an unversioned live endpoint: it always
|
|
5
|
+
* serves the current spec, and there is no tag, release asset, or `info.version`
|
|
6
|
+
* bump to pin against — `info.version` has read `1.0.0` for as long as the
|
|
7
|
+
* endpoint has existed. There is consequently nothing for the self-upgrade
|
|
8
|
+
* tooling to bump, so this plugin declares no `upstreamPin`, the same call fly
|
|
9
|
+
* makes for `docs.machines.dev/openapi.json`. Re-running `generate` picks up
|
|
10
|
+
* whatever the endpoint currently serves.
|
|
11
|
+
*
|
|
12
|
+
* Unlike fly, this lexicon keeps a committed offline fallback. Two reasons the
|
|
13
|
+
* live-only route was not good enough here:
|
|
14
|
+
*
|
|
15
|
+
* - The endpoint is the production API's own doc route, not a docs CDN. It is
|
|
16
|
+
* subject to the same maintenance windows as the API, and a generate step
|
|
17
|
+
* that fails when Control Plane is briefly unreachable makes CI a function of
|
|
18
|
+
* someone else's uptime.
|
|
19
|
+
* - The full document is 2.8 MB, almost all of which is the `patch_*` mirror
|
|
20
|
+
* schemas and kinds this lexicon does not model. The snapshot is pruned to
|
|
21
|
+
* the schemas actually reachable from the modelled kinds — 23 of 106 — which
|
|
22
|
+
* is small enough to commit, and to re-indent for a readable diff, without
|
|
23
|
+
* turning every regeneration into a megabyte-scale change.
|
|
24
|
+
*
|
|
25
|
+
* The fallback is never silent. Both routes log which one was taken, because a
|
|
26
|
+
* fallback nobody can see is how you end up debugging types that came from
|
|
27
|
+
* somewhere you did not expect.
|
|
28
|
+
*
|
|
29
|
+
* Refresh the snapshot with `just snapshot` (see `snapshot-cli.ts`).
|
|
30
|
+
*/
|
|
31
|
+
export declare const SCHEMA_URL = "https://api.cpln.io/openapi.json";
|
|
32
|
+
export declare const SNAPSHOT_FILE: string;
|
|
33
|
+
/** The single map key the parser is handed. The spec is one document. */
|
|
34
|
+
export declare const SPEC_KEY = "Cpln::OpenAPI";
|
|
35
|
+
/**
|
|
36
|
+
* Fetch the Control Plane OpenAPI spec, falling back to the committed pruned
|
|
37
|
+
* snapshot when the endpoint is unreachable. Returns a single-entry map — the
|
|
38
|
+
* whole spec is one document; the parser fans it out into per-kind results.
|
|
39
|
+
*/
|
|
40
|
+
export declare function fetchSchemas(options?: {
|
|
41
|
+
force?: boolean;
|
|
42
|
+
}): Promise<Map<string, Buffer>>;
|
|
43
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/spec/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAQH,eAAO,MAAM,UAAU,qCAAqC,CAAC;AAS7D,eAAO,MAAM,aAAa,QAA8E,CAAC;AAEzG,yEAAyE;AACzE,eAAO,MAAM,QAAQ,kBAAkB,CAAC;AAExC;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoB9F"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control Plane Core API OpenAPI 3.0.3 parser.
|
|
3
|
+
*
|
|
4
|
+
* The cpln spec is one document with a schema per kind. Unlike the k8s swagger
|
|
5
|
+
* or ARM, it is mostly *inline*: `workload.spec.containers[].readinessProbe`
|
|
6
|
+
* is nested object literals all the way down, with only a handful of named
|
|
7
|
+
* `$ref` schemas (`query`, `policy_binding`, `secret_opaque`, …). So there is
|
|
8
|
+
* no upstream definition table to lift property types out of — this parser
|
|
9
|
+
* synthesizes them from the tree, which raises two questions the naming rules
|
|
10
|
+
* below answer: what to call them, and where to stop.
|
|
11
|
+
*
|
|
12
|
+
* ## Naming
|
|
13
|
+
*
|
|
14
|
+
* A `$ref`'d schema keeps its upstream name (`query` → `Query`), so a shape
|
|
15
|
+
* shared by two kinds is emitted once and both reference it. An inline object
|
|
16
|
+
* is named by its path under the nearest named ancestor
|
|
17
|
+
* (`workload.spec.containers[].readinessProbe` → `WorkloadSpecContainersReadinessProbe`).
|
|
18
|
+
* Names are long, but they are derived rather than chosen, so two runs of the
|
|
19
|
+
* generator over the same spec agree, and a property that moves in the spec
|
|
20
|
+
* produces a visible rename rather than a silent re-binding.
|
|
21
|
+
*
|
|
22
|
+
* Arrays do not contribute a segment: an array of objects and a single object
|
|
23
|
+
* yield the same class, because `containers[]` and `containers` describe the
|
|
24
|
+
* same shape.
|
|
25
|
+
*
|
|
26
|
+
* ## Where it stops
|
|
27
|
+
*
|
|
28
|
+
* One subtree is deliberately untyped: `spec.sidecar.envoy` on both `gvc` and
|
|
29
|
+
* `workload`. It is a raw Envoy bootstrap fragment that Control Plane passes
|
|
30
|
+
* through verbatim — `typed_config`, `google_grpc` channel credentials, the
|
|
31
|
+
* lot — and expanding it costs 81 property-type classes on `gvc` alone, more
|
|
32
|
+
* than four times every other shape in this lexicon combined, to type a field
|
|
33
|
+
* whose contents are Envoy's contract and not Control Plane's. It resolves to
|
|
34
|
+
* `Record<string, unknown>`; see {@link LOOSENED_PATHS}.
|
|
35
|
+
*
|
|
36
|
+
* Everything else is typed in full. That comes to 137 property types across
|
|
37
|
+
* the eight kinds, with a natural maximum depth of 6.
|
|
38
|
+
*/
|
|
39
|
+
import { type PropertyConstraints } from "@intentius/chant/codegen/json-schema";
|
|
40
|
+
export type { PropertyConstraints };
|
|
41
|
+
export interface ParsedProperty {
|
|
42
|
+
name: string;
|
|
43
|
+
tsType: string;
|
|
44
|
+
required: boolean;
|
|
45
|
+
description?: string;
|
|
46
|
+
constraints: PropertyConstraints;
|
|
47
|
+
}
|
|
48
|
+
export interface ParsedResource {
|
|
49
|
+
typeName: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
properties: ParsedProperty[];
|
|
52
|
+
attributes: Array<{
|
|
53
|
+
name: string;
|
|
54
|
+
tsType: string;
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
export interface CplnParseResult {
|
|
58
|
+
resource: ParsedResource;
|
|
59
|
+
/** Always empty — cpln emits property types as standalone results, like fly. */
|
|
60
|
+
propertyTypes: Array<{
|
|
61
|
+
name: string;
|
|
62
|
+
defType: string;
|
|
63
|
+
}>;
|
|
64
|
+
/** Always empty — enums are inlined as string-literal unions. */
|
|
65
|
+
enums: Array<{
|
|
66
|
+
name: string;
|
|
67
|
+
values: string[];
|
|
68
|
+
}>;
|
|
69
|
+
/** Whether this entity is a property type rather than a resource. */
|
|
70
|
+
isProperty?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Parse the cpln OpenAPI spec into the modelled kinds and every property type
|
|
74
|
+
* reachable from them.
|
|
75
|
+
*/
|
|
76
|
+
export declare function parseCplnOpenAPI(data: string | Buffer): CplnParseResult[];
|
|
77
|
+
/** `volumeset_spec` → `VolumeSetSpec`, `policy_binding` → `PolicyBinding`. */
|
|
78
|
+
export declare function schemaClassName(schemaName: string): string;
|
|
79
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/spec/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,sCAAsC,CAAC;AAK9C,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,mBAAmB,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,cAAc,CAAC;IACzB,gFAAgF;IAChF,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,iEAAiE;IACjE,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACjD,qEAAqE;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA+GD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,eAAe,EAAE,CAsEzE;AAgKD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAK1D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Refresh the committed offline spec snapshot (`just snapshot`).
|
|
4
|
+
*
|
|
5
|
+
* Fetches the live Control Plane OpenAPI document and writes back the subset
|
|
6
|
+
* reachable from the modelled kinds. Pruning is what makes committing it
|
|
7
|
+
* reasonable: the full document is 2.8 MB of which this lexicon reads 23
|
|
8
|
+
* schemas, and the remainder is `patch_*` mirrors and kinds not modelled here
|
|
9
|
+
* — churn in a file whose whole purpose is to be a stable fallback. It is
|
|
10
|
+
* written re-indented rather than compact so upstream changes show up as a
|
|
11
|
+
* readable diff.
|
|
12
|
+
*
|
|
13
|
+
* Run this on a networked machine whenever the generated surface is meant to
|
|
14
|
+
* move, and commit the result in the same change as the regenerated types, so
|
|
15
|
+
* the snapshot and the types in the tree always describe the same API.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=snapshot-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-cli.d.ts","sourceRoot":"","sources":["../../src/spec/snapshot-cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG"}
|