@intentius/chant 0.45.0 → 0.49.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/dist/audit/core.d.ts +21 -3
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +3 -2
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/build.d.ts +3 -3
- package/dist/build.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +14 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/lexicon-surface-diff.d.ts +6 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts +13 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts +6 -0
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +1 -1
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +7 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/reporters/stylish.d.ts +15 -1
- package/dist/cli/reporters/stylish.d.ts.map +1 -1
- package/dist/codegen/lexicon-regen.d.ts +11 -0
- package/dist/codegen/lexicon-regen.d.ts.map +1 -1
- package/dist/codegen/validate.d.ts +10 -0
- package/dist/codegen/validate.d.ts.map +1 -1
- package/dist/components/auto-release.d.ts +4 -0
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts +2 -0
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/ensure-secret.d.ts +50 -0
- package/dist/components/verbs/ensure-secret.d.ts.map +1 -0
- package/dist/components/verbs/index.d.ts +8 -0
- package/dist/components/verbs/index.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts +76 -0
- package/dist/components/verbs/r2-sync.d.ts.map +1 -0
- package/dist/components/verbs/wrangler.d.ts +108 -0
- package/dist/components/verbs/wrangler.d.ts.map +1 -0
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/deep-observation.d.ts +14 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/effect-receipt.d.ts +177 -0
- package/dist/effect-receipt.d.ts.map +1 -0
- package/dist/env.d.ts +12 -1
- package/dist/env.d.ts.map +1 -1
- package/dist/fold/subset.d.ts +15 -2
- package/dist/fold/subset.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +223 -2
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +33 -5
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +3 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/observation-baseline.d.ts +21 -3
- package/dist/lifecycle/observation-baseline.d.ts.map +1 -1
- package/dist/lifecycle/receipt-plan.d.ts +62 -0
- package/dist/lifecycle/receipt-plan.d.ts.map +1 -0
- package/dist/lifecycle/release-ledger.d.ts +20 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/teardown.d.ts +132 -0
- package/dist/lifecycle/teardown.d.ts.map +1 -0
- package/dist/lifecycle/unobserved-gate.d.ts +67 -0
- package/dist/lifecycle/unobserved-gate.d.ts.map +1 -0
- package/dist/lint/engine.d.ts +6 -2
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/knowledge-checks.d.ts +48 -0
- package/dist/lint/knowledge-checks.d.ts.map +1 -0
- package/dist/lint/output-checks.d.ts +5 -0
- package/dist/lint/output-checks.d.ts.map +1 -0
- package/dist/lint/pipeline-change-gate.d.ts +101 -0
- package/dist/lint/pipeline-change-gate.d.ts.map +1 -0
- package/dist/lint/post-synth.d.ts +12 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/receipt-checks.d.ts +9 -0
- package/dist/lint/receipt-checks.d.ts.map +1 -0
- package/dist/lint/rule.d.ts +31 -0
- package/dist/lint/rule.d.ts.map +1 -1
- package/dist/lint/rules/cor021-env-literal-name.d.ts +3 -0
- package/dist/lint/rules/cor021-env-literal-name.d.ts.map +1 -0
- package/dist/lint/rules/cor022-receipt-leaf.d.ts +13 -0
- package/dist/lint/rules/cor022-receipt-leaf.d.ts.map +1 -0
- package/dist/lint/rules/cor024-receipt-secret-pointer.d.ts +3 -0
- package/dist/lint/rules/cor024-receipt-secret-pointer.d.ts.map +1 -0
- package/dist/lint/rules/evl001-non-literal-expression.d.ts.map +1 -1
- package/dist/lint/rules/index.d.ts +4 -1
- package/dist/lint/rules/index.d.ts.map +1 -1
- package/dist/okf-read.d.ts +78 -0
- package/dist/okf-read.d.ts.map +1 -0
- package/dist/op/builders.d.ts +134 -8
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/index.d.ts +4 -2
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +2 -1
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +138 -0
- package/dist/op/receipt-store.d.ts.map +1 -0
- package/dist/op/types.d.ts +31 -1
- package/dist/op/types.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts +138 -0
- package/dist/secret-materialization.d.ts.map +1 -0
- package/dist/secret-provenance.d.ts +218 -0
- package/dist/secret-provenance.d.ts.map +1 -0
- package/dist/serializer.d.ts +11 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/testing.d.ts +136 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +9 -1
- package/src/audit/core.test.ts +57 -0
- package/src/audit/core.ts +0 -0
- package/src/audit/detect-bundle.test.ts +1 -1
- package/src/audit/discover.test.ts +24 -0
- package/src/audit/discover.ts +11 -2
- package/src/audit/rules-doc.ts +11 -1
- package/src/build.test.ts +41 -0
- package/src/build.ts +34 -6
- package/src/cli/commands/__fixtures__/audit-fountain/agents/fleet.yaml +27 -0
- package/src/cli/commands/__fixtures__/audit-fountain/k8s/deploy.yaml +16 -0
- package/src/cli/commands/__fixtures__/audit-fountain-clean/fleet.yaml +20 -0
- package/src/cli/commands/audit.test.ts +53 -0
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/build.test.ts +211 -0
- package/src/cli/commands/build.ts +126 -8
- package/src/cli/commands/check-lexicon.test.ts +45 -1
- package/src/cli/commands/check-lexicon.ts +45 -0
- package/src/cli/commands/lexicon-surface-diff.ts +9 -0
- package/src/cli/commands/lexicon-surface-diff.update.test.ts +112 -0
- package/src/cli/commands/lint.ts +32 -7
- package/src/cli/handlers/explain.test.ts +70 -1
- package/src/cli/handlers/graph.ts +4 -4
- package/src/cli/handlers/lifecycle.test.ts +345 -1
- package/src/cli/handlers/lifecycle.ts +300 -11
- package/src/cli/handlers/search.ts +5 -2
- package/src/cli/main.ts +12 -1
- package/src/cli/mcp/resource-handlers.ts +38 -1
- package/src/cli/mcp/server.test.ts +58 -1
- package/src/cli/mcp/tools/explain.ts +51 -2
- package/src/cli/plugins.ts +4 -2
- package/src/cli/registry.ts +7 -0
- package/src/cli/reporters/stylish.test.ts +154 -0
- package/src/cli/reporters/stylish.ts +154 -33
- package/src/codegen/lexicon-regen.ts +19 -1
- package/src/codegen/validate.test.ts +33 -0
- package/src/codegen/validate.ts +21 -2
- package/src/components/auto-release.ts +6 -0
- package/src/components/registry.test.ts +7 -2
- package/src/components/starter-plugin.ts +17 -0
- package/src/components/verbs/ensure-secret.test.ts +130 -0
- package/src/components/verbs/ensure-secret.ts +79 -0
- package/src/components/verbs/index.ts +8 -0
- package/src/components/verbs/r2-sync.test.ts +107 -0
- package/src/components/verbs/r2-sync.ts +124 -0
- package/src/components/verbs/wrangler.test.ts +170 -0
- package/src/components/verbs/wrangler.ts +241 -0
- package/src/config.test.ts +55 -0
- package/src/config.ts +88 -1
- package/src/deep-observation.test.ts +19 -0
- package/src/deep-observation.ts +17 -0
- package/src/effect-receipt-exclusion.test.ts +190 -0
- package/src/effect-receipt.test.ts +419 -0
- package/src/effect-receipt.ts +412 -0
- package/src/env.test.ts +35 -1
- package/src/env.ts +17 -3
- package/src/fold/subset.test.ts +26 -0
- package/src/fold/subset.ts +45 -19
- package/src/index.ts +4 -0
- package/src/lexicon.ts +227 -2
- package/src/lifecycle/change-set.ts +46 -7
- package/src/lifecycle/index.ts +3 -0
- package/src/lifecycle/observation-baseline.test.ts +46 -0
- package/src/lifecycle/observation-baseline.ts +33 -1
- package/src/lifecycle/receipt-plan.test.ts +250 -0
- package/src/lifecycle/receipt-plan.ts +249 -0
- package/src/lifecycle/release-ledger.ts +20 -0
- package/src/lifecycle/teardown.test.ts +568 -0
- package/src/lifecycle/teardown.ts +359 -0
- package/src/lifecycle/unobserved-gate.test.ts +109 -0
- package/src/lifecycle/unobserved-gate.ts +102 -0
- package/src/lint/engine.ts +7 -1
- package/src/lint/knowledge-checks.test.ts +80 -0
- package/src/lint/knowledge-checks.ts +74 -0
- package/src/lint/output-checks.test.ts +85 -0
- package/src/lint/output-checks.ts +99 -0
- package/src/lint/pipeline-change-gate.test.ts +144 -0
- package/src/lint/pipeline-change-gate.ts +153 -0
- package/src/lint/post-synth.ts +15 -0
- package/src/lint/receipt-checks.test.ts +101 -0
- package/src/lint/receipt-checks.ts +93 -0
- package/src/lint/rule.ts +23 -0
- package/src/lint/rules/cor021-env-literal-name.test.ts +128 -0
- package/src/lint/rules/cor021-env-literal-name.ts +114 -0
- package/src/lint/rules/cor022-receipt-leaf.test.ts +116 -0
- package/src/lint/rules/cor022-receipt-leaf.ts +130 -0
- package/src/lint/rules/cor024-receipt-secret-pointer.test.ts +121 -0
- package/src/lint/rules/cor024-receipt-secret-pointer.ts +218 -0
- package/src/lint/rules/evl001-non-literal-expression.test.ts +27 -0
- package/src/lint/rules/evl001-non-literal-expression.ts +8 -1
- package/src/lint/rules/index.ts +10 -1
- package/src/okf-read.test.ts +149 -0
- package/src/okf-read.ts +197 -0
- package/src/op/builders.ts +179 -8
- package/src/op/effect-step.test.ts +311 -0
- package/src/op/index.ts +10 -3
- package/src/op/local-executor.ts +172 -25
- package/src/op/op.test.ts +25 -2
- package/src/op/receipt-store.ts +211 -0
- package/src/op/types.ts +33 -1
- package/src/secret-materialization.test.ts +199 -0
- package/src/secret-materialization.ts +235 -0
- package/src/secret-provenance.test.ts +388 -0
- package/src/secret-provenance.ts +475 -0
- package/src/serializer.ts +12 -0
- package/src/testing.test.ts +261 -0
- package/src/testing.ts +338 -0
- package/src/yaml.test.ts +88 -0
- package/src/yaml.ts +76 -6
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated-once secret materialization — the one implementation behind the
|
|
3
|
+
* `ensure-secret` capability verb (components/verbs/ensure-secret.ts) and the
|
|
4
|
+
* `ensureSecret(...)` op step builder (op/builders.ts). chant #1829, epic
|
|
5
|
+
* #1365 decisions 3 and 6.
|
|
6
|
+
*
|
|
7
|
+
* The contract is read-then-write:
|
|
8
|
+
*
|
|
9
|
+
* - Absent: mint once, through the store adapter, and report `created`.
|
|
10
|
+
* - Present: verify presence, the declared key-set, and any declared
|
|
11
|
+
* metadata, then STOP — present means done. Never mint over an existing
|
|
12
|
+
* value. Never rotate implicitly. A re-run of a whole deploy leaves the
|
|
13
|
+
* stored bytes untouched.
|
|
14
|
+
* - Mismatch: fail loudly, naming what mismatched — key names and metadata
|
|
15
|
+
* keys, never a value or a value-derived hash (#1365 decision 6).
|
|
16
|
+
*
|
|
17
|
+
* The constitutional line (../secret-provenance.ts): no code path here may
|
|
18
|
+
* hold, log, hash, or compare a secret value. That is structural, not
|
|
19
|
+
* discipline:
|
|
20
|
+
*
|
|
21
|
+
* - {@link ensureSecretMaterialization} never calls the generator. It hands
|
|
22
|
+
* the generator to the store adapter's `create`, which consumes the
|
|
23
|
+
* material as it writes. The engine's result type has no field that could
|
|
24
|
+
* carry material.
|
|
25
|
+
* - The generator produces {@link SecretMaterial}, an opaque single-use
|
|
26
|
+
* handle. The plaintext lives in a module-private WeakMap, not on the
|
|
27
|
+
* object: enumeration, `JSON.stringify`, `String(...)`, and `util.inspect`
|
|
28
|
+
* all see only a redaction marker. Only {@link consumeSecretMaterial} —
|
|
29
|
+
* meant for store adapters, at the write — yields the plaintext, exactly
|
|
30
|
+
* once; a second consume throws.
|
|
31
|
+
* - `describe` returns key names and metadata only, so the mismatch check
|
|
32
|
+
* has nothing value-shaped to compare even by accident.
|
|
33
|
+
*
|
|
34
|
+
* Store adapters are per-provider (#1830 is the k8s row); core defines only
|
|
35
|
+
* the seam.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* A single-use, opaque handle to generated secret material. The plaintext is
|
|
39
|
+
* not a property of this object — it lives in a module-private WeakMap — so
|
|
40
|
+
* spreading, enumerating, stringifying, or logging the handle yields only a
|
|
41
|
+
* redaction marker. A store adapter redeems it with
|
|
42
|
+
* {@link consumeSecretMaterial} at the moment it writes; nothing else can.
|
|
43
|
+
*/
|
|
44
|
+
export declare class SecretMaterial {
|
|
45
|
+
private constructor();
|
|
46
|
+
/** Wrap plaintext in an opaque handle. Call inside a generator only. */
|
|
47
|
+
static mint(plaintext: string): SecretMaterial;
|
|
48
|
+
toString(): string;
|
|
49
|
+
toJSON(): string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Redeem a {@link SecretMaterial} handle for its plaintext — exactly once.
|
|
53
|
+
* For store adapters only, at the write to the backing store. Throws if the
|
|
54
|
+
* handle was already consumed (or was never minted here): material flows to
|
|
55
|
+
* the store exactly once and is retained nowhere.
|
|
56
|
+
*/
|
|
57
|
+
export declare function consumeSecretMaterial(material: SecretMaterial): string;
|
|
58
|
+
/**
|
|
59
|
+
* Produces the material for one key of a secret being minted. Called by the
|
|
60
|
+
* store adapter (never by the engine) once per declared key, at create time —
|
|
61
|
+
* generation is apply-time I/O, never synthesis.
|
|
62
|
+
*/
|
|
63
|
+
export type SecretMaterialGenerator = (key: string) => SecretMaterial | Promise<SecretMaterial>;
|
|
64
|
+
/** 32 bytes from the CSPRNG, base64url — the default mint. */
|
|
65
|
+
export declare const defaultSecretMaterialGenerator: SecretMaterialGenerator;
|
|
66
|
+
/** What `describe` reports about an existing secret: key NAMES and metadata. Never values. */
|
|
67
|
+
export interface SecretStoreDescription {
|
|
68
|
+
/** The key names present in the stored secret. */
|
|
69
|
+
readonly keys: readonly string[];
|
|
70
|
+
/** Store metadata (e.g. k8s labels/annotations the provider surfaces). */
|
|
71
|
+
readonly metadata?: Readonly<Record<string, string>>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A provider's view of one secret store — the seam #1830 (k8s) and future
|
|
75
|
+
* provider rows implement. `create` receives the generator and consumes each
|
|
76
|
+
* key's material as it writes; no method returns material.
|
|
77
|
+
*/
|
|
78
|
+
export interface SecretStoreAdapter {
|
|
79
|
+
/** Whether a secret of this name exists in the store. */
|
|
80
|
+
exists(name: string): Promise<boolean>;
|
|
81
|
+
/** Key names and metadata of an existing secret. Never values. */
|
|
82
|
+
describe(name: string): Promise<SecretStoreDescription>;
|
|
83
|
+
/**
|
|
84
|
+
* Create the secret, minting material for each declared key via
|
|
85
|
+
* `generate` and writing it straight to the store. Returns nothing:
|
|
86
|
+
* material must not travel back through this seam.
|
|
87
|
+
*/
|
|
88
|
+
create(name: string, keys: readonly string[], generate: SecretMaterialGenerator): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
/** The declared contract to ensure — names and keys only, never material. */
|
|
91
|
+
export interface EnsureSecretSpec {
|
|
92
|
+
/** The secret's name as the store knows it. */
|
|
93
|
+
readonly name: string;
|
|
94
|
+
/** The declared key-set. Creation mints one value per key; verification compares names. */
|
|
95
|
+
readonly keys: readonly string[];
|
|
96
|
+
/** Declared metadata an existing secret must carry (compared per key; mismatches are reported by KEY). */
|
|
97
|
+
readonly metadata?: Readonly<Record<string, string>>;
|
|
98
|
+
}
|
|
99
|
+
/** What `ensureSecretMaterialization` did. No field can carry material. */
|
|
100
|
+
export interface EnsureSecretOutcome {
|
|
101
|
+
/** `created` = minted now (first materialization); `present` = existed and matched the contract (no write). */
|
|
102
|
+
readonly outcome: "created" | "present";
|
|
103
|
+
/** The secret's name. */
|
|
104
|
+
readonly name: string;
|
|
105
|
+
/** The declared key names the contract was checked (or minted) against. */
|
|
106
|
+
readonly keys: readonly string[];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The loud failure: an existing secret does not match its declared contract.
|
|
110
|
+
* `mismatches` names what differed — key names and metadata keys only.
|
|
111
|
+
* Constructing one with anything value-shaped is the reviewer's tripwire;
|
|
112
|
+
* nothing in this module can, because nothing in this module holds a value.
|
|
113
|
+
*/
|
|
114
|
+
export declare class SecretContractMismatchError extends Error {
|
|
115
|
+
/** The secret's name. */
|
|
116
|
+
readonly secretName: string;
|
|
117
|
+
/** Human-readable mismatch descriptions, naming keys — never values. */
|
|
118
|
+
readonly mismatches: readonly string[];
|
|
119
|
+
constructor(
|
|
120
|
+
/** The secret's name. */
|
|
121
|
+
secretName: string,
|
|
122
|
+
/** Human-readable mismatch descriptions, naming keys — never values. */
|
|
123
|
+
mismatches: readonly string[]);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Ensure a `generated-once` secret exists and matches its declared contract.
|
|
127
|
+
* Read-then-write:
|
|
128
|
+
*
|
|
129
|
+
* - Absent: `store.create(name, keys, generate)` — one mint, then done.
|
|
130
|
+
* - Present and matching: no write of any kind; returns `present`.
|
|
131
|
+
* - Present and mismatching: throws {@link SecretContractMismatchError}
|
|
132
|
+
* naming the missing/unexpected key names and mismatched metadata keys.
|
|
133
|
+
*
|
|
134
|
+
* The engine never calls `generate` itself and never sees what the adapter
|
|
135
|
+
* writes; its return value carries names only.
|
|
136
|
+
*/
|
|
137
|
+
export declare function ensureSecretMaterialization(store: SecretStoreAdapter, spec: EnsureSecretSpec, generate?: SecretMaterialGenerator): Promise<EnsureSecretOutcome>;
|
|
138
|
+
//# sourceMappingURL=secret-materialization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-materialization.d.ts","sourceRoot":"","sources":["../src/secret-materialization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAWH;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO;IAEP,wEAAwE;IACxE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc;IAM9C,QAAQ,IAAI,MAAM;IAIlB,MAAM,IAAI,MAAM;CAQjB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAStE;AAED;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAEhG,8DAA8D;AAC9D,eAAO,MAAM,8BAA8B,EAAE,uBACe,CAAC;AAI7D,8FAA8F;AAC9F,MAAM,WAAW,sBAAsB;IACrC,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACxD;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjG;AAID,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,0GAA0G;IAC1G,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,+GAA+G;IAC/G,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IACxC,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IAElD,yBAAyB;aACT,UAAU,EAAE,MAAM;IAClC,wEAAwE;aACxD,UAAU,EAAE,SAAS,MAAM,EAAE;;IAH7C,yBAAyB;IACT,UAAU,EAAE,MAAM;IAClC,wEAAwE;IACxD,UAAU,EAAE,SAAS,MAAM,EAAE;CAQhD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,kBAAkB,EACzB,IAAI,EAAE,gBAAgB,EACtB,QAAQ,GAAE,uBAAwD,GACjE,OAAO,CAAC,mBAAmB,CAAC,CA0C9B"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret provenance vocabulary (chant #1828, epic #1365).
|
|
3
|
+
*
|
|
4
|
+
* A secret's PROVENANCE is where its value comes from — never what the value
|
|
5
|
+
* is. chant's constitutional line on secrets: no code path may hold, log,
|
|
6
|
+
* hash, or compare a secret value. This module makes that structural: the
|
|
7
|
+
* declaration types have no field that could carry material, the factory
|
|
8
|
+
* rejects material-shaped fields at both the type level (`never` fields) and
|
|
9
|
+
* at runtime (own-property check, naming only the offending KEY), and
|
|
10
|
+
* "mismatch" anywhere downstream means presence, declared key-set, and
|
|
11
|
+
* metadata — never a value or a value-derived hash (#1365 decision 6).
|
|
12
|
+
*
|
|
13
|
+
* The closed kind set:
|
|
14
|
+
*
|
|
15
|
+
* - `referenced` — the value exists out of band (a human or an external
|
|
16
|
+
* process put it where consumers read it). chant records only that the
|
|
17
|
+
* estate depends on it, which is what lets the consumed-but-unproduced
|
|
18
|
+
* check (#1382) ship as an error instead of a guess.
|
|
19
|
+
* - `from-provider` — a declared provider binding materializes it (the
|
|
20
|
+
* operator/CRD seam; `K8s::Infisical::InfisicalSecret` from #1321 is the
|
|
21
|
+
* exemplar). The declaration POINTS at that binding, it does not re-model
|
|
22
|
+
* it.
|
|
23
|
+
* - `generated-once` — minted on first materialization, then never
|
|
24
|
+
* regenerated (present means done). The declaration carries contract flags
|
|
25
|
+
* only — e.g. the declared key-set — never mint parameters holding
|
|
26
|
+
* material. `generated-once` secrets never enter the prunable set (#1365
|
|
27
|
+
* decision 5).
|
|
28
|
+
* - `committed-encrypted` — sops-style ciphertext committed in the repo,
|
|
29
|
+
* decrypted by the delivery system (Flux) straight into the target. The
|
|
30
|
+
* declaration records a repo-relative PATH to the ciphertext, never the
|
|
31
|
+
* bytes: the factory is pure and touches no filesystem, so it still folds
|
|
32
|
+
* under `--sandbox`. The bytes are read at `buildRoots()` — the one
|
|
33
|
+
* sanctioned impure seam — and emitted as a sidecar file, never as a
|
|
34
|
+
* document in the primary output. See
|
|
35
|
+
* `docs/design/committed-encrypted-sops-provenance.md`.
|
|
36
|
+
*
|
|
37
|
+
* Declarations are serializer-neutral: discovery collects them like any
|
|
38
|
+
* entity (they are Declarables), but `partitionByLexicon` (../build.ts)
|
|
39
|
+
* excludes them from every serializer partition, so no lexicon ever emits
|
|
40
|
+
* them. They are data that lint rules and lexicons READ (via
|
|
41
|
+
* {@link collectSecretDeclarations}), not output.
|
|
42
|
+
*/
|
|
43
|
+
import { type Declarable } from "./declarable.js";
|
|
44
|
+
/** The closed union of secret origins. */
|
|
45
|
+
export type SecretProvenance = "referenced" | "from-provider" | "generated-once" | "committed-encrypted";
|
|
46
|
+
/** Every provenance kind, for exhaustiveness checks. */
|
|
47
|
+
export declare const SECRET_PROVENANCE_KINDS: readonly SecretProvenance[];
|
|
48
|
+
/**
|
|
49
|
+
* Encryption tools a {@link CommittedEncryptedSecretDeclaration} understands.
|
|
50
|
+
* A closed union with one member, not a free string: a second tool later is a
|
|
51
|
+
* deliberate widening with a detection rule attached, not an unvalidated
|
|
52
|
+
* string that silently means nothing.
|
|
53
|
+
*/
|
|
54
|
+
export type SecretEncryption = "sops";
|
|
55
|
+
/** Every encryption tool, for exhaustiveness checks. */
|
|
56
|
+
export declare const SECRET_ENCRYPTION_TOOLS: readonly SecretEncryption[];
|
|
57
|
+
/** Marker symbol identifying a secret provenance declaration. `Symbol.for` so
|
|
58
|
+
* it survives the entity-wire codec (../discovery/entity-wire-codec.ts). */
|
|
59
|
+
export declare const SECRET_DECLARATION_MARKER: unique symbol;
|
|
60
|
+
/** The `entityType` every secret declaration carries. */
|
|
61
|
+
export declare const SECRET_DECLARATION_ENTITY_TYPE = "Chant::SecretProvenance";
|
|
62
|
+
/**
|
|
63
|
+
* Points a `from-provider` declaration at the provider binding that
|
|
64
|
+
* materializes the secret — the CRD seam, not a re-model of it. The binding
|
|
65
|
+
* itself is an ordinary declarable in its own lexicon (e.g. an
|
|
66
|
+
* `InfisicalSecret` instance, #1321); this ref names it so lint can resolve
|
|
67
|
+
* the pair without core depending on any lexicon.
|
|
68
|
+
*/
|
|
69
|
+
export interface SecretProviderRef {
|
|
70
|
+
/** Entity name (export name) of the provider binding declarable in this project. */
|
|
71
|
+
readonly binding: string;
|
|
72
|
+
/**
|
|
73
|
+
* Expected `entityType` of the binding (e.g.
|
|
74
|
+
* `"K8s::Infisical::InfisicalSecret"`). Optional; when present, lint can
|
|
75
|
+
* verify the named binding is actually the kind of seam the declaration
|
|
76
|
+
* claims.
|
|
77
|
+
*/
|
|
78
|
+
readonly entityType?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Fields that would carry secret material, forbidden by construction. Typed
|
|
82
|
+
* as `never` on every factory input so they fail to compile even when the
|
|
83
|
+
* input object was widened or spread (plain excess-property checks only catch
|
|
84
|
+
* object literals). The runtime check in {@link declareSecret} is the same
|
|
85
|
+
* list, for untyped callers.
|
|
86
|
+
*/
|
|
87
|
+
interface NoSecretMaterial {
|
|
88
|
+
readonly value?: never;
|
|
89
|
+
readonly data?: never;
|
|
90
|
+
readonly stringData?: never;
|
|
91
|
+
readonly material?: never;
|
|
92
|
+
readonly plaintext?: never;
|
|
93
|
+
readonly ciphertext?: never;
|
|
94
|
+
}
|
|
95
|
+
/** Fields shared by every secret declaration. */
|
|
96
|
+
interface SecretDeclarationBase extends Declarable {
|
|
97
|
+
readonly [SECRET_DECLARATION_MARKER]: true;
|
|
98
|
+
readonly lexicon: "chant";
|
|
99
|
+
readonly entityType: typeof SECRET_DECLARATION_ENTITY_TYPE;
|
|
100
|
+
/** The secret's name as consumers know it (e.g. the k8s Secret name). */
|
|
101
|
+
readonly name: string;
|
|
102
|
+
/** Which of the closed kind set this declaration is. */
|
|
103
|
+
readonly provenance: SecretProvenance;
|
|
104
|
+
}
|
|
105
|
+
/** A secret whose value exists out of band. */
|
|
106
|
+
export interface ReferencedSecretDeclaration extends SecretDeclarationBase {
|
|
107
|
+
readonly provenance: "referenced";
|
|
108
|
+
/** Where consumers find it — free-form (a namespace, a vault path, a doc link). */
|
|
109
|
+
readonly scope?: string;
|
|
110
|
+
}
|
|
111
|
+
/** A secret a declared provider binding materializes. */
|
|
112
|
+
export interface FromProviderSecretDeclaration extends SecretDeclarationBase {
|
|
113
|
+
readonly provenance: "from-provider";
|
|
114
|
+
readonly provider: SecretProviderRef;
|
|
115
|
+
}
|
|
116
|
+
/** A secret minted on first materialization and never regenerated. */
|
|
117
|
+
export interface GeneratedOnceSecretDeclaration extends SecretDeclarationBase {
|
|
118
|
+
readonly provenance: "generated-once";
|
|
119
|
+
/**
|
|
120
|
+
* The declared key-set of the materialized secret. This is the contract a
|
|
121
|
+
* materializer (#1830) checks for mismatch — presence and keys, never
|
|
122
|
+
* values.
|
|
123
|
+
*/
|
|
124
|
+
readonly keys?: readonly string[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A secret whose ciphertext is committed to the repo and decrypted by the
|
|
128
|
+
* delivery system on the way into the target.
|
|
129
|
+
*
|
|
130
|
+
* The declaration is a POINTER: `file` is a repo-relative path, and nothing
|
|
131
|
+
* here carries bytes. That is what keeps the factory pure — the ciphertext is
|
|
132
|
+
* read at `buildRoots()` and emitted as a sidecar, never inlined into the
|
|
133
|
+
* primary output an applier reads.
|
|
134
|
+
*/
|
|
135
|
+
export interface CommittedEncryptedSecretDeclaration extends SecretDeclarationBase {
|
|
136
|
+
readonly provenance: "committed-encrypted";
|
|
137
|
+
/** Repo-relative path to the committed ciphertext file. */
|
|
138
|
+
readonly file: string;
|
|
139
|
+
/** Encryption tool. Defaults to `"sops"` when omitted. */
|
|
140
|
+
readonly encryption: SecretEncryption;
|
|
141
|
+
/**
|
|
142
|
+
* Public recipient identifiers — age recipients or PGP fingerprints. Public
|
|
143
|
+
* by definition, which is the opposite of material; a private key here is
|
|
144
|
+
* refused by the factory.
|
|
145
|
+
*/
|
|
146
|
+
readonly recipients?: readonly string[];
|
|
147
|
+
/**
|
|
148
|
+
* The declared key-set of the decrypted Secret — the same contract meaning
|
|
149
|
+
* as {@link GeneratedOnceSecretDeclaration.keys}: presence and key names,
|
|
150
|
+
* never values. SOPS leaves key NAMES cleartext, so this is checkable
|
|
151
|
+
* against the file itself.
|
|
152
|
+
*/
|
|
153
|
+
readonly keys?: readonly string[];
|
|
154
|
+
}
|
|
155
|
+
/** A secret provenance declaration — the discriminant is `provenance`. */
|
|
156
|
+
export type SecretDeclaration = ReferencedSecretDeclaration | FromProviderSecretDeclaration | GeneratedOnceSecretDeclaration | CommittedEncryptedSecretDeclaration;
|
|
157
|
+
/** Narrow a declaration to the committed-encrypted kind. */
|
|
158
|
+
export declare function isCommittedEncryptedSecret(decl: SecretDeclaration): decl is CommittedEncryptedSecretDeclaration;
|
|
159
|
+
/** Factory input for a `referenced` secret. */
|
|
160
|
+
export interface ReferencedSecretInput extends NoSecretMaterial {
|
|
161
|
+
readonly name: string;
|
|
162
|
+
readonly provenance: "referenced";
|
|
163
|
+
readonly scope?: string;
|
|
164
|
+
}
|
|
165
|
+
/** Factory input for a `from-provider` secret. */
|
|
166
|
+
export interface FromProviderSecretInput extends NoSecretMaterial {
|
|
167
|
+
readonly name: string;
|
|
168
|
+
readonly provenance: "from-provider";
|
|
169
|
+
readonly provider: SecretProviderRef;
|
|
170
|
+
}
|
|
171
|
+
/** Factory input for a `generated-once` secret. */
|
|
172
|
+
export interface GeneratedOnceSecretInput extends NoSecretMaterial {
|
|
173
|
+
readonly name: string;
|
|
174
|
+
readonly provenance: "generated-once";
|
|
175
|
+
readonly keys?: readonly string[];
|
|
176
|
+
}
|
|
177
|
+
/** Factory input for a `committed-encrypted` secret. */
|
|
178
|
+
export interface CommittedEncryptedSecretInput extends NoSecretMaterial {
|
|
179
|
+
readonly name: string;
|
|
180
|
+
readonly provenance: "committed-encrypted";
|
|
181
|
+
/**
|
|
182
|
+
* Repo-relative path to the committed ciphertext file — `file`, never
|
|
183
|
+
* `ciphertext`: the declaration points at bytes, it does not carry them,
|
|
184
|
+
* and `ciphertext` is a forbidden material field.
|
|
185
|
+
*/
|
|
186
|
+
readonly file: string;
|
|
187
|
+
/** Encryption tool. Closed union; `"sops"` is its only member today. */
|
|
188
|
+
readonly encryption?: SecretEncryption;
|
|
189
|
+
/** Public recipient identifiers — age recipients or PGP fingerprints. */
|
|
190
|
+
readonly recipients?: readonly string[];
|
|
191
|
+
/** The declared key-set of the decrypted Secret. Names only, never values. */
|
|
192
|
+
readonly keys?: readonly string[];
|
|
193
|
+
}
|
|
194
|
+
export type SecretDeclarationInput = ReferencedSecretInput | FromProviderSecretInput | GeneratedOnceSecretInput | CommittedEncryptedSecretInput;
|
|
195
|
+
/**
|
|
196
|
+
* Declare a secret's provenance. The returned object is a locked Declarable:
|
|
197
|
+
* discovery collects it like any entity, `chant list` shows it, lint and
|
|
198
|
+
* lexicons read it — and no serializer ever emits it.
|
|
199
|
+
*
|
|
200
|
+
* Only the fields the kind defines are copied onto the declaration; anything
|
|
201
|
+
* else on the input — in particular anything that could carry material — is
|
|
202
|
+
* either a compile error ({@link NoSecretMaterial}) or a thrown error here.
|
|
203
|
+
* The thrown message names the offending KEY only, never its value.
|
|
204
|
+
*/
|
|
205
|
+
export declare function declareSecret(input: ReferencedSecretInput): ReferencedSecretDeclaration;
|
|
206
|
+
export declare function declareSecret(input: FromProviderSecretInput): FromProviderSecretDeclaration;
|
|
207
|
+
export declare function declareSecret(input: GeneratedOnceSecretInput): GeneratedOnceSecretDeclaration;
|
|
208
|
+
export declare function declareSecret(input: CommittedEncryptedSecretInput): CommittedEncryptedSecretDeclaration;
|
|
209
|
+
/** Type guard for a secret provenance declaration. */
|
|
210
|
+
export declare function isSecretDeclaration(value: unknown): value is SecretDeclaration;
|
|
211
|
+
/**
|
|
212
|
+
* Extract the secret declarations from a discovered entity map — the read
|
|
213
|
+
* surface for lint rules (#1382) and lexicon materializers (#1830). Keyed by
|
|
214
|
+
* entity name (export name), the same key `DiscoveryResult.entities` uses.
|
|
215
|
+
*/
|
|
216
|
+
export declare function collectSecretDeclarations(entities: ReadonlyMap<string, Declarable>): Map<string, SecretDeclaration>;
|
|
217
|
+
export {};
|
|
218
|
+
//# sourceMappingURL=secret-provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-provenance.d.ts","sourceRoot":"","sources":["../src/secret-provenance.ts"],"names":[],"mappings":"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"}
|
package/dist/serializer.d.ts
CHANGED
|
@@ -18,6 +18,17 @@ export interface SerializeContext {
|
|
|
18
18
|
* ad-hoc builds (e.g. context tools) that pass no config.
|
|
19
19
|
*/
|
|
20
20
|
config?: Record<string, unknown>;
|
|
21
|
+
/**
|
|
22
|
+
* Effect receipts (#1832, epic #1703) declared in this lexicon's partition.
|
|
23
|
+
* Withheld from the `entities` map by the build: receipts are observe-only
|
|
24
|
+
* to the generic apply path, and the serialized output is what feeds
|
|
25
|
+
* appliers, so a receipt must never enter the apply-bound document. A
|
|
26
|
+
* serializer that wants to render receipts for visibility (#1835) reads
|
|
27
|
+
* them here and puts them anywhere BUT the section an applier writes from;
|
|
28
|
+
* a serializer that ignores this field emits nothing for them, which is the
|
|
29
|
+
* safe default.
|
|
30
|
+
*/
|
|
31
|
+
receipts?: ReadonlyMap<string, Declarable>;
|
|
21
32
|
}
|
|
22
33
|
/**
|
|
23
34
|
* Result of serialization that may include additional files (e.g. nested stack templates).
|
package/dist/serializer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEjC;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEtC;;;;;OAKG;IACH,SAAS,CACP,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACjC,OAAO,CAAC,EAAE,aAAa,EAAE,EACzB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,GAAG,gBAAgB,CAAC;IAE7B;;;;;OAKG;IACH,iBAAiB,CAAC,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC;CACpD"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@intentius/chant/testing` (#1224) — the live-stack test harness.
|
|
3
|
+
*
|
|
4
|
+
* A vitest suite deploys a real instance of its project once, asserts against
|
|
5
|
+
* it, and tears it down — emulator-locally on a dev machine, real-cloud in CI,
|
|
6
|
+
* with the same suite text. One call composes machinery that already exists:
|
|
7
|
+
*
|
|
8
|
+
* - **build** — the same programmatic path `chant build` takes: config
|
|
9
|
+
* resolution (`buildParams` + the ownership marker) mirrored from the CLI,
|
|
10
|
+
* then `build()` over the project's own serializers.
|
|
11
|
+
* - **apply** — an additive `nativeApply` per built lexicon output, run
|
|
12
|
+
* in-process through the local Op executor (`runOpLocally`). `deleteMode`
|
|
13
|
+
* is `"never"`: a test deploy creates and updates, nothing else.
|
|
14
|
+
* - **destroy** — #1222's marker-scoped teardown (`executeTeardown`), called
|
|
15
|
+
* in-process for exactly this suite's environment. Stateless by design:
|
|
16
|
+
* a crashed suite's environment is recovered by calling destroy again (or
|
|
17
|
+
* `chant lifecycle teardown <env> --yes`).
|
|
18
|
+
*
|
|
19
|
+
* ## Isolation
|
|
20
|
+
*
|
|
21
|
+
* Every deploy targets its own environment: `test-<suite>-<nonce>` by default
|
|
22
|
+
* ({@link testEnvName}), so parallel CI jobs never collide. The environment
|
|
23
|
+
* is the teardown key — everything the deploy stamps carries the ownership
|
|
24
|
+
* marker `{ stack, env }`, and `destroy()` selects on that identity and
|
|
25
|
+
* nothing else. A project that declares `environments` must legalize the
|
|
26
|
+
* dynamic names with a pattern entry (#1221):
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* environments: ["dev", "prod", { name: "test-*", endpoint: "http://localhost:4566" }]
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* ## Emulators
|
|
33
|
+
*
|
|
34
|
+
* The harness is emulator-aware the same way `--live` reads are (#1166): the
|
|
35
|
+
* target environment's declared `endpoint` is injected into each lexicon's
|
|
36
|
+
* ambient endpoint variable (`AWS_ENDPOINT_URL`, …) for the apply and the
|
|
37
|
+
* teardown — unless the variable is already set. Ambient always wins, so the
|
|
38
|
+
* env vars `chant emulator up --json` reports (#920) take precedence when
|
|
39
|
+
* exported, and a CI job pointing the identical suite at a real account just
|
|
40
|
+
* leaves both unset.
|
|
41
|
+
*/
|
|
42
|
+
import type { Declarable } from "./declarable.js";
|
|
43
|
+
import type { SerializerResult } from "./serializer.js";
|
|
44
|
+
import { type BuildParamValue } from "./build-params.js";
|
|
45
|
+
import type { LexiconPlugin } from "./lexicon.js";
|
|
46
|
+
import { type ActivityFn, type ActivityProfile } from "./op/activity-registry.js";
|
|
47
|
+
import { type TeardownReport } from "./lifecycle/teardown.js";
|
|
48
|
+
export interface DeployStackOptions {
|
|
49
|
+
/** The chant project directory (where the infra source lives). */
|
|
50
|
+
dir: string;
|
|
51
|
+
/**
|
|
52
|
+
* Explicit environment name. Overrides the default `test-<suite>-<nonce>`
|
|
53
|
+
* derivation — for a shared long-lived test environment, or a test that
|
|
54
|
+
* needs a deterministic name. Must be legal for the project's declared
|
|
55
|
+
* `environments`, exactly as `--env` would be.
|
|
56
|
+
*/
|
|
57
|
+
env?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Suite name folded into the default environment name. Defaults to the
|
|
60
|
+
* project directory's basename.
|
|
61
|
+
*/
|
|
62
|
+
suite?: string;
|
|
63
|
+
/** Build parameters, exactly as `--param name=value` flags would supply them. */
|
|
64
|
+
params?: Record<string, BuildParamValue>;
|
|
65
|
+
/**
|
|
66
|
+
* Loaded lexicon plugins. Defaults to loading the project's own declared/
|
|
67
|
+
* detected lexicons — pass this only to substitute test doubles.
|
|
68
|
+
*/
|
|
69
|
+
plugins?: LexiconPlugin[];
|
|
70
|
+
/** Activity implementations for the apply. Defaults to the real registry. */
|
|
71
|
+
activities?: Map<string, ActivityFn>;
|
|
72
|
+
/** Activity profiles (timeouts/retries). Defaults to the lexicon-declared table. */
|
|
73
|
+
profiles?: Record<string, ActivityProfile>;
|
|
74
|
+
/**
|
|
75
|
+
* Extra lexicon-name → `nativeApply` target entries, merged over the
|
|
76
|
+
* built-in map (aws → cloudformation, k8s → kubectl, azure → arm,
|
|
77
|
+
* gcp → gcp, fly → fly). A seam for tests and out-of-tree lexicons.
|
|
78
|
+
*/
|
|
79
|
+
applyTargets?: Record<string, string>;
|
|
80
|
+
}
|
|
81
|
+
/** The handle a suite holds between `beforeAll` and `afterAll`. */
|
|
82
|
+
export interface DeployedStack {
|
|
83
|
+
/** The built outputs, keyed by lexicon — what was deployed. */
|
|
84
|
+
outputs: Map<string, string | SerializerResult>;
|
|
85
|
+
/** The discovered entities, keyed by name. */
|
|
86
|
+
entities: Map<string, Declarable>;
|
|
87
|
+
/** The environment this deploy targeted — the teardown key. */
|
|
88
|
+
env: string;
|
|
89
|
+
/**
|
|
90
|
+
* Tear down everything carrying this suite's marker `{ stack, env }`.
|
|
91
|
+
* Throws {@link TeardownIncompleteError} when any candidate failed to
|
|
92
|
+
* delete or the plan had holes — an environment that cannot be called
|
|
93
|
+
* clean is a test failure, never a silent leak. Safe to call again:
|
|
94
|
+
* teardown is stateless, and a second call over a clean environment
|
|
95
|
+
* plans nothing.
|
|
96
|
+
*/
|
|
97
|
+
destroy(): Promise<TeardownReport>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Thrown by {@link DeployedStack.destroy} when the environment cannot be
|
|
101
|
+
* called clean: candidates still `failed` after the retry pass, or the plan
|
|
102
|
+
* had holes (#1089 — parts of the estate could not be read, so "nothing
|
|
103
|
+
* left" would be a claim about what was readable, not about the environment).
|
|
104
|
+
* Carries the full report for diagnosis.
|
|
105
|
+
*/
|
|
106
|
+
export declare class TeardownIncompleteError extends Error {
|
|
107
|
+
readonly report: TeardownReport;
|
|
108
|
+
constructor(report: TeardownReport);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The default environment name for one suite run: `test-<suite>-<nonce>`.
|
|
112
|
+
* The `test-` prefix is what a project's `"test-*"` pattern entry (#1221)
|
|
113
|
+
* legalizes; the nonce keeps parallel CI jobs of the same suite apart.
|
|
114
|
+
*/
|
|
115
|
+
export declare function testEnvName(suite: string): string;
|
|
116
|
+
/**
|
|
117
|
+
* Deploy a live instance of the project in `dir` for one test suite.
|
|
118
|
+
*
|
|
119
|
+
* Build (the CLI's own config resolution: `buildParams`, ownership marker,
|
|
120
|
+
* build roots) + additive apply (one `nativeApply` per built output with a
|
|
121
|
+
* native mechanism, via the local Op executor). Returns the handle the suite
|
|
122
|
+
* holds: outputs, entities, the environment name, and `destroy`.
|
|
123
|
+
*
|
|
124
|
+
* The ownership marker stamped on every resource is `{ stack: ownership.stack,
|
|
125
|
+
* env: <this deploy's environment> }` — the marker env always follows the
|
|
126
|
+
* suite environment, whatever `ownership.env` in config says, because the
|
|
127
|
+
* marker is the only thing `destroy()` selects on. A project with no
|
|
128
|
+
* `ownership.stack` is refused up front: a deploy that stamps nothing is a
|
|
129
|
+
* deploy nothing can sweep.
|
|
130
|
+
*
|
|
131
|
+
* Failures are thrown, never returned: build errors, unresolved parameters,
|
|
132
|
+
* an illegal environment name, and a failed apply (the local executor's
|
|
133
|
+
* `OpRunFailure`) all reject the returned promise.
|
|
134
|
+
*/
|
|
135
|
+
export declare function deployStack(options: DeployStackOptions): Promise<DeployedStack>;
|
|
136
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAMrD,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAI1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/C,OAAO,EAAgC,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE7G,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAgB5E,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC;IAChD,8CAA8C;IAC9C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;CACpC;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,MAAM,EAAE,cAAc;gBAAtB,MAAM,EAAE,cAAc;CAkBnD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUjD;AA8BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAkHrF"}
|
package/dist/yaml.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA0BH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAgH/D;AAMD,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASlE;AAiFD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,WAAW,CA8Eb;AA0GD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,WAAW,CAqGb;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA0BH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAgH/D;AAMD,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASlE;AAiFD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,WAAW,CA8Eb;AA0GD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,WAAW,CAqGb;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAwBlD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.0",
|
|
4
4
|
"description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -64,6 +64,11 @@
|
|
|
64
64
|
"types": "./dist/components/index.d.ts",
|
|
65
65
|
"default": "./src/components/index.ts"
|
|
66
66
|
},
|
|
67
|
+
"./testing": {
|
|
68
|
+
"development": "./src/testing.ts",
|
|
69
|
+
"types": "./dist/testing.d.ts",
|
|
70
|
+
"default": "./src/testing.ts"
|
|
71
|
+
},
|
|
67
72
|
"./*": {
|
|
68
73
|
"development": "./src/*.ts",
|
|
69
74
|
"types": "./dist/*.d.ts",
|
|
@@ -86,5 +91,8 @@
|
|
|
86
91
|
"devDependencies": {
|
|
87
92
|
"@cdktf/hcl2json": "^0.21.0",
|
|
88
93
|
"ajv": "^8.20.0"
|
|
94
|
+
},
|
|
95
|
+
"overrides": {
|
|
96
|
+
"esbuild": "^0.28.1"
|
|
89
97
|
}
|
|
90
98
|
}
|
package/src/audit/core.test.ts
CHANGED
|
@@ -187,4 +187,61 @@ describe("auditFiles", () => {
|
|
|
187
187
|
});
|
|
188
188
|
expect(findings.map((f) => f.checkId)).toEqual(["OK001"]);
|
|
189
189
|
});
|
|
190
|
+
|
|
191
|
+
test("parse-to-graph: an injected entities parser lets entity-reading checks fire per file (#1567)", async () => {
|
|
192
|
+
const entityCheck: PostSynthCheck = {
|
|
193
|
+
id: "ENT001",
|
|
194
|
+
description: "reads ctx.entities, not ctx.outputs",
|
|
195
|
+
check: (ctx) =>
|
|
196
|
+
[...ctx.entities.keys()].map((name) => ({ checkId: "ENT001", severity: "warning" as const, message: `saw ${name}`, entity: name })),
|
|
197
|
+
};
|
|
198
|
+
const findings = await auditFiles(
|
|
199
|
+
[
|
|
200
|
+
{ path: "a.yaml", content: "one", lexicon: "custom" },
|
|
201
|
+
{ path: "b.yaml", content: "two", lexicon: "custom" },
|
|
202
|
+
],
|
|
203
|
+
{
|
|
204
|
+
checksProvider: async () => [entityCheck],
|
|
205
|
+
entitiesProvider: async () => (content) => new Map([[content, { entityType: "T::X" } as never]]),
|
|
206
|
+
},
|
|
207
|
+
);
|
|
208
|
+
expect(findings.map((f) => `${f.file}:${f.entity}`).sort()).toEqual(["a.yaml:one", "b.yaml:two"]);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("parse-to-graph merge: the same entity name in two files keeps both — a duplicate check sees the collision cross-file", async () => {
|
|
212
|
+
const dupCheck: PostSynthCheck = {
|
|
213
|
+
id: "DUP001",
|
|
214
|
+
description: "fires when more than one entity is present",
|
|
215
|
+
check: (ctx) => (ctx.entities.size > 1 ? [{ checkId: "DUP001", severity: "error" as const, message: "name declared twice" }] : []),
|
|
216
|
+
};
|
|
217
|
+
const findings = await auditFiles(
|
|
218
|
+
[
|
|
219
|
+
{ path: "a.yaml", content: "x", lexicon: "custom" },
|
|
220
|
+
{ path: "b.yaml", content: "y", lexicon: "custom" },
|
|
221
|
+
],
|
|
222
|
+
{
|
|
223
|
+
checksProvider: async () => [dupCheck],
|
|
224
|
+
// both files declare the entity name "dev" — the merged pass must keep both
|
|
225
|
+
entitiesProvider: async () => () => new Map([["dev", { entityType: "T::X" } as never]]),
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
const dup = findings.find((f) => f.checkId === "DUP001");
|
|
229
|
+
expect(dup).toBeDefined();
|
|
230
|
+
expect(dup!.file).toBe(CROSS_FILE);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("an entities parser that throws contributes no entities and does not abort the audit", async () => {
|
|
234
|
+
const entityCheck: PostSynthCheck = {
|
|
235
|
+
id: "ENT002",
|
|
236
|
+
description: "counts entities",
|
|
237
|
+
check: (ctx) => (ctx.entities.size > 0 ? [{ checkId: "ENT002", severity: "warning" as const, message: "saw entities" }] : []),
|
|
238
|
+
};
|
|
239
|
+
const findings = await auditFiles([{ path: "a.yaml", content: "x", lexicon: "custom" }], {
|
|
240
|
+
checksProvider: async () => [entityCheck],
|
|
241
|
+
entitiesProvider: async () => () => {
|
|
242
|
+
throw new Error("unparseable");
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
expect(findings).toEqual([]);
|
|
246
|
+
});
|
|
190
247
|
});
|
package/src/audit/core.ts
CHANGED
|
Binary file
|
|
@@ -9,7 +9,7 @@ import { fileURLToPath } from "url";
|
|
|
9
9
|
* service content-detect all lexicons on Workers.
|
|
10
10
|
*/
|
|
11
11
|
const repoRoot = fileURLToPath(new URL("../../../../", import.meta.url));
|
|
12
|
-
const LEXICONS = ["k8s", "docker", "aws", "azure", "gcp", "helm"];
|
|
12
|
+
const LEXICONS = ["k8s", "docker", "aws", "azure", "gcp", "helm", "fountain"];
|
|
13
13
|
|
|
14
14
|
describe("detectTemplate modules are edge-bundle clean", () => {
|
|
15
15
|
test("importing every lexicon's /detect pulls in no typescript or plugin.ts", async () => {
|