@intentius/chant 0.24.0 → 0.26.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.
Files changed (72) hide show
  1. package/dist/build.d.ts.map +1 -1
  2. package/dist/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cli/main.d.ts.map +1 -1
  4. package/dist/config-import.d.ts +33 -0
  5. package/dist/config-import.d.ts.map +1 -0
  6. package/dist/config-sandbox.d.ts +47 -0
  7. package/dist/config-sandbox.d.ts.map +1 -0
  8. package/dist/config.d.ts +11 -2
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/discovery/entity-wire-codec.d.ts +15 -10
  11. package/dist/discovery/entity-wire-codec.d.ts.map +1 -1
  12. package/dist/discovery/graph.d.ts.map +1 -1
  13. package/dist/discovery/sandbox/config-run.d.ts +24 -0
  14. package/dist/discovery/sandbox/config-run.d.ts.map +1 -0
  15. package/dist/discovery/sandbox/config-wire.d.ts +84 -0
  16. package/dist/discovery/sandbox/config-wire.d.ts.map +1 -0
  17. package/dist/discovery/sandbox/driver.d.ts +49 -0
  18. package/dist/discovery/sandbox/driver.d.ts.map +1 -1
  19. package/dist/discovery/sandbox/fork.d.ts +70 -0
  20. package/dist/discovery/sandbox/fork.d.ts.map +1 -0
  21. package/dist/discovery/sandbox/policy-run.d.ts +33 -0
  22. package/dist/discovery/sandbox/policy-run.d.ts.map +1 -0
  23. package/dist/discovery/sandbox/policy-wire.d.ts +177 -0
  24. package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -0
  25. package/dist/discovery/sandbox/run.d.ts +10 -20
  26. package/dist/discovery/sandbox/run.d.ts.map +1 -1
  27. package/dist/intrinsic-interpolation.d.ts.map +1 -1
  28. package/dist/lexicon-output.d.ts +62 -6
  29. package/dist/lexicon-output.d.ts.map +1 -1
  30. package/dist/lint/config.d.ts +6 -0
  31. package/dist/lint/config.d.ts.map +1 -1
  32. package/dist/lint/policy-import.d.ts +50 -0
  33. package/dist/lint/policy-import.d.ts.map +1 -0
  34. package/dist/lint/policy-sandbox.d.ts +89 -0
  35. package/dist/lint/policy-sandbox.d.ts.map +1 -0
  36. package/dist/lint/policy.d.ts +12 -1
  37. package/dist/lint/policy.d.ts.map +1 -1
  38. package/dist/stack-output.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/build.test.ts +96 -1
  41. package/src/build.ts +36 -12
  42. package/src/cli/commands/build.ts +46 -5
  43. package/src/cli/main.test.ts +93 -17
  44. package/src/cli/main.ts +111 -11
  45. package/src/config-import.ts +43 -0
  46. package/src/config-sandbox.ts +138 -0
  47. package/src/config.ts +14 -5
  48. package/src/discovery/entity-wire-codec.ts +35 -21
  49. package/src/discovery/entity-wire.test.ts +26 -0
  50. package/src/discovery/graph.test.ts +40 -1
  51. package/src/discovery/graph.ts +8 -2
  52. package/src/discovery/sandbox/config-boundary.test.ts +239 -0
  53. package/src/discovery/sandbox/config-run.ts +130 -0
  54. package/src/discovery/sandbox/config-wire.test.ts +110 -0
  55. package/src/discovery/sandbox/config-wire.ts +195 -0
  56. package/src/discovery/sandbox/driver.ts +200 -0
  57. package/src/discovery/sandbox/fork.ts +148 -0
  58. package/src/discovery/sandbox/policy-boundary.test.ts +325 -0
  59. package/src/discovery/sandbox/policy-run.ts +180 -0
  60. package/src/discovery/sandbox/policy-wire.test.ts +310 -0
  61. package/src/discovery/sandbox/policy-wire.ts +277 -0
  62. package/src/discovery/sandbox/run.ts +28 -85
  63. package/src/intrinsic-interpolation.test.ts +27 -1
  64. package/src/intrinsic-interpolation.ts +10 -2
  65. package/src/lexicon-output.test.ts +173 -1
  66. package/src/lexicon-output.ts +123 -14
  67. package/src/lint/config.ts +8 -4
  68. package/src/lint/policy-import.ts +70 -0
  69. package/src/lint/policy-sandbox.ts +123 -0
  70. package/src/lint/policy.ts +20 -2
  71. package/src/stack-output.test.ts +118 -0
  72. package/src/stack-output.ts +21 -5
@@ -0,0 +1,177 @@
1
+ import type { Declarable } from "../../declarable.js";
2
+ import type { SerializerResult } from "../../serializer.js";
3
+ import type { PostSynthContext } from "../../lint/post-synth.js";
4
+ import { type EntitySetWire } from "../entity-wire-codec.js";
5
+ import { type ConfigWireOffender } from "./config-wire.js";
6
+ /**
7
+ * chant #1131 — what a build result looks like on its way INTO the sandboxed
8
+ * policy child, and what a `PostSynthDiagnostic` must look like on its way back
9
+ * out.
10
+ *
11
+ * A project's `lint.policies` checks are project-authored functions chant calls
12
+ * over the finished build. #1113 put `chant.config.ts` behind the `--sandbox`
13
+ * boundary but could not take the policies with it, because the config declares
14
+ * them as *paths*: the modules were still imported and their `check` functions
15
+ * still invoked in the CLI's own process, with the CLI's filesystem, network,
16
+ * environment and process-spawn access, after discovery was over.
17
+ *
18
+ * The shape of the fix is forced by what a policy is. It is not data that can
19
+ * be evaluated somewhere and carried back — it is a callback over the resolved
20
+ * resources, so it has to run somewhere it can see them. It also cannot run in
21
+ * the #1045 discovery child, because that child only ever sees the run-fallback
22
+ * *subset*: folded files are collected in the parent, and serialization happens
23
+ * in the parent, so no complete view of the build exists on that side. What
24
+ * does exist, after the parent has merged and serialized, is a build result
25
+ * that is *nearly* data already — which is what this module makes explicit.
26
+ *
27
+ * So: one more child, after the merge, handed the encoded build result,
28
+ * importing the policy modules inside the boundary and returning plain
29
+ * diagnostics. Same bundling (`./bundle.ts`), same spawn and `--permission`
30
+ * profile (`./fork.ts`), same error classification (`./child-errors.ts`), same
31
+ * "only JSON crosses, and anything else is named, never dropped" contract
32
+ * (`./config-wire.ts`, whose walk is reused directly).
33
+ *
34
+ * ## What crosses, and what that costs
35
+ *
36
+ * `PostSynthContext` gives a check five things. Four of them are already data:
37
+ * `outputs` (each lexicon's serialized text), `warnings`, `errors`,
38
+ * `sourceFileCount`. The fifth, `entities`, is a live `Map<string, Declarable>`
39
+ * whose cross-entity references are object identity and `WeakRef`s — the exact
40
+ * problem chant #1045 Phase 1 solved for discovery, so this reuses that codec
41
+ * (`../entity-wire-codec.ts`) rather than inventing a second one.
42
+ *
43
+ * That reuse is what makes the round trip cheap AND what defines its limits.
44
+ * `encodeEntitySet`/`decodeEntitySet` is documented as producing entities
45
+ * "behaviorally indistinguishable" from the in-process ones for chant's own
46
+ * consumers (serializers, the dependency graph, cross-lexicon detection), and
47
+ * a policy is a consumer of the same shape. Where it is NOT identical is
48
+ * written down in `docs/.../architecture/sandbox.mdx` and pinned by
49
+ * `./policy-wire.test.ts`:
50
+ *
51
+ * - An intrinsic (`Sub`, `Ref`, gitlab's `!reference`, …) decodes to a
52
+ * marker-bearing wrapper exposing `toJSON()`/`toYAML()`, not to an instance
53
+ * of the lexicon's own intrinsic class.
54
+ * - A decoded entity is a plain marker-bearing object, not an instance of the
55
+ * lexicon's resource class, and its `lexicon`/`entityType`/`kind`/`props`/
56
+ * `attributes` are non-enumerable (so `Object.keys(entity)` sees only the
57
+ * per-attribute/extra fields). Reads — `entity.props`, `entity.entityType`,
58
+ * `isDeclarable(entity)`, `instanceof AttrRef` — all still work.
59
+ * - A `ChildProjectInstance` (`nestedStack()`) has no wire form at all;
60
+ * `encodeEntitySet` throws rather than mis-encoding it, so a `--sandbox`
61
+ * build that both uses `nestedStack()` and declares `lint.policies` fails
62
+ * loudly. (No corpus entry uses `nestedStack()`.)
63
+ * - `errors` cross as the plain objects `DiscoveryError`/`BuildError`'s own
64
+ * `toJSON()` produces, not as `Error` instances. In practice this is never
65
+ * observable: `chant build` runs policies only when the build produced no
66
+ * errors at all, so the array is always empty at that point.
67
+ *
68
+ * Crucially, the first two are NOT new under `--sandbox`: a sandboxed build
69
+ * already merges decoded entities for every run-fallback file (`./run.ts`), so
70
+ * a policy running in-process on a `--sandbox` build is already looking at
71
+ * decoded entities for part of the set. Encoding is idempotent over a decoded
72
+ * entity (verified in `./policy-wire.test.ts`), so this child widens that from
73
+ * "the run-fallback subset" to "all of them" and changes nothing else.
74
+ */
75
+ /** Wire form of one lexicon's serialized output — already data on both sides; carried as-is. */
76
+ export type PolicyOutputWire = string | {
77
+ primary: string;
78
+ files?: Record<string, string>;
79
+ warnings?: string[];
80
+ };
81
+ /** A build result as pure JSON, for the sandboxed policy child. */
82
+ export interface PolicyBuildResultWire {
83
+ /** `../entity-wire-codec.ts`'s format — the same one the #1045 discovery child returns. */
84
+ entities: EntitySetWire;
85
+ /** `Map` entries as pairs; a `Map` itself JSON-stringifies to `{}`. */
86
+ outputs: Array<[string, PolicyOutputWire]>;
87
+ warnings: string[];
88
+ /** `DiscoveryError`/`BuildError`'s own `toJSON()` output. Always empty in practice — see the module doc. */
89
+ errors: Array<Record<string, unknown>>;
90
+ sourceFileCount: number;
91
+ /** `BuildResult.dependencies` (`Map<string, Set<string>>`) as pairs of arrays. Not part of `PostSynthContext`'s declared surface; carried so `ctx.buildResult` is not silently narrower than the object the in-process path passes. */
92
+ dependencies: Array<[string, string[]]>;
93
+ /** `BuildResult.manifest` — plain data (lexicons, cross-lexicon outputs, deploy order, stack graph). Same "not declared, still carried" reasoning as {@link dependencies}. */
94
+ manifest?: unknown;
95
+ /** `BuildResult.foldDecisions` — plain data. */
96
+ foldDecisions?: unknown[];
97
+ /** `BuildResult.buildParams` — plain data (#1064 provenance records). */
98
+ buildParams?: unknown[];
99
+ }
100
+ /** The subset of `BuildResult` this module knows how to carry. Structurally satisfied by `../../build.ts`'s `BuildResult`. */
101
+ export interface EncodablePolicyBuildResult {
102
+ outputs: Map<string, string | SerializerResult>;
103
+ entities: Map<string, Declarable>;
104
+ warnings: string[];
105
+ errors: ReadonlyArray<{
106
+ name: string;
107
+ message: string;
108
+ toJSON?: () => unknown;
109
+ }>;
110
+ sourceFileCount: number;
111
+ dependencies?: Map<string, Set<string>>;
112
+ manifest?: unknown;
113
+ foldDecisions?: unknown[];
114
+ buildParams?: unknown[];
115
+ }
116
+ /**
117
+ * Encode a merged, serialized build result for the policy child.
118
+ *
119
+ * Runs in the PARENT. Throws — never drops — when the result holds something
120
+ * the wire cannot represent: `encodeEntitySet`'s own refusals (a `nestedStack()`
121
+ * child project, an `AttrRef` that never got a logical name) propagate, and the
122
+ * finished payload is walked by `./config-wire.ts`'s scan so a serializer that
123
+ * somehow produced a non-data output is named by key path rather than silently
124
+ * mangled by `JSON.stringify`.
125
+ */
126
+ export declare function encodePolicyBuildResult(result: EncodablePolicyBuildResult): PolicyBuildResultWire;
127
+ /**
128
+ * Rebuild the `PostSynthContext["buildResult"]` a check expects, from the wire.
129
+ *
130
+ * Runs INSIDE the child. The maps and the live entity graph are reconstructed
131
+ * here (`decodeEntitySet`), so a check sees the same kind of object it sees
132
+ * in-process — `ctx.entities` is a real `Map`, its values are real
133
+ * `Declarable`s, and an `AttrRef` between two of them is a real `AttrRef`
134
+ * carrying its resolved logical name.
135
+ */
136
+ export declare function decodePolicyBuildResult(wire: PolicyBuildResultWire): PostSynthContext["buildResult"];
137
+ /** One thing a policy returned that cannot cross back, with the policy module it came from. */
138
+ export interface PolicyDiagnosticOffender extends ConfigWireOffender {
139
+ /** Absolute path of the `lint.policies` module whose check returned it. */
140
+ policy: string;
141
+ }
142
+ /**
143
+ * Validate what one policy module's checks returned, INSIDE the child, before
144
+ * it goes anywhere near the IPC channel.
145
+ *
146
+ * Two separate questions, both answered here rather than by hoping
147
+ * `JSON.stringify` behaves:
148
+ *
149
+ * 1. Is it data? A `PostSynthDiagnostic` is declared as five plain fields, but
150
+ * a check is arbitrary project code and can return anything. A function, a
151
+ * `Date`, a class instance, a circular reference — `JSON.stringify` would
152
+ * drop or rewrite each of them without a word, and the CLI would print a
153
+ * diagnostic that is not the one the policy produced.
154
+ * 2. Is it a diagnostic? A missing `checkId`, or a `severity` outside
155
+ * `error`/`warning`/`info`, is reported here instead of turning into an
156
+ * undefined-shaped line in the build's error list.
157
+ */
158
+ export declare function scanPolicyDiagnostics(diagnostics: unknown, policyPath: string): PolicyDiagnosticOffender[];
159
+ /**
160
+ * Thrown INSIDE the child by the per-check wrapper `./driver.ts` generates,
161
+ * when a check returns something that cannot cross back. Carries the offenders
162
+ * so the driver can report them as data rather than as a message string it
163
+ * would then have to parse.
164
+ *
165
+ * A class rather than a tagged object because the driver tests it with
166
+ * `instanceof`: both halves come from this one module, bundled once, so there
167
+ * is exactly one class identity inside the child.
168
+ */
169
+ export declare class PolicyWireError extends Error {
170
+ readonly offenders: PolicyDiagnosticOffender[];
171
+ constructor(offenders: PolicyDiagnosticOffender[]);
172
+ }
173
+ /** Render offenders as the body of a build error — one line each, naming the policy module. */
174
+ export declare function formatPolicyWireOffenders(subject: string, offenders: ReadonlyArray<ConfigWireOffender & {
175
+ policy?: string;
176
+ }>): string;
177
+ //# sourceMappingURL=policy-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-wire.d.ts","sourceRoot":"","sources":["../../../src/discovery/sandbox/policy-wire.ts"],"names":[],"mappings":"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"}
@@ -6,26 +6,16 @@ import { DiscoveryError } from "../../errors.js";
6
6
  * the same shape `discover()`'s own in-process run path would have produced:
7
7
  * a named, ref-resolved entities map plus any errors.
8
8
  *
9
- * Isolation mechanics (verified on Node v24.13.1see the chant#1045 PR
10
- * description for the full write-up):
11
- * - `--permission --allow-fs-read=<bundle dir>,<project dir>[,<trusted
12
- * external package dirs>]` no filesystem write, no child-process, no
13
- * worker-thread access. Bundling with esbuild first (not a packaging
14
- * change see `./bundle.ts`) means the child needs NO TypeScript loader
15
- * (no `tsx`, so no `--allow-worker` and no writable temp dir either),
16
- * unlike the plain `tsx`-based run path. The "trusted external package
17
- * dirs" allowance is narrow and specific: `./bundle.ts` deliberately
18
- * leaves a couple of chant/lexicon-internal dependencies (`typescript`)
19
- * unbundled and resolves them to their real, fixed location instead —
20
- * project source never controls what's installed there.
21
- * - The env is a spawn-time scrub (`env: {}` below, plus `PATH` — see the
22
- * option below), not `--permission`: Node's Permission Model does not gate
23
- * `process.env` at all (confirmed: every key stays readable even under
24
- * `--permission`).
25
- * - Network egress is NOT addressed here — Node has no flag for it. See the
26
- * chant#1045 PR description / docs for the residual-risk statement and
27
- * deployment guidance (a container with no egress, a network namespace).
28
- * This function does not claim to close that gap.
9
+ * Isolation mechanics live in `./fork.ts` — the one function that spawns a
10
+ * sandboxed child, shared with chant #1113's config evaluation
11
+ * (`./config-run.ts`) so the two cannot drift apart. In short:
12
+ * `--permission --allow-fs-read=<bundle dir>,<project dir>[,<trusted external
13
+ * package dirs>]`, a spawn-time environment scrub, no writes, no spawning, no
14
+ * worker threads, and no network guarantee. The "trusted external package
15
+ * dirs" allowance is narrow and specific: `./bundle.ts` deliberately leaves a
16
+ * couple of chant/lexicon-internal dependencies (`typescript`) unbundled and
17
+ * resolves them to their real, fixed location instead — project source never
18
+ * controls what's installed there.
29
19
  *
30
20
  * What does NOT run inside the child: fold (`tryFoldFile`, `../fold-import`)
31
21
  * stays exactly where it is today, in the parent, unsandboxed — fold already
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/discovery/sandbox/run.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAA2B,MAAM,cAAc,CAAC;AAMvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,2TAA2T;IAC3T,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,8LAA8L;IAC9L,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAsC3B"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/discovery/sandbox/run.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAA2B,MAAM,cAAc,CAAC;AAOvE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,2TAA2T;IAC3T,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,8LAA8L;IAC9L,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAsD3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"intrinsic-interpolation.d.ts","sourceRoot":"","sources":["../src/intrinsic-interpolation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,MAAM,4BAA4B,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;AAEtE;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,EACpE,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GACxC,4BAA4B,CA2C9B;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,cAAc,EAAE,4BAA4B,GAC3C,MAAM,CASR"}
1
+ {"version":3,"file":"intrinsic-interpolation.d.ts","sourceRoot":"","sources":["../src/intrinsic-interpolation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,MAAM,MAAM,4BAA4B,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;AAEtE;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,EACpE,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GACxC,4BAA4B,CAkD9B;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,cAAc,EAAE,4BAA4B,GAC3C,MAAM,CASR"}
@@ -1,5 +1,29 @@
1
1
  import { INTRINSIC_MARKER, type Intrinsic } from "./intrinsic.js";
2
2
  import { AttrRef } from "./attrref.js";
3
+ /** A value `output()` accepts that is already fully resolved — not a
4
+ * reference to anything, just data the author computed (a literal, a prop,
5
+ * a template string). See chant #1121. */
6
+ export type LexiconOutputLiteral = string | number | boolean;
7
+ /**
8
+ * Marker symbol for LexiconOutput identification (chant #1122).
9
+ *
10
+ * A GLOBAL symbol (via `Symbol.for`), like every other chant-core brand
11
+ * check — `DECLARABLE_MARKER`, `STACK_OUTPUT_MARKER`, `INTRINSIC_MARKER` —
12
+ * holds across separately-loaded copies of chant-core the way `instanceof`
13
+ * does not. Two copies in one process is a plain npm-dedupe outcome: a
14
+ * lexicon pinned to a chant range that does not overlap the project's own
15
+ * gets a nested `node_modules/@intentius/chant`, and a project file
16
+ * importing `output` from that lexicon then holds a different `LexiconOutput`
17
+ * class than the CLI does. `instanceof LexiconOutput` returns false for a
18
+ * real output built by the other copy, and every `Outputs` entry vanishes
19
+ * silently.
20
+ *
21
+ * Installed non-enumerably in the constructor (not as a public class field)
22
+ * so a shallow spread/clone of a real instance — which would already lack
23
+ * its prototype methods (`getOutputValue()`, `_setSourceEntity()`, …) — does
24
+ * not silently pick up the marker and pass this guard too.
25
+ */
26
+ export declare const LEXICON_OUTPUT_MARKER: unique symbol;
3
27
  /**
4
28
  * Sanitize auto-generated Output name parts into a valid CloudFormation
5
29
  * logical id. Real CloudFormation logical ids (including `Outputs` keys)
@@ -21,11 +45,17 @@ export declare function sanitizeLogicalId(...parts: string[]): string;
21
45
  *
22
46
  * Implements Intrinsic so it can be used as Value<string> anywhere.
23
47
  *
24
- * Accepts either an AttrRef (resource attribute reference) or any Intrinsic
25
- * (e.g. Sub, Join) for computed output values like constructed URLs.
48
+ * Accepts an AttrRef (resource attribute reference), any Intrinsic (e.g. Sub,
49
+ * Join) for computed output values like constructed URLs, or an already-
50
+ * resolved literal (string/number/boolean) — a constant the author's code
51
+ * computed rather than a reference to anything (chant #1121).
26
52
  */
27
53
  export declare class LexiconOutput implements Intrinsic {
28
54
  readonly [INTRINSIC_MARKER]: true;
55
+ /** @internal Brand marker — see {@link LEXICON_OUTPUT_MARKER}. Declared
56
+ * here only for type purposes; the real, non-enumerable property is
57
+ * installed by the constructor. */
58
+ readonly [LEXICON_OUTPUT_MARKER]: true;
29
59
  readonly sourceLexicon: string;
30
60
  readonly sourceEntity: string;
31
61
  readonly sourceAttribute: string | null;
@@ -39,7 +69,17 @@ export declare class LexiconOutput implements Intrinsic {
39
69
  * checking on every field it reads (#1047).
40
70
  */
41
71
  readonly _intrinsic: Intrinsic | null;
42
- constructor(ref: AttrRef | Intrinsic | string, name: string);
72
+ /**
73
+ * @internal The already-resolved literal (string/number/boolean) when
74
+ * constructed from neither an AttrRef nor an Intrinsic — non-null exactly
75
+ * when `_intrinsic` is null AND `sourceAttribute` is null. There is no
76
+ * source entity or attribute to reference, so `getOutputValue()` returns
77
+ * this value verbatim rather than fabricating a `Fn::GetAtt` out of an
78
+ * unset attribute (chant #1121). Readable outside the class for the same
79
+ * reason as `_intrinsic`/`_sourceParent` above.
80
+ */
81
+ readonly _literalValue: LexiconOutputLiteral | null;
82
+ constructor(ref: AttrRef | Intrinsic | LexiconOutputLiteral, name: string);
43
83
  /**
44
84
  * Set the source entity logical name.
45
85
  * Called during build when entity names are resolved.
@@ -48,6 +88,7 @@ export declare class LexiconOutput implements Intrinsic {
48
88
  _setSourceEntity(name: string): void;
49
89
  /**
50
90
  * Returns the CloudFormation Output Value for this output.
91
+ * For a literal output: the resolved value itself, verbatim.
51
92
  * For AttrRef-based outputs: emits Fn::GetAtt.
52
93
  * For Intrinsic-based outputs: delegates to the intrinsic's toJSON().
53
94
  */
@@ -71,7 +112,8 @@ export declare class LexiconOutput implements Intrinsic {
71
112
  };
72
113
  }
73
114
  /**
74
- * Create a LexiconOutput from an AttrRef or Intrinsic and a user-provided output name.
115
+ * Create a LexiconOutput from an AttrRef, an Intrinsic, or an already-
116
+ * resolved literal, and a user-provided output name.
75
117
  *
76
118
  * Usage with AttrRef:
77
119
  * ```ts
@@ -82,10 +124,24 @@ export declare class LexiconOutput implements Intrinsic {
82
124
  * ```ts
83
125
  * const solrUrl = output(Sub`http://${Ref(albDnsName)}/solr`, "solrUrl");
84
126
  * ```
127
+ *
128
+ * Usage with a literal (chant #1121) — a real value the caller already
129
+ * computed, not a reference:
130
+ * ```ts
131
+ * const apiVersion = output("v1", "ApiVersion");
132
+ * ```
85
133
  */
86
- export declare function output(ref: AttrRef | Intrinsic | string, name: string): LexiconOutput;
134
+ export declare function output(ref: AttrRef | Intrinsic | LexiconOutputLiteral, name: string): LexiconOutput;
87
135
  /**
88
- * Type guard to check if a value is a LexiconOutput
136
+ * Type guard to check if a value is a LexiconOutput.
137
+ *
138
+ * Structural, not `instanceof` (chant #1122) — keys off {@link
139
+ * LEXICON_OUTPUT_MARKER}, a global symbol, so it holds across separately-
140
+ * loaded copies of chant-core the way `instanceof` does not. Every caller
141
+ * (`collect.ts`, `build.ts`, `graph-ir.ts`, `entity-wire-codec.ts`) reads
142
+ * only own-prototype members off the result (`outputName`, `_sourceParent`,
143
+ * `_setSourceEntity()`, `getOutputValue()`), all of which work identically
144
+ * on a cross-copy instance.
89
145
  */
90
146
  export declare function isLexiconOutput(value: unknown): value is LexiconOutput;
91
147
  //# sourceMappingURL=lexicon-output.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lexicon-output.d.ts","sourceRoot":"","sources":["../src/lexicon-output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAW5D;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC7C,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAG,IAAI,CAAU;IAC5C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI,CAAC;gBAE1B,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM;IA8B3D;;;;OAIG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;OAIG;IACH,cAAc,IAAI,OAAO;IAOzB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa;IAO5D,MAAM,IAAI;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE;CAGtC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAErF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAEtE"}
1
+ {"version":3,"file":"lexicon-output.d.ts","sourceRoot":"","sources":["../src/lexicon-output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;0CAE0C;AAC1C,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,qBAAqB,eAAoC,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAW5D;AAED;;;;;;;;;;GAUG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC7C,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAG,IAAI,CAAU;IAC5C;;uCAEmC;IACnC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,EAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI,CAAC;IACtC;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,EAAE,oBAAoB,GAAG,IAAI,CAAC;gBAExC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,oBAAoB,EAAE,IAAI,EAAE,MAAM;IAwEzE;;;;OAIG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;;OAKG;IACH,cAAc,IAAI,OAAO;IAUzB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa;IAO5D,MAAM,IAAI;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE;CAGtC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,oBAAoB,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAEnG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAOtE"}
@@ -83,6 +83,12 @@ export declare const DEFAULT_CONFIG: LintConfig;
83
83
  * then falls back to `chant.config.json` (legacy LintConfig format).
84
84
  * Returns default configuration if neither exists.
85
85
  *
86
+ * chant #1113 — the `chant.config.ts` branch executes project-authored code,
87
+ * so it goes through `../config-sandbox.ts` like every other config load
88
+ * rather than `require`-ing the file itself. Unarmed (which is every `chant
89
+ * lint` invocation today — `lint` has no `--sandbox` flag) that is the
90
+ * identical `createRequire` path this used before, moved one module over.
91
+ *
86
92
  * @param dir - Directory path to search for config file
87
93
  * @returns Loaded and merged configuration, or default config if not found
88
94
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lint/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AASnD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAiBlD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAS3B,CAAC;AAkGH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,gBAAgB,CAsBnE;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,UAG5B,CAAC;AA0HF;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAoClD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAkBpG"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lint/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AASnD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAiBlD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAS3B,CAAC;AAkGH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,gBAAgB,CAsBnE;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,UAG5B,CAAC;AA0HF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAkClD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAkBpG"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The single place chant imports a project's `lint.policies` module **in the
3
+ * CLI's own process** — and the flag that says it may not.
4
+ *
5
+ * The third member of the same family as `../discovery/import.ts`'s
6
+ * `importModule` (project source) and `../config-import.ts`'s
7
+ * `importConfigModule` (`chant.config.ts`): one narrow module whose only job is
8
+ * "execute project-authored code here", so that "did any project code run in
9
+ * this process?" has one place to look and one place to instrument — see
10
+ * `examples/sandbox-execution-boundary.test.ts`, which spies on all three.
11
+ *
12
+ * Before chant #1131 `./policy.ts` called `await import(resolved)` inline,
13
+ * which is why the corpus boundary gate could not see it even after #1113 put
14
+ * the config behind the boundary: there was nothing named to wrap.
15
+ *
16
+ * The armed flag lives here rather than in `./policy-sandbox.ts` (which owns
17
+ * the *decision* and documents the reasoning, and re-exports these three
18
+ * functions as its public surface) for one structural reason: `./policy.ts`
19
+ * needs to consult it, `./policy-sandbox.ts` needs to call `./policy.ts`, and a
20
+ * flag on a leaf module with no imports of its own breaks what would otherwise
21
+ * be an import cycle. It also puts the check on the narrowest possible thing —
22
+ * the function that actually executes project code — rather than on a caller
23
+ * that might forget to ask.
24
+ */
25
+ /**
26
+ * Arm sandboxed policy execution for the rest of this process. See
27
+ * `./policy-sandbox.ts` for what arms it and why it is a process mode rather
28
+ * than a threaded option. Idempotent; there is deliberately no disarm.
29
+ */
30
+ export declare function armSandboxPolicyExecution(): void;
31
+ /** Whether {@link armSandboxPolicyExecution} has been called. */
32
+ export declare function isSandboxPolicyExecutionArmed(): boolean;
33
+ /** Test-only reset — vitest gives each test file its own module registry, so this exists for suites that arm and disarm within one file. */
34
+ export declare function resetSandboxPolicyExecutionForTests(): void;
35
+ /** The shape a policy module evaluates to — chant reads its exported values and keeps the `PostSynthCheck`-shaped ones. */
36
+ export type PolicyModuleNamespace = Record<string, unknown>;
37
+ /**
38
+ * Import a policy module into THIS process and return its module namespace.
39
+ * Node's ESM registry caches it, so repeated loads within one CLI invocation
40
+ * evaluate the file once.
41
+ *
42
+ * Refuses while armed. Under `--sandbox` the policy modules are imported inside
43
+ * a child process (`../discovery/sandbox/policy-run.ts`); arriving here anyway
44
+ * means something is about to execute project-authored code in the CLI's own
45
+ * process, which is exactly what the flag promises does not happen. Falling
46
+ * through would make `--sandbox` mean less than it says with nothing visible to
47
+ * notice, so this throws instead.
48
+ */
49
+ export declare function importPolicyModule(policyPath: string): Promise<PolicyModuleNamespace>;
50
+ //# sourceMappingURL=policy-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-import.d.ts","sourceRoot":"","sources":["../../src/lint/policy-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,iEAAiE;AACjE,wBAAgB,6BAA6B,IAAI,OAAO,CAEvD;AAED,4IAA4I;AAC5I,wBAAgB,mCAAmC,IAAI,IAAI,CAE1D;AAED,2HAA2H;AAC3H,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAO3F"}
@@ -0,0 +1,89 @@
1
+ import { type PostSynthCheck, type PostSynthContext, type PostSynthDiagnostic } from "./post-synth.js";
2
+ import { armSandboxPolicyExecution, isSandboxPolicyExecutionArmed, resetSandboxPolicyExecutionForTests } from "./policy-import.js";
3
+ import type { EncodablePolicyBuildResult } from "../discovery/sandbox/policy-wire.js";
4
+ /**
5
+ * chant #1131 — decides WHERE a project's `lint.policies` checks run.
6
+ *
7
+ * A policy is project-authored code. Every other piece of project code moved
8
+ * behind the `--sandbox` boundary in chant #1045 (run-fallback source), #1093
9
+ * (composite factories, constructors, intrinsic tags) and #1113
10
+ * (`chant.config.ts`), and all three had to leave this one out: the config
11
+ * declares its policies as *paths*, so putting the config behind the boundary
12
+ * did not put them there with it. `chant build` imported each policy module and
13
+ * called its `check` function in the CLI's own process, after discovery was
14
+ * over, with the CLI's filesystem, network, environment and process-spawn
15
+ * access. This module closes it.
16
+ *
17
+ * ## Why an armed process mode rather than a threaded option
18
+ *
19
+ * The same reason `../config-sandbox.ts` gives. `./policy.ts`'s
20
+ * `loadPolicyChecks` is exported from chant-core's public surface and called
21
+ * from more than one place (`../cli/commands/build.ts` for a build, and
22
+ * `evaluateProjectPolicies` for the `policyGate` Op step). Threading a
23
+ * `sandbox` flag to each is fail-OPEN: miss one and project code executes in
24
+ * the CLI process with nothing to notice. Arming the process once, before any
25
+ * policy is loaded, is fail-CLOSED — `loadPolicyChecks` REFUSES while armed, so
26
+ * a call site nobody remembered gets a loud error rather than a silent
27
+ * execution.
28
+ *
29
+ * ## What arms it
30
+ *
31
+ * Both ways of turning sandboxing on, unlike `../config-sandbox.ts`. That
32
+ * asymmetry is not an oversight: the config has a bootstrap limit (reading
33
+ * `build.sandbox` out of `chant.config.ts` means running it, so only the CLI
34
+ * flag, known before any config is touched, can cover the config's own
35
+ * evaluation). Policies have no such limit — they are loaded long after the
36
+ * config is known — so `build.sandbox: true` in a project's config sandboxes
37
+ * them just as `--sandbox` does, and `../cli/commands/build.ts` arms this from
38
+ * the RESOLVED value.
39
+ *
40
+ * There is deliberately no disarm: a security mode that can be turned off
41
+ * partway through a process is not one.
42
+ */
43
+ /**
44
+ * The mode itself lives on `./policy-import.ts` — the leaf module that actually
45
+ * performs an in-process policy import, so the refusal sits on the narrowest
46
+ * possible thing and `./policy.ts` can consult it without importing this file
47
+ * (which imports `./policy.ts`). Re-exported here because this is where the
48
+ * decision is documented and where callers look.
49
+ *
50
+ * `armSandboxPolicyExecution` is called from `../cli/commands/build.ts` once
51
+ * `build.sandbox`/`--sandbox` has resolved, and from `../cli/main.ts` off the
52
+ * parsed flag.
53
+ */
54
+ export { armSandboxPolicyExecution, isSandboxPolicyExecutionArmed, resetSandboxPolicyExecutionForTests };
55
+ export interface ProjectPolicyRun {
56
+ /** `lint.policies` as declared in the config — relative paths, resolved against {@link configDir}. */
57
+ policies: readonly string[];
58
+ /** The `chant.config.*` directory (`lint.policies` paths are relative to it), also the child's read allowance. */
59
+ configDir: string;
60
+ /** The merged, serialized build result the checks run over. */
61
+ buildResult: EncodablePolicyBuildResult & PostSynthContext["buildResult"];
62
+ /** `--env`, else `ownership.env`. Becomes `ctx.env`. */
63
+ env?: string;
64
+ /**
65
+ * Checks the caller already loaded into THIS process, before the build ran.
66
+ *
67
+ * `chant build` has always loaded `lint.policies` up front rather than at the
68
+ * point of use, so a policy path that doesn't resolve fails the command
69
+ * immediately — including when the build itself goes on to fail, which is
70
+ * exactly when a typo'd path would otherwise go unnoticed. Preserving that
71
+ * for the unsandboxed path is the whole reason this field exists.
72
+ *
73
+ * Ignored when armed: under `--sandbox` there is nothing loaded here to pass,
74
+ * and `loadPolicyChecks` refuses outright.
75
+ */
76
+ preloaded?: PostSynthCheck[];
77
+ }
78
+ /**
79
+ * Run a project's organizational policy checks over a finished build and return
80
+ * their diagnostics. Sandboxed in a post-merge child when armed, in-process
81
+ * otherwise.
82
+ *
83
+ * The unarmed path is byte-for-byte what `chant build` has always done: load
84
+ * the modules, hand every check one `PostSynthContext`, concatenate what they
85
+ * return. The armed path does the same thing on the other side of a process
86
+ * boundary — see `../discovery/sandbox/policy-run.ts`.
87
+ */
88
+ export declare function runProjectPolicies(run: ProjectPolicyRun): Promise<PostSynthDiagnostic[]>;
89
+ //# sourceMappingURL=policy-sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-sandbox.d.ts","sourceRoot":"","sources":["../../src/lint/policy-sandbox.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,mCAAmC,EACpC,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;;;GAUG;AACH,OAAO,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,mCAAmC,EAAE,CAAC;AAEzG,MAAM,WAAW,gBAAgB;IAC/B,sGAAsG;IACtG,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,kHAAkH;IAClH,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,WAAW,EAAE,0BAA0B,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAAC;IAC1E,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAoB9F"}
@@ -1,5 +1,16 @@
1
1
  import type { PostSynthCheck, PostSynthDiagnostic } from "./post-synth.js";
2
- /** Load project policy checks (one or more `PostSynthCheck` exports) from files. */
2
+ /**
3
+ * Load project policy checks (one or more `PostSynthCheck` exports) from files,
4
+ * **into this process**.
5
+ *
6
+ * chant #1131 — refuses while `./policy-sandbox.ts` is armed. Under `--sandbox`
7
+ * the policy modules are imported and their checks run inside a child process
8
+ * (`runProjectPolicies`); reaching this function anyway means a call site is
9
+ * about to execute project-authored code in the CLI's own process, which is
10
+ * precisely the thing the flag promises does not happen. Failing loudly is the
11
+ * only honest option — falling through would make `--sandbox` mean less than it
12
+ * says without anything visible to notice.
13
+ */
3
14
  export declare function loadPolicyChecks(paths: string[], configDir: string): Promise<PostSynthCheck[]>;
4
15
  export interface PolicyEvaluation {
5
16
  /** All policy diagnostics (errors + warnings). */
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/lint/policy.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExE,oFAAoF;AACpF,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAiBpG;AAED,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,2EAA2E;IAC3E,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8B5B"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/lint/policy.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGxE;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAuBpG;AAED,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,2EAA2E;IAC3E,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8B5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"stack-output.d.ts","sourceRoot":"","sources":["../src/stack-output.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,mBAAmB,eAAkC,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC;IACrC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB;mDAC+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAgBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAOlE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,GAAG,SAAS,EACxB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACjC,WAAW,CAuBb"}
1
+ {"version":3,"file":"stack-output.d.ts","sourceRoot":"","sources":["../src/stack-output.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAG1D;;GAEG;AACH,eAAO,MAAM,mBAAmB,eAAkC,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC;IACrC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB;mDAC+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAqBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAOlE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,GAAG,SAAS,EACxB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACjC,WAAW,CAiCb"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.24.0",
3
+ "version": "0.26.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",