/** * chant #1113 — what a `chant.config.ts` may contain if it is to be evaluated * inside the sandbox boundary and handed back to the CLI as data. * * Under `--sandbox` the config file is evaluated in a child process (see * `./config-run.ts`), so the only thing that can come back is what survives a * process boundary: JSON. Node's IPC channel serializes with `JSON.stringify` * by default, and `JSON.stringify` is *lossy without complaining* — a function * property vanishes, a `Date` becomes a string, a `Map` becomes `{}`, `NaN` * becomes `null`. Silently handing the CLI a config that differs from the one * the project wrote is the worst available outcome for a security feature, so * this module walks the value FIRST and reports every offending key path. * `./config-run.ts` turns a non-empty report into a build error that names the * keys; nothing is ever dropped quietly. * * This module is bundled INTO the generated config driver (`./driver.ts`'s * `generateConfigDriverSource`) and runs inside the sandboxed child, next to * the project code it is inspecting — so it must not import anything, and must * not touch the filesystem, the environment or the process. * * chant #1131 reuses the same walk for the OTHER direction: a `lint.policies` * check runs inside a sandboxed child and its `PostSynthDiagnostic[]` has to * come back as data (`./policy-wire.ts`). That is the same "JSON is lossy * without complaining" problem with a different root value, so the walk is * exported as {@link scanValueWireSafety} rather than copied. * * ## What `ChantConfig` legally holds * * Every field of `ChantConfig` (`../../config.ts`) is JSON data: string arrays * (`lexicons`, `capabilities`), strings (`sourceDir`), an array of strings or * plain `{ name, endpoint }` objects (`environments`, #1166), nested plain * objects of strings/booleans (`ownership`, `build`, `release`, `sbom`, * `signing`, `vulnPolicy`), arrays of plain objects (`stacks`), and records of * plain objects (`buildParams`). `lint` is a `LintConfig`, whose rule values * are a severity string or a `[severity, options]` tuple, and whose `plugins` * / `policies` are file *paths* — chant loads those modules itself, they are * not functions embedded in the config. So the declared type admits nothing * that fails the check below. * * The one way to get there is `ChantConfigSchema`'s `.passthrough()`, which * accepts unknown extra keys of any type (that is how a lexicon extends the * config — `temporal:` in the temporal lexicon's `TemporalChantConfig`, itself * pure data). A project that parks a function under such a key gets a clear * error naming it, rather than a config that silently lost it. * * ## The one accepted lossy case: `undefined` object properties * * `{ sourceDir: undefined }` and `{}` are indistinguishable to every reader of * `ChantConfig` — each field is optional and every resolver tests * `config.x === undefined` / `?.` — so an `undefined`-valued property is * dropped rather than rejected, exactly as omitting the key would be. An * `undefined` inside an ARRAY is a different story (`JSON.stringify` rewrites * it to `null`, changing the element), and is reported. */ /** One value in the config that cannot cross the sandbox boundary as data. */ export interface ConfigWireOffender { /** Dotted/bracketed path from the config root, e.g. `lint.rules.foo` or `stacks[0].name`. */ path: string; /** What was found there, phrased for an error message (e.g. `a function`, `a Date`). */ found: string; } /** * chant #1131 — report every value ANYWHERE in `value` that cannot cross the * sandbox boundary as JSON, with paths rooted at `rootPath`. * * {@link scanConfigWireSafety} is the config-shaped entry point (it tolerates a * module namespace object at the root); this one takes the value as given, so * an array root (`diagnostics`) or a plain object root both work. Same rules, * same `undefined`-object-property allowance — see the module doc. */ export declare function scanValueWireSafety(value: unknown, rootPath?: string): ConfigWireOffender[]; /** * Report every value in `config` that cannot cross the sandbox boundary as * JSON. An empty array means a `JSON.parse(JSON.stringify(config))` round-trip * preserves the configuration exactly (modulo `undefined` object properties, * which are dropped — see the module doc). * * `config` itself may be a module namespace object (`await import(...)` with * no `default` export), which is not a plain object; its own enumerable keys * are walked the same way rather than being reported wholesale. */ export declare function scanConfigWireSafety(config: unknown): ConfigWireOffender[]; /** Render a {@link ConfigWireOffender} list as the body of a build error — one line per offending key, most specific information first. */ export declare function formatConfigWireOffenders(configPath: string, offenders: readonly ConfigWireOffender[]): string; //# sourceMappingURL=config-wire.d.ts.map