@intentius/chant 0.41.20 → 0.44.1
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/build.d.ts +15 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-apply.d.ts +9 -0
- package/dist/cli/commands/carve-apply.d.ts.map +1 -1
- package/dist/cli/commands/carve-bridge.d.ts +7 -0
- package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts +7 -0
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/handlers/carve-apply.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/explain.d.ts +11 -0
- package/dist/cli/handlers/explain.d.ts.map +1 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +8 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +2 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/docs-rule-scanning.d.ts +11 -0
- package/dist/codegen/docs-rule-scanning.d.ts.map +1 -1
- package/dist/codegen/okf-lexicon.d.ts +36 -0
- package/dist/codegen/okf-lexicon.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +2 -1
- package/dist/codegen/package.d.ts.map +1 -1
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/verbs/sbom.d.ts +1 -1
- package/dist/components/verbs/sbom.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts +15 -4
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts +18 -6
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/deep-observation.d.ts +13 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/lexicon.d.ts +47 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/snapshot.d.ts.map +1 -1
- package/dist/okf.d.ts +57 -0
- package/dist/okf.d.ts.map +1 -0
- package/dist/terraform/__fixtures__/build-graph.d.ts +13 -0
- package/dist/terraform/__fixtures__/build-graph.d.ts.map +1 -0
- package/dist/terraform/adopt-state.d.ts +33 -1
- package/dist/terraform/adopt-state.d.ts.map +1 -1
- package/dist/terraform/aws-resources.d.ts.map +1 -1
- package/dist/terraform/bridge.d.ts +7 -1
- package/dist/terraform/bridge.d.ts.map +1 -1
- package/dist/terraform/carve.d.ts +12 -0
- package/dist/terraform/carve.d.ts.map +1 -1
- package/dist/terraform/excise.d.ts +31 -0
- package/dist/terraform/excise.d.ts.map +1 -0
- package/dist/terraform/graduate.d.ts +12 -0
- package/dist/terraform/graduate.d.ts.map +1 -1
- package/dist/terraform/graph.d.ts +35 -5
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/manifest.d.ts +89 -0
- package/dist/terraform/manifest.d.ts.map +1 -0
- package/dist/terraform/parse.d.ts +9 -4
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +4 -3
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/dist/terraform/types.d.ts +7 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/dist/terraform/unified-diff.d.ts +11 -0
- package/dist/terraform/unified-diff.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/__snapshots__/okf.test.ts.snap +381 -0
- package/src/audit/rules-doc.ts +1 -1
- package/src/build.test.ts +95 -0
- package/src/build.ts +46 -1
- package/src/cli/commands/build.ts +9 -1
- package/src/cli/commands/carve-apply.test.ts +94 -2
- package/src/cli/commands/carve-apply.ts +62 -11
- package/src/cli/commands/carve-bridge.test.ts +82 -4
- package/src/cli/commands/carve-bridge.ts +79 -11
- package/src/cli/commands/carve-emit-state.test.ts +110 -1
- package/src/cli/commands/carve-emit.ts +184 -8
- package/src/cli/commands/init.ts +1 -1
- package/src/cli/handlers/carve-apply.ts +1 -0
- package/src/cli/handlers/components.ts +4 -2
- package/src/cli/handlers/explain.test.ts +93 -0
- package/src/cli/handlers/explain.ts +60 -0
- package/src/cli/handlers/lifecycle.ts +16 -9
- package/src/cli/main.ts +21 -5
- package/src/cli/mcp/server.test.ts +17 -0
- package/src/cli/mcp/tools/explain.ts +15 -3
- package/src/cli/plugins.ts +17 -0
- package/src/cli/registry.ts +2 -0
- package/src/codegen/__snapshots__/okf-lexicon.test.ts.snap +170 -0
- package/src/codegen/docs-rule-scanning.ts +35 -14
- package/src/codegen/okf-lexicon.test.ts +248 -0
- package/src/codegen/okf-lexicon.ts +303 -0
- package/src/codegen/package.ts +29 -4
- package/src/components/config-defaults.test.ts +30 -0
- package/src/components/deploy-units.test.ts +13 -0
- package/src/components/deploy-units.ts +5 -0
- package/src/components/verbs/__fixtures__/grype-with-kev-epss.json +1 -0
- package/src/components/verbs/__fixtures__/trivy-with-kev-epss.json +631 -0
- package/src/components/verbs/exploitability-roundtrip.test.ts +190 -0
- package/src/components/verbs/sbom.ts +1 -1
- package/src/components/verbs/vuln-gate.test.ts +144 -1
- package/src/components/verbs/vuln-gate.ts +61 -10
- package/src/components/verbs/vuln-scan.test.ts +94 -0
- package/src/components/verbs/vuln-scan.ts +44 -9
- package/src/config.test.ts +21 -0
- package/src/config.ts +18 -0
- package/src/deep-observation.test.ts +19 -0
- package/src/deep-observation.ts +32 -13
- package/src/lexicon.ts +50 -0
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +10 -3
- package/src/lifecycle/snapshot.ts +5 -4
- package/src/okf.test.ts +169 -0
- package/src/okf.ts +308 -0
- package/src/terraform/__fixtures__/build-graph.ts +25 -0
- package/src/terraform/adopt-state.test.ts +34 -1
- package/src/terraform/adopt-state.ts +69 -2
- package/src/terraform/aws-resources.test.ts +52 -2
- package/src/terraform/aws-resources.ts +95 -4
- package/src/terraform/bridge.test.ts +38 -14
- package/src/terraform/bridge.ts +48 -14
- package/src/terraform/carve.test.ts +9 -7
- package/src/terraform/carve.ts +0 -0
- package/src/terraform/excise.test.ts +92 -0
- package/src/terraform/excise.ts +139 -0
- package/src/terraform/graduate.test.ts +73 -6
- package/src/terraform/graduate.ts +49 -0
- package/src/terraform/graph.test.ts +73 -10
- package/src/terraform/graph.ts +124 -47
- package/src/terraform/manifest.test.ts +105 -0
- package/src/terraform/manifest.ts +162 -0
- package/src/terraform/parse.test.ts +39 -1
- package/src/terraform/parse.ts +36 -9
- package/src/terraform/score.test.ts +8 -8
- package/src/terraform/state.test.ts +4 -4
- package/src/terraform/tier-map.ts +60 -8
- package/src/terraform/types.ts +7 -0
- package/src/terraform/unified-diff.test.ts +77 -0
- package/src/terraform/unified-diff.ts +146 -0
|
@@ -8,8 +8,14 @@
|
|
|
8
8
|
* advisor fails with a one-line install hint.
|
|
9
9
|
*/
|
|
10
10
|
import type { Hcl2JsonTree, TfGraph } from "./types.js";
|
|
11
|
-
/** Minimal shape of the parser
|
|
12
|
-
|
|
11
|
+
/** Minimal shape of the parser exports we depend on. */
|
|
12
|
+
export interface Hcl2Json {
|
|
13
|
+
parse: (filename: string, hcl: string) => Promise<Hcl2JsonTree>;
|
|
14
|
+
/** Expression-AST reference extraction (#998) — one traversal accessor per reference. */
|
|
15
|
+
getReferencesInExpression: (filename: string, expression: string) => Promise<Array<{
|
|
16
|
+
value: string;
|
|
17
|
+
}>>;
|
|
18
|
+
}
|
|
13
19
|
export declare class Hcl2JsonNotInstalled extends Error {
|
|
14
20
|
constructor(cause: unknown);
|
|
15
21
|
}
|
|
@@ -17,7 +23,7 @@ export declare class Hcl2JsonNotInstalled extends Error {
|
|
|
17
23
|
* Lazy-load the optional HCL parser. Throws `Hcl2JsonNotInstalled` with an
|
|
18
24
|
* install hint when the package is missing, rather than a raw MODULE_NOT_FOUND.
|
|
19
25
|
*/
|
|
20
|
-
export declare function loadHcl2json(): Promise<
|
|
26
|
+
export declare function loadHcl2json(): Promise<Hcl2Json>;
|
|
21
27
|
export interface ParseTerraformOptions {
|
|
22
28
|
/** Opt-in `.tfstate` path (#214 T2): overlays state-expanded instance counts. */
|
|
23
29
|
statePath?: string;
|
|
@@ -29,5 +35,4 @@ export interface ParseTerraformOptions {
|
|
|
29
35
|
* instance counts become accurate (see `state.ts`).
|
|
30
36
|
*/
|
|
31
37
|
export declare function parseTerraformDir(dir: string, opts?: ParseTerraformOptions): Promise<TfGraph>;
|
|
32
|
-
export {};
|
|
33
38
|
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/terraform/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAErD,
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/terraform/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAErD,wDAAwD;AACxD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAChE,yFAAyF;IACzF,yBAAyB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CACxG;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,KAAK,EAAE,OAAO;CAQ3B;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,CAMtD;AA+CD,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,OAAO,CAAC,CAWvG"}
|
|
@@ -29,9 +29,10 @@ export declare const TIER_MAP: Record<string, TierInfo>;
|
|
|
29
29
|
*/
|
|
30
30
|
export declare const FOLDS_INTO: Record<string, string>;
|
|
31
31
|
/**
|
|
32
|
-
* The HCL attribute carrying a resource's physical name, per type —
|
|
33
|
-
* from the
|
|
34
|
-
*
|
|
32
|
+
* The HCL attribute carrying a resource's physical name, per type — AWS entries
|
|
33
|
+
* derived from the carve-out table, non-AWS listed directly. A dotted entry is
|
|
34
|
+
* a path into nested blocks (`manifest.metadata.name`). Used for the graph's
|
|
35
|
+
* identity and the live-import hint. Absent → fall back to the TF logical name.
|
|
35
36
|
*/
|
|
36
37
|
export declare const IDENTITY_ATTR: Record<string, string>;
|
|
37
38
|
export declare function resolveTier(tfType: string): TierInfo | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tier-map.d.ts","sourceRoot":"","sources":["../../src/terraform/tier-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"tier-map.d.ts","sourceRoot":"","sources":["../../src/terraform/tier-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AA0CD,sEAAsE;AACtE,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAK7C,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiB7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGhD,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAE3D"}
|
|
@@ -46,6 +46,13 @@ export interface TfEdge {
|
|
|
46
46
|
to: string;
|
|
47
47
|
/** The attribute path(s) referenced, e.g. `["id", "arn"]`. */
|
|
48
48
|
attrs: string[];
|
|
49
|
+
/**
|
|
50
|
+
* The referring block's own top-level attribute(s) the reference sits in,
|
|
51
|
+
* e.g. `["vpc_id"]` for a subnet reading its VPC (#998). This is what a
|
|
52
|
+
* deferred outbound input is named after when emit turns it into a build
|
|
53
|
+
* parameter. Empty when the reference came from a non-object block shape.
|
|
54
|
+
*/
|
|
55
|
+
via: string[];
|
|
49
56
|
}
|
|
50
57
|
export interface TfGraph {
|
|
51
58
|
nodes: TfNode[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/terraform/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,MAAM;IACrB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/terraform/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,MAAM;IACrB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;;OAKG;IACH,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal unified-diff generator for the carve bridge patch (#998). Emits
|
|
3
|
+
* git-applyable hunks (`git apply`, or plain `patch -p1`) so the whole survivor
|
|
4
|
+
* edit — data sources plus rewired references — lands in one reviewable file.
|
|
5
|
+
* LCS-based; bridge inputs are hand-sized `.tf` files, so O(n·m) is fine.
|
|
6
|
+
*/
|
|
7
|
+
/** One file's diff, `a/<path>` → `b/<path>`, with git headers. Empty when unchanged. */
|
|
8
|
+
export declare function unifiedDiff(path: string, oldText: string, newText: string, context?: number): string;
|
|
9
|
+
/** A new-file diff (`/dev/null` → `b/<path>`), git-applyable. */
|
|
10
|
+
export declare function newFileDiff(path: string, text: string): string;
|
|
11
|
+
//# sourceMappingURL=unified-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-diff.d.ts","sourceRoot":"","sources":["../../src/terraform/unified-diff.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CA0B/F;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAa9D"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`buildOkfBundle over shipped examples > aws lambda-s3 emits a conformant, snapshot-stable bundle 1`] = `
|
|
4
|
+
[
|
|
5
|
+
{
|
|
6
|
+
"content": "---
|
|
7
|
+
type: AWS::S3::Bucket
|
|
8
|
+
title: appBucket
|
|
9
|
+
description: aws resource of type AWS::S3::Bucket
|
|
10
|
+
name: appBucket
|
|
11
|
+
lexicon: aws
|
|
12
|
+
kind: resource
|
|
13
|
+
source: main.ts
|
|
14
|
+
composite: LambdaS3
|
|
15
|
+
composite_instance: app
|
|
16
|
+
---
|
|
17
|
+
Declared in \`main.ts\`.
|
|
18
|
+
|
|
19
|
+
## Referenced by
|
|
20
|
+
|
|
21
|
+
- [appFunc](/aws/appFunc.md)
|
|
22
|
+
- [appRole](/aws/appRole.md)
|
|
23
|
+
",
|
|
24
|
+
"path": "aws/appBucket.md",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"content": "---
|
|
28
|
+
type: AWS::Lambda::Function
|
|
29
|
+
title: appFunc
|
|
30
|
+
description: aws resource of type AWS::Lambda::Function
|
|
31
|
+
name: appFunc
|
|
32
|
+
lexicon: aws
|
|
33
|
+
kind: resource
|
|
34
|
+
source: main.ts
|
|
35
|
+
composite: LambdaS3
|
|
36
|
+
composite_instance: app
|
|
37
|
+
---
|
|
38
|
+
Declared in \`main.ts\`.
|
|
39
|
+
|
|
40
|
+
## Depends on
|
|
41
|
+
|
|
42
|
+
- [appBucket](/aws/appBucket.md)
|
|
43
|
+
- [appRole](/aws/appRole.md)
|
|
44
|
+
",
|
|
45
|
+
"path": "aws/appFunc.md",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"content": "---
|
|
49
|
+
type: AWS::IAM::Role
|
|
50
|
+
title: appRole
|
|
51
|
+
description: aws resource of type AWS::IAM::Role
|
|
52
|
+
name: appRole
|
|
53
|
+
lexicon: aws
|
|
54
|
+
kind: resource
|
|
55
|
+
source: main.ts
|
|
56
|
+
composite: LambdaS3
|
|
57
|
+
composite_instance: app
|
|
58
|
+
---
|
|
59
|
+
Declared in \`main.ts\`.
|
|
60
|
+
|
|
61
|
+
## Depends on
|
|
62
|
+
|
|
63
|
+
- [appBucket](/aws/appBucket.md)
|
|
64
|
+
|
|
65
|
+
## Referenced by
|
|
66
|
+
|
|
67
|
+
- [appFunc](/aws/appFunc.md)
|
|
68
|
+
",
|
|
69
|
+
"path": "aws/appRole.md",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"content": "---
|
|
73
|
+
type: Output
|
|
74
|
+
title: bucketArn
|
|
75
|
+
description: aws output of type Output
|
|
76
|
+
name: bucketArn
|
|
77
|
+
lexicon: aws
|
|
78
|
+
kind: output
|
|
79
|
+
source: outputs.ts
|
|
80
|
+
---
|
|
81
|
+
Declared in \`outputs.ts\`.
|
|
82
|
+
",
|
|
83
|
+
"path": "aws/bucketArn.md",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"content": "---
|
|
87
|
+
type: AWS::CloudFormation::Parameter
|
|
88
|
+
title: environment
|
|
89
|
+
description: aws resource of type AWS::CloudFormation::Parameter
|
|
90
|
+
name: environment
|
|
91
|
+
lexicon: aws
|
|
92
|
+
kind: resource
|
|
93
|
+
source: params.ts
|
|
94
|
+
---
|
|
95
|
+
Declared in \`params.ts\`.
|
|
96
|
+
",
|
|
97
|
+
"path": "aws/environment.md",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"content": "---
|
|
101
|
+
type: chant:aws:defaultTags
|
|
102
|
+
title: tags
|
|
103
|
+
description: aws resource of type chant:aws:defaultTags
|
|
104
|
+
name: tags
|
|
105
|
+
lexicon: aws
|
|
106
|
+
kind: resource
|
|
107
|
+
source: tags.ts
|
|
108
|
+
---
|
|
109
|
+
Declared in \`tags.ts\`.
|
|
110
|
+
",
|
|
111
|
+
"path": "aws/tags.md",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"content": "---
|
|
115
|
+
okf_version: '0.2'
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
# Lexicon: aws
|
|
119
|
+
|
|
120
|
+
* [appBucket](/aws/appBucket.md) - aws resource of type AWS::S3::Bucket
|
|
121
|
+
* [appFunc](/aws/appFunc.md) - aws resource of type AWS::Lambda::Function
|
|
122
|
+
* [appRole](/aws/appRole.md) - aws resource of type AWS::IAM::Role
|
|
123
|
+
* [bucketArn](/aws/bucketArn.md) - aws output of type Output
|
|
124
|
+
* [environment](/aws/environment.md) - aws resource of type AWS::CloudFormation::Parameter
|
|
125
|
+
* [tags](/aws/tags.md) - aws resource of type chant:aws:defaultTags
|
|
126
|
+
",
|
|
127
|
+
"path": "index.md",
|
|
128
|
+
},
|
|
129
|
+
]
|
|
130
|
+
`;
|
|
131
|
+
|
|
132
|
+
exports[`buildOkfBundle over shipped examples > gitlab node-pipeline emits a conformant, snapshot-stable bundle 1`] = `
|
|
133
|
+
[
|
|
134
|
+
{
|
|
135
|
+
"content": "---
|
|
136
|
+
type: GitLab::CI::Job
|
|
137
|
+
title: appBuild
|
|
138
|
+
description: gitlab resource of type GitLab::CI::Job
|
|
139
|
+
name: appBuild
|
|
140
|
+
lexicon: gitlab
|
|
141
|
+
kind: resource
|
|
142
|
+
source: pipeline.ts
|
|
143
|
+
composite: NodePipeline
|
|
144
|
+
composite_instance: app
|
|
145
|
+
---
|
|
146
|
+
Declared in \`pipeline.ts\`.
|
|
147
|
+
",
|
|
148
|
+
"path": "gitlab/appBuild.md",
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"content": "---
|
|
152
|
+
type: GitLab::CI::Default
|
|
153
|
+
title: appDefaults
|
|
154
|
+
description: gitlab resource of type GitLab::CI::Default
|
|
155
|
+
name: appDefaults
|
|
156
|
+
lexicon: gitlab
|
|
157
|
+
kind: resource
|
|
158
|
+
source: pipeline.ts
|
|
159
|
+
composite: NodePipeline
|
|
160
|
+
composite_instance: app
|
|
161
|
+
---
|
|
162
|
+
Declared in \`pipeline.ts\`.
|
|
163
|
+
",
|
|
164
|
+
"path": "gitlab/appDefaults.md",
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"content": "---
|
|
168
|
+
type: GitLab::CI::Job
|
|
169
|
+
title: appTest
|
|
170
|
+
description: gitlab resource of type GitLab::CI::Job
|
|
171
|
+
name: appTest
|
|
172
|
+
lexicon: gitlab
|
|
173
|
+
kind: resource
|
|
174
|
+
source: pipeline.ts
|
|
175
|
+
composite: NodePipeline
|
|
176
|
+
composite_instance: app
|
|
177
|
+
---
|
|
178
|
+
Declared in \`pipeline.ts\`.
|
|
179
|
+
",
|
|
180
|
+
"path": "gitlab/appTest.md",
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"content": "---
|
|
184
|
+
okf_version: '0.2'
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
# Lexicon: gitlab
|
|
188
|
+
|
|
189
|
+
* [appBuild](/gitlab/appBuild.md) - gitlab resource of type GitLab::CI::Job
|
|
190
|
+
* [appDefaults](/gitlab/appDefaults.md) - gitlab resource of type GitLab::CI::Default
|
|
191
|
+
* [appTest](/gitlab/appTest.md) - gitlab resource of type GitLab::CI::Job
|
|
192
|
+
",
|
|
193
|
+
"path": "index.md",
|
|
194
|
+
},
|
|
195
|
+
]
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
exports[`buildOkfBundle over shipped examples > k8s layered-config emits a conformant, snapshot-stable bundle 1`] = `
|
|
199
|
+
[
|
|
200
|
+
{
|
|
201
|
+
"content": "---
|
|
202
|
+
okf_version: '0.2'
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
# Lexicon: k8s
|
|
206
|
+
|
|
207
|
+
* [devAppDeployment](/k8s/devAppDeployment.md) - k8s resource of type K8s::Apps::Deployment
|
|
208
|
+
* [devAppService](/k8s/devAppService.md) - k8s resource of type K8s::Core::Service
|
|
209
|
+
* [prodAppDeployment](/k8s/prodAppDeployment.md) - k8s resource of type K8s::Apps::Deployment
|
|
210
|
+
* [prodAppIngress](/k8s/prodAppIngress.md) - k8s resource of type K8s::Networking::Ingress
|
|
211
|
+
* [prodAppPdb](/k8s/prodAppPdb.md) - k8s resource of type K8s::Policy::PodDisruptionBudget
|
|
212
|
+
* [prodAppService](/k8s/prodAppService.md) - k8s resource of type K8s::Core::Service
|
|
213
|
+
* [stagingAppDeployment](/k8s/stagingAppDeployment.md) - k8s resource of type K8s::Apps::Deployment
|
|
214
|
+
* [stagingAppIngress](/k8s/stagingAppIngress.md) - k8s resource of type K8s::Networking::Ingress
|
|
215
|
+
* [stagingAppPdb](/k8s/stagingAppPdb.md) - k8s resource of type K8s::Policy::PodDisruptionBudget
|
|
216
|
+
* [stagingAppService](/k8s/stagingAppService.md) - k8s resource of type K8s::Core::Service
|
|
217
|
+
",
|
|
218
|
+
"path": "index.md",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"content": "---
|
|
222
|
+
type: K8s::Apps::Deployment
|
|
223
|
+
title: devAppDeployment
|
|
224
|
+
description: k8s resource of type K8s::Apps::Deployment
|
|
225
|
+
name: devAppDeployment
|
|
226
|
+
lexicon: k8s
|
|
227
|
+
kind: resource
|
|
228
|
+
source: web.ts
|
|
229
|
+
composite: WebApp
|
|
230
|
+
composite_instance: devApp
|
|
231
|
+
---
|
|
232
|
+
Declared in \`web.ts\`.
|
|
233
|
+
",
|
|
234
|
+
"path": "k8s/devAppDeployment.md",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"content": "---
|
|
238
|
+
type: K8s::Core::Service
|
|
239
|
+
title: devAppService
|
|
240
|
+
description: k8s resource of type K8s::Core::Service
|
|
241
|
+
name: devAppService
|
|
242
|
+
lexicon: k8s
|
|
243
|
+
kind: resource
|
|
244
|
+
source: web.ts
|
|
245
|
+
composite: WebApp
|
|
246
|
+
composite_instance: devApp
|
|
247
|
+
---
|
|
248
|
+
Declared in \`web.ts\`.
|
|
249
|
+
",
|
|
250
|
+
"path": "k8s/devAppService.md",
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"content": "---
|
|
254
|
+
type: K8s::Apps::Deployment
|
|
255
|
+
title: prodAppDeployment
|
|
256
|
+
description: k8s resource of type K8s::Apps::Deployment
|
|
257
|
+
name: prodAppDeployment
|
|
258
|
+
lexicon: k8s
|
|
259
|
+
kind: resource
|
|
260
|
+
source: web.ts
|
|
261
|
+
composite: WebApp
|
|
262
|
+
composite_instance: prodApp
|
|
263
|
+
---
|
|
264
|
+
Declared in \`web.ts\`.
|
|
265
|
+
",
|
|
266
|
+
"path": "k8s/prodAppDeployment.md",
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"content": "---
|
|
270
|
+
type: K8s::Networking::Ingress
|
|
271
|
+
title: prodAppIngress
|
|
272
|
+
description: k8s resource of type K8s::Networking::Ingress
|
|
273
|
+
name: prodAppIngress
|
|
274
|
+
lexicon: k8s
|
|
275
|
+
kind: resource
|
|
276
|
+
source: web.ts
|
|
277
|
+
composite: WebApp
|
|
278
|
+
composite_instance: prodApp
|
|
279
|
+
---
|
|
280
|
+
Declared in \`web.ts\`.
|
|
281
|
+
",
|
|
282
|
+
"path": "k8s/prodAppIngress.md",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"content": "---
|
|
286
|
+
type: K8s::Policy::PodDisruptionBudget
|
|
287
|
+
title: prodAppPdb
|
|
288
|
+
description: k8s resource of type K8s::Policy::PodDisruptionBudget
|
|
289
|
+
name: prodAppPdb
|
|
290
|
+
lexicon: k8s
|
|
291
|
+
kind: resource
|
|
292
|
+
source: web.ts
|
|
293
|
+
composite: WebApp
|
|
294
|
+
composite_instance: prodApp
|
|
295
|
+
---
|
|
296
|
+
Declared in \`web.ts\`.
|
|
297
|
+
",
|
|
298
|
+
"path": "k8s/prodAppPdb.md",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"content": "---
|
|
302
|
+
type: K8s::Core::Service
|
|
303
|
+
title: prodAppService
|
|
304
|
+
description: k8s resource of type K8s::Core::Service
|
|
305
|
+
name: prodAppService
|
|
306
|
+
lexicon: k8s
|
|
307
|
+
kind: resource
|
|
308
|
+
source: web.ts
|
|
309
|
+
composite: WebApp
|
|
310
|
+
composite_instance: prodApp
|
|
311
|
+
---
|
|
312
|
+
Declared in \`web.ts\`.
|
|
313
|
+
",
|
|
314
|
+
"path": "k8s/prodAppService.md",
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"content": "---
|
|
318
|
+
type: K8s::Apps::Deployment
|
|
319
|
+
title: stagingAppDeployment
|
|
320
|
+
description: k8s resource of type K8s::Apps::Deployment
|
|
321
|
+
name: stagingAppDeployment
|
|
322
|
+
lexicon: k8s
|
|
323
|
+
kind: resource
|
|
324
|
+
source: web.ts
|
|
325
|
+
composite: WebApp
|
|
326
|
+
composite_instance: stagingApp
|
|
327
|
+
---
|
|
328
|
+
Declared in \`web.ts\`.
|
|
329
|
+
",
|
|
330
|
+
"path": "k8s/stagingAppDeployment.md",
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"content": "---
|
|
334
|
+
type: K8s::Networking::Ingress
|
|
335
|
+
title: stagingAppIngress
|
|
336
|
+
description: k8s resource of type K8s::Networking::Ingress
|
|
337
|
+
name: stagingAppIngress
|
|
338
|
+
lexicon: k8s
|
|
339
|
+
kind: resource
|
|
340
|
+
source: web.ts
|
|
341
|
+
composite: WebApp
|
|
342
|
+
composite_instance: stagingApp
|
|
343
|
+
---
|
|
344
|
+
Declared in \`web.ts\`.
|
|
345
|
+
",
|
|
346
|
+
"path": "k8s/stagingAppIngress.md",
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"content": "---
|
|
350
|
+
type: K8s::Policy::PodDisruptionBudget
|
|
351
|
+
title: stagingAppPdb
|
|
352
|
+
description: k8s resource of type K8s::Policy::PodDisruptionBudget
|
|
353
|
+
name: stagingAppPdb
|
|
354
|
+
lexicon: k8s
|
|
355
|
+
kind: resource
|
|
356
|
+
source: web.ts
|
|
357
|
+
composite: WebApp
|
|
358
|
+
composite_instance: stagingApp
|
|
359
|
+
---
|
|
360
|
+
Declared in \`web.ts\`.
|
|
361
|
+
",
|
|
362
|
+
"path": "k8s/stagingAppPdb.md",
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
"content": "---
|
|
366
|
+
type: K8s::Core::Service
|
|
367
|
+
title: stagingAppService
|
|
368
|
+
description: k8s resource of type K8s::Core::Service
|
|
369
|
+
name: stagingAppService
|
|
370
|
+
lexicon: k8s
|
|
371
|
+
kind: resource
|
|
372
|
+
source: web.ts
|
|
373
|
+
composite: WebApp
|
|
374
|
+
composite_instance: stagingApp
|
|
375
|
+
---
|
|
376
|
+
Declared in \`web.ts\`.
|
|
377
|
+
",
|
|
378
|
+
"path": "k8s/stagingAppService.md",
|
|
379
|
+
},
|
|
380
|
+
]
|
|
381
|
+
`;
|
package/src/audit/rules-doc.ts
CHANGED
|
@@ -14,7 +14,7 @@ const GROUPS: Array<{ heading: string; prefixes: string[]; blurb: string }> = [
|
|
|
14
14
|
{ heading: "GitHub Actions (GHA)", prefixes: ["GHA"], blurb: "Also applied to Forgejo workflows, which are GitHub-dialect." },
|
|
15
15
|
{ heading: "GitLab CI (WGL)", prefixes: ["WGL"], blurb: "" },
|
|
16
16
|
{ heading: "Forgejo (WFJ)", prefixes: ["WFJ"], blurb: "" },
|
|
17
|
-
{ heading: "Kubernetes (WK8 / ARGO)", prefixes: ["WK8", "ARGO"], blurb: "Run against Kubernetes manifests." },
|
|
17
|
+
{ heading: "Kubernetes (WK8 / ARGO / FLUX)", prefixes: ["WK8", "ARGO", "FLUX"], blurb: "Run against Kubernetes manifests." },
|
|
18
18
|
{ heading: "Docker (DKRD)", prefixes: ["DKRD"], blurb: "Run against Dockerfiles and Compose files." },
|
|
19
19
|
{ heading: "AWS CloudFormation (WAW / COR / EXT)", prefixes: ["WAW", "COR", "EXT"], blurb: "Run against CloudFormation templates (JSON or YAML)." },
|
|
20
20
|
{ heading: "Azure ARM (AZR)", prefixes: ["AZR"], blurb: "Run against ARM deployment templates (JSON)." },
|
package/src/build.test.ts
CHANGED
|
@@ -257,6 +257,101 @@ export const testEntity = {
|
|
|
257
257
|
});
|
|
258
258
|
});
|
|
259
259
|
|
|
260
|
+
describe("build-root contributors (#1548 piece 3)", () => {
|
|
261
|
+
let testDir: string;
|
|
262
|
+
|
|
263
|
+
beforeEach(async () => {
|
|
264
|
+
testDir = join(tmpdir(), `chant-buildroots-test-${Date.now()}-${Math.random()}`);
|
|
265
|
+
await mkdir(testDir, { recursive: true });
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
afterEach(async () => {
|
|
269
|
+
await rm(testDir, { recursive: true, force: true });
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const entity = (entityType: string): Declarable =>
|
|
273
|
+
({
|
|
274
|
+
lexicon: "test",
|
|
275
|
+
entityType,
|
|
276
|
+
kind: "resource",
|
|
277
|
+
props: {},
|
|
278
|
+
[DECLARABLE_MARKER]: true,
|
|
279
|
+
}) as unknown as Declarable;
|
|
280
|
+
|
|
281
|
+
const recordingSerializer = (seen: string[][]): Serializer => ({
|
|
282
|
+
name: "test",
|
|
283
|
+
rulePrefix: "TEST",
|
|
284
|
+
serialize: (entities) => {
|
|
285
|
+
seen.push([...entities.keys()]);
|
|
286
|
+
return "out";
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("contributed entities join the entity set and reach the serializer", async () => {
|
|
291
|
+
const seen: string[][] = [];
|
|
292
|
+
const result = await build(testDir, [recordingSerializer(seen)], undefined, {
|
|
293
|
+
buildRoots: [
|
|
294
|
+
async () => ({
|
|
295
|
+
entities: new Map([["overlays/prod/deploymentApp", entity("TestEntity")]]),
|
|
296
|
+
warnings: ["rendered a stray doc"],
|
|
297
|
+
}),
|
|
298
|
+
],
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
expect(result.errors).toEqual([]);
|
|
302
|
+
expect(result.entities.has("overlays/prod/deploymentApp")).toBe(true);
|
|
303
|
+
expect(seen).toEqual([["overlays/prod/deploymentApp"]]);
|
|
304
|
+
expect(result.warnings).toContain("rendered a stray doc");
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("a contributor that throws becomes a build error carrying its message, not a thrown stack", async () => {
|
|
308
|
+
const result = await build(testDir, [], undefined, {
|
|
309
|
+
buildRoots: [
|
|
310
|
+
async () => {
|
|
311
|
+
throw new Error("neither the `kustomize` binary nor `kubectl` was found on PATH");
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
expect(result.errors).toHaveLength(1);
|
|
317
|
+
expect(result.errors[0].message).toContain("neither the `kustomize` binary nor `kubectl`");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("a contributed name colliding with a discovered entity is a build error, never an overwrite", async () => {
|
|
321
|
+
await writeFile(
|
|
322
|
+
join(testDir, "app.infra.ts"),
|
|
323
|
+
`
|
|
324
|
+
export const discovered = {
|
|
325
|
+
lexicon: "test",
|
|
326
|
+
entityType: "Discovered",
|
|
327
|
+
props: {},
|
|
328
|
+
[Symbol.for("chant.declarable")]: true,
|
|
329
|
+
};
|
|
330
|
+
`,
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
const result = await build(testDir, [recordingSerializer([])], undefined, {
|
|
334
|
+
buildRoots: [async () => ({ entities: new Map([["discovered", entity("Contributed")]]) })],
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
expect(result.errors.some((e) => e.message.includes('"discovered" collides'))).toBe(true);
|
|
338
|
+
expect(result.entities.get("discovered")?.entityType).toBe("Discovered");
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("contributors run exactly once per build", async () => {
|
|
342
|
+
let calls = 0;
|
|
343
|
+
await build(testDir, [], undefined, {
|
|
344
|
+
buildRoots: [
|
|
345
|
+
async () => {
|
|
346
|
+
calls++;
|
|
347
|
+
return { entities: new Map() };
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
});
|
|
351
|
+
expect(calls).toBe(1);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
260
355
|
describe("partitionByLexicon", () => {
|
|
261
356
|
test("partitions entities by lexicon", () => {
|
|
262
357
|
const entities = new Map<string, Declarable>([
|
package/src/build.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Declarable } from "./declarable";
|
|
|
2
2
|
import type { Serializer, SerializerResult } from "./serializer";
|
|
3
3
|
import type { OwnershipMarker } from "./ownership";
|
|
4
4
|
import type { BuildError, DiscoveryErrorType } from "./errors";
|
|
5
|
-
import type { IntrinsicDef } from "./lexicon";
|
|
5
|
+
import type { IntrinsicDef, BuildRootContribution } from "./lexicon";
|
|
6
6
|
import type { BuildParamProvenance } from "./provenance";
|
|
7
7
|
import { DiscoveryError, BuildError as BuildErrorClass } from "./errors";
|
|
8
8
|
import { LexiconOutput, isLexiconOutput } from "./lexicon-output";
|
|
@@ -215,6 +215,21 @@ export interface BuildOptions {
|
|
|
215
215
|
* carries the already-resolved records for provenance.
|
|
216
216
|
*/
|
|
217
217
|
buildParams?: BuildParamProvenance[];
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* chant #1548 piece 3 — lexicon-contributed build roots: closures the CLI
|
|
221
|
+
* binds from each configured plugin's `buildRoots(ctx)` hook (see
|
|
222
|
+
* `collectBuildRootContributors` in ./cli/plugins.ts), each rendering a
|
|
223
|
+
* non-chant-source root (a kustomize overlay dir) into entities. Run once,
|
|
224
|
+
* at the TOP-LEVEL build only (never repeated for nested child projects),
|
|
225
|
+
* after discovery and before partitioning — so contributed entities are
|
|
226
|
+
* serialized, ownership-stamped, post-synth-checked and observed exactly
|
|
227
|
+
* like discovered ones. A contributor that throws becomes a build error
|
|
228
|
+
* carrying its message (the k8s hook's missing-binary refusal names the
|
|
229
|
+
* binaries); a contributed name colliding with a discovered entity is a
|
|
230
|
+
* build error, never a silent overwrite.
|
|
231
|
+
*/
|
|
232
|
+
buildRoots?: Array<() => Promise<BuildRootContribution>>;
|
|
218
233
|
}
|
|
219
234
|
|
|
220
235
|
export interface BuildResult {
|
|
@@ -657,6 +672,36 @@ async function buildFromDiscoveryResult(
|
|
|
657
672
|
}
|
|
658
673
|
}
|
|
659
674
|
|
|
675
|
+
// Step 4b (#1548 piece 3): lexicon-contributed build roots — rendered
|
|
676
|
+
// non-source roots (kustomize dirs) joining the entity set before
|
|
677
|
+
// partitioning, so everything downstream (serialization with ownership
|
|
678
|
+
// stamping, post-synth checks, observation) treats them as declared.
|
|
679
|
+
// Top-level build only: nested child builds receive the same options
|
|
680
|
+
// object, and re-running the contributors there would duplicate every
|
|
681
|
+
// contributed entity once per child.
|
|
682
|
+
if (!parentBuildStack && options?.buildRoots) {
|
|
683
|
+
for (const contribute of options.buildRoots) {
|
|
684
|
+
try {
|
|
685
|
+
const contribution = await contribute();
|
|
686
|
+
for (const w of contribution.warnings ?? []) warnings.push(w);
|
|
687
|
+
for (const [name, entity] of contribution.entities) {
|
|
688
|
+
if (discoveryResult.entities.has(name)) {
|
|
689
|
+
errors.push(
|
|
690
|
+
new BuildErrorClass(
|
|
691
|
+
"",
|
|
692
|
+
`Build-root entity "${name}" collides with a discovered entity of the same name`,
|
|
693
|
+
),
|
|
694
|
+
);
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
discoveryResult.entities.set(name, entity);
|
|
698
|
+
}
|
|
699
|
+
} catch (error) {
|
|
700
|
+
errors.push(new BuildErrorClass("", error instanceof Error ? error.message : String(error)));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
660
705
|
// Step 5: Partition entities by lexicon
|
|
661
706
|
const partitions = partitionByLexicon(discoveryResult.entities);
|
|
662
707
|
|