@pho9ubenaa/siro 0.3.0 → 0.4.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/index.d.mts CHANGED
@@ -1,18 +1,22 @@
1
1
  import * as vb from "valibot";
2
2
 
3
+ //#region src/domain/entities/config-value.d.ts
4
+ declare const CODEC_KINDS: readonly ["json", "npmrc", "toml", "yaml"];
5
+ type CodecKind = (typeof CODEC_KINDS)[number];
6
+ /** Scalar value that can be written back to a config file. */
7
+ type ConfigValue = string | number | boolean;
8
+ /** Parsed keys are unvalidated; each rule narrows the values it reads. */
9
+ interface ParsedConfig {
10
+ readonly [key: string]: unknown;
11
+ }
12
+ /** A (possibly nested) key path, guaranteed to have at least one segment. */
13
+ type KeyPath = readonly [string, ...string[]];
14
+ /** Parser values may include nested arrays and TOML dates. */
15
+ type ConfigReadValue = unknown;
16
+ /** Read an own key path; absent or non-mapping parents yield undefined. */
17
+ declare const getByPath: (config: ParsedConfig, keyPath: KeyPath) => ConfigReadValue;
18
+ //#endregion
3
19
  //#region src/shared/paths.d.ts
4
- /**
5
- * Branded path types. Surface the distinction between
6
- * - `AbsPath`: absolute filesystem paths handed to the FS boundary
7
- * (`FileSystem.readText` etc.), and
8
- * - `RelPath`: paths relative to a repo root, accepted by
9
- * `RepoContext` and resolved via `resolveIn`.
10
- *
11
- * The brand is a structural tag with no runtime footprint — the cast in
12
- * `asAbsPath` / `asRelPath` is the only place either type is minted, so
13
- * passing a raw `string` to an FS or repo API now requires the caller to
14
- * declare intent rather than silently mixing the two flavours.
15
- */
16
20
  declare const AbsPathBrand: unique symbol;
17
21
  declare const RelPathBrand: unique symbol;
18
22
  type AbsPath = string & {
@@ -21,10 +25,8 @@ type AbsPath = string & {
21
25
  type RelPath = string & {
22
26
  readonly [RelPathBrand]: true;
23
27
  };
24
- /** Tag a string as absolute. The caller vouches for the shape. */
25
- declare const asAbsPath: (path: string) => AbsPath;
26
- /** Tag a string as repo-root-relative. The caller vouches for the shape. */
27
- declare const asRelPath: (path: string) => RelPath;
28
+ declare const asAbsPath: (value: string) => AbsPath;
29
+ declare const asRelPath: (value: string) => RelPath;
28
30
  //#endregion
29
31
  //#region src/domain/ports/file-system.d.ts
30
32
  /** IO boundary: swap in memfs (or any other backend) for tests. */
@@ -33,54 +35,6 @@ interface FileSystem {
33
35
  exists: (path: AbsPath) => boolean;
34
36
  }
35
37
  //#endregion
36
- //#region src/adapters/node-file-system.d.ts
37
- declare const nodeFileSystem: FileSystem;
38
- //#endregion
39
- //#region src/domain/ports/io.d.ts
40
- /** Output sink for commands; injectable so tests can drive a string buffer. */
41
- interface IO {
42
- stdout: (line: string) => void;
43
- stderr: (line: string) => void;
44
- }
45
- //#endregion
46
- //#region src/adapters/node-io.d.ts
47
- declare const nodeIO: IO;
48
- //#endregion
49
- //#region src/domain/entities/config-value.d.ts
50
- declare const CODEC_KINDS: readonly ["json", "npmrc", "toml", "yaml"];
51
- type CodecKind = (typeof CODEC_KINDS)[number];
52
- /** Scalar value that can be written back to a config file. */
53
- type ConfigValue = string | number | boolean;
54
- /** Scalar value as it appears when reading (codecs may produce `null`). */
55
- type ConfigScalar = ConfigValue | null;
56
- /** Recursive, structurally typed view of a parsed config file. */
57
- interface ParsedConfig {
58
- readonly [key: string]: ConfigScalar | readonly ConfigScalar[] | ParsedConfig;
59
- }
60
- /** A (possibly nested) key path, guaranteed to have at least one segment. */
61
- type KeyPath = readonly [string, ...string[]];
62
- /** A single key to set. */
63
- interface KeyAssignment {
64
- readonly keyPath: KeyPath;
65
- readonly value: ConfigValue;
66
- }
67
- /**
68
- * Value a rule's `check` saw at the target key, as returned by `getByPath`.
69
- * Runtime caveat: YAML/TOML parsers can yield host values (e.g. `Date`)
70
- * nested inside `ParsedConfig` even though the type does not name them —
71
- * compare timestamps by `valueOf()`, not by type narrowing on this union.
72
- */
73
- type ConfigReadValue = ConfigScalar | readonly ConfigScalar[] | ParsedConfig | undefined;
74
- /**
75
- * Look up a nested value by key path; `undefined` if any segment is missing.
76
- *
77
- * Part of the public surface (re-exported from `src/index.ts`): embedders
78
- * writing custom rules receive the same `config: ParsedConfig` shape that
79
- * built-in rules see, so they need the canonical traversal helper rather
80
- * than re-implementing `null`-vs-missing semantics per rule.
81
- */
82
- declare const getByPath: (config: ParsedConfig, keyPath: KeyPath) => ConfigScalar | readonly ConfigScalar[] | ParsedConfig | undefined;
83
- //#endregion
84
38
  //#region src/domain/entities/pms.d.ts
85
39
  /**
86
40
  * Single source of truth for package managers and severities.
@@ -94,25 +48,25 @@ type Severity = (typeof SEVERITIES)[number];
94
48
  declare const isPM: (value: string) => value is PM;
95
49
  declare const isSeverity: (value: string) => value is Severity;
96
50
  //#endregion
51
+ //#region src/domain/entities/project-type.d.ts
52
+ declare const PROJECT_TYPES: readonly ["application", "package"];
53
+ type ProjectType = (typeof PROJECT_TYPES)[number];
54
+ //#endregion
97
55
  //#region src/domain/schemas/package-json.d.ts
98
56
  declare const PackageJsonSchema: vb.LooseObjectSchema<{
99
- readonly files: vb.SchemaWithFallback<vb.OptionalSchema<vb.ArraySchema<vb.StringSchema<undefined>, undefined>, undefined>, undefined>;
100
- readonly name: vb.SchemaWithFallback<vb.OptionalSchema<vb.StringSchema<undefined>, undefined>, undefined>;
101
- readonly packageManager: vb.SchemaWithFallback<vb.OptionalSchema<vb.StringSchema<undefined>, undefined>, undefined>;
102
- readonly private: vb.OptionalSchema<vb.SchemaWithFallback<vb.BooleanSchema<undefined>, true>, undefined>;
103
- readonly publishConfig: vb.SchemaWithFallback<vb.OptionalSchema<vb.LooseObjectSchema<{
104
- readonly access: vb.SchemaWithFallback<vb.OptionalSchema<vb.UnionSchema<[vb.LiteralSchema<"public", undefined>, vb.LiteralSchema<"restricted", undefined>], undefined>, undefined>, undefined>;
105
- }, undefined>, undefined>, undefined>;
106
- readonly trustedDependencies: vb.SchemaWithFallback<vb.OptionalSchema<vb.ArraySchema<vb.StringSchema<undefined>, undefined>, undefined>, undefined>;
57
+ readonly files: vb.OptionalSchema<vb.ArraySchema<vb.StringSchema<undefined>, undefined>, undefined>;
58
+ readonly name: vb.OptionalSchema<vb.StringSchema<undefined>, undefined>;
59
+ readonly packageManager: vb.OptionalSchema<vb.StringSchema<undefined>, undefined>;
60
+ readonly private: vb.OptionalSchema<vb.BooleanSchema<undefined>, undefined>;
61
+ readonly publishConfig: vb.OptionalSchema<vb.LooseObjectSchema<{
62
+ readonly access: vb.OptionalSchema<vb.PicklistSchema<["public", "restricted", "private"], undefined>, undefined>;
63
+ }, undefined>, undefined>;
64
+ readonly trustedDependencies: vb.OptionalSchema<vb.ArraySchema<vb.StringSchema<undefined>, undefined>, undefined>;
107
65
  }, undefined>;
108
66
  type PackageJson = vb.InferOutput<typeof PackageJsonSchema>;
109
67
  //#endregion
110
- //#region src/domain/entities/project-type.d.ts
111
- declare const PROJECT_TYPES: readonly ["application", "package"];
112
- type ProjectType = (typeof PROJECT_TYPES)[number];
113
- //#endregion
114
68
  //#region src/domain/ports/repo-context.d.ts
115
- /** Read-only view of a repository, passed to every rule's `check` and `fix`. */
69
+ /** Read-only view of a repository, passed to every rule's `check`. */
116
70
  interface RepoContext {
117
71
  readonly root: AbsPath;
118
72
  exists: (relPath: RelPath) => boolean;
@@ -120,111 +74,58 @@ interface RepoContext {
120
74
  readonly packageJson: PackageJson | undefined;
121
75
  readonly projectType?: ProjectType;
122
76
  }
77
+ /** Settings read during one evaluation share its parser and cache. */
78
+ interface RuleContext extends RepoContext {
79
+ readConfig: (file: ConfigFileRef) => ParsedConfig;
80
+ }
123
81
  //#endregion
124
82
  //#region src/domain/entities/rule.d.ts
125
- /**
126
- * What a rule binding points at on disk: a parsed config file or an existence
127
- * check (e.g. "a lockfile is committed"). `path` is a branded `RelPath` minted
128
- * once at the ref's definition (CONFIG_FILES), so the readText boundary is
129
- * type-checked and a stray absolute path can't slip in as a string.
130
- */
131
- type ConfigFileRef = {
83
+ interface ConfigFileRef {
132
84
  readonly kind: CodecKind;
133
85
  readonly path: RelPath;
86
+ }
87
+ interface SetKeyOperation {
88
+ readonly op: 'setKey';
89
+ readonly file: ConfigFileRef;
90
+ readonly keyPath: KeyPath;
91
+ readonly value: ConfigValue;
92
+ }
93
+ /** A check chooses one remedy for the state it observed. siro does not apply it. */
94
+ type Remediation = {
95
+ readonly kind: 'automatic';
96
+ readonly operations: readonly [SetKeyOperation, ...SetKeyOperation[]];
97
+ readonly steps?: never;
134
98
  } | {
135
- readonly kind: 'fileGlob';
136
- readonly path: RelPath;
99
+ readonly kind: 'manual';
100
+ readonly steps: readonly [string, ...string[]];
101
+ readonly operations?: never;
137
102
  };
138
- /** Result of evaluating a single rule binding against a repo. */
139
103
  type CheckStatus = {
140
104
  readonly state: 'ok';
105
+ } | {
106
+ readonly state: 'na';
141
107
  } | {
142
108
  readonly state: 'violation';
143
- readonly message: string;
109
+ readonly message: string; /** Override the primary file when the violation concerns another input. */
110
+ readonly file?: RelPath;
144
111
  readonly expected?: ConfigValue;
145
- readonly actual?: ConfigReadValue;
146
- /**
147
- * Dynamic severity for this specific violation, overriding both
148
- * {@link AutoRuleBinding.severity} and {@link Rule.severity}. Lets a
149
- * `check` distinguish "unset but PM-default safe" (advisory) from
150
- * "explicitly weakened" (full severity). A user `rules` override in
151
- * config still wins (see `applyConfig`).
152
- */
112
+ readonly actual?: ConfigReadValue; /** User configuration takes precedence over this per-result severity. */
153
113
  readonly severity?: Severity;
154
- /**
155
- * Manual remediation steps surfaced verbatim on the finding. Lets a
156
- * `check` signal "the setKey fix ops cannot resolve this state; the
157
- * user has to intervene" — e.g. when an explicit user override would
158
- * have to be deleted first. When non-empty, `Finding.fix` is emitted
159
- * empty so an external fixer never writes ops the user's existing
160
- * config would defeat.
161
- */
162
- readonly manualSteps?: readonly string[];
163
- } | {
164
- readonly state: 'na';
165
- };
166
- /** A remediation step produced by a rule's `fix`. */
167
- type FixOp = {
168
- readonly op: 'setKey';
169
- readonly file: ConfigFileRef;
170
- readonly keyPath: KeyPath;
171
- readonly value: ConfigValue;
172
- } | {
173
- readonly op: 'ensureFileTracked';
174
- readonly file: ConfigFileRef;
175
- readonly message: string;
176
- } | {
177
- readonly op: 'note';
178
- readonly message: string;
179
- readonly file?: ConfigFileRef;
114
+ readonly remediation?: Remediation;
180
115
  };
181
- /**
182
- * - `auto`: `fix` produces setKey ops an external fixer can apply
183
- * mechanically (surfaced via `Finding.fix`; see docs/json-output.md).
184
- * - `advisory`: `fix` only produces notes/ensureFileTracked hints.
185
- */
186
- type FixKind = 'auto' | 'advisory';
187
116
  /** Display-only package-manager version metadata. */
188
117
  interface VersionNote {
189
118
  readonly configAvailableSince?: string;
190
119
  readonly defaultSafeSince?: string;
191
120
  readonly note?: string;
192
121
  }
193
- type SetKeyOp = Extract<FixOp, {
194
- op: 'setKey';
195
- }>;
196
- type AdvisoryOp = Extract<FixOp, {
197
- op: 'note' | 'ensureFileTracked';
198
- }>;
199
- interface AutoRuleBinding {
200
- readonly file: ConfigFileRef;
201
- readonly fixKind: 'auto';
202
- /** Official package-manager doc URL for the setting this binding writes. */
203
- readonly docs?: string;
204
- /**
205
- * Per-binding severity. When set, it shadows {@link Rule.severity} for this
206
- * PM only — used when a package manager's safe default already mitigates
207
- * the threat (so the binding is informational) while another PM with the
208
- * same rule still warrants the rule-wide level. A user config `rules`
209
- * override always wins over both.
210
- */
211
- readonly severity?: Severity;
212
- readonly versionNote?: VersionNote;
213
- check: (ctx: RepoContext, config: ParsedConfig) => CheckStatus;
214
- fix: (ctx: RepoContext) => readonly SetKeyOp[];
215
- }
216
- interface AdvisoryRuleBinding {
217
- readonly file: ConfigFileRef;
218
- readonly fixKind: 'advisory';
219
- /** Official package-manager doc URL for the setting this binding describes. */
122
+ interface RuleBinding {
123
+ readonly file?: ConfigFileRef;
220
124
  readonly docs?: string;
221
- /** See {@link AutoRuleBinding.severity}. */
222
125
  readonly severity?: Severity;
223
126
  readonly versionNote?: VersionNote;
224
- check: (ctx: RepoContext, config: ParsedConfig) => CheckStatus;
225
- fix: (ctx: RepoContext) => readonly AdvisoryOp[];
127
+ check: (ctx: RuleContext, config: ParsedConfig) => CheckStatus;
226
128
  }
227
- type RuleBinding = AutoRuleBinding | AdvisoryRuleBinding;
228
129
  /** A package-manager-agnostic security intent, realized per PM via `bindings`. */
229
130
  interface Rule<Id extends string = string> {
230
131
  readonly id: Id;
@@ -237,6 +138,18 @@ interface Rule<Id extends string = string> {
237
138
  /** Absence of a PM key means the rule does not apply (N/A) to that PM. */
238
139
  readonly bindings: Partial<Record<PM, RuleBinding>>;
239
140
  }
141
+ declare const defineRule: <const Id extends string>(rule: Rule<Id>) => Rule<Id>;
142
+ //#endregion
143
+ //#region src/domain/builtin-rules.d.ts
144
+ declare const rules: readonly [Rule<"advisory-check">, Rule<"approved-git-repos">, Rule<"audit-suppression">, Rule<"block-auto-install">, Rule<"block-exotic-subdeps">, Rule<"bun-security-scanner">, Rule<"checksum-verification">, Rule<"commit-lockfile">, Rule<"dependency-overrides">, Rule<"disable-lifecycle-scripts">, Rule<"enforce-strict-ssl">, Rule<"files-field">, Rule<"frozen-lockfile">, Rule<"frozen-store">, Rule<"hardened-mode">, Rule<"minimum-release-age">, Rule<"named-registries">, Rule<"paranoid-mode">, Rule<"patched-dependencies">, Rule<"pin-exact-versions">, Rule<"provenance">, Rule<"publish-access">, Rule<"store-server">, Rule<"strict-allow-scripts">, Rule<"strict-release-age">, Rule<"strict-store-integrity">, Rule<"trust-policy">];
145
+ type BuiltinRuleId = (typeof rules)[number]['id'];
146
+ //#endregion
147
+ //#region src/domain/ports/io.d.ts
148
+ /** Output sink for commands; injectable so tests can drive a string buffer. */
149
+ interface IO {
150
+ stdout: (line: string) => void;
151
+ stderr: (line: string) => void;
152
+ }
240
153
  //#endregion
241
154
  //#region src/domain/entities/lint-result.d.ts
242
155
  interface Finding {
@@ -245,22 +158,7 @@ interface Finding {
245
158
  readonly severity: Severity;
246
159
  readonly message: string;
247
160
  readonly file?: string;
248
- readonly fixable: boolean;
249
- /**
250
- * Machine-readable remediation: the binding's fix ops, verbatim. Empty
251
- * when `manualSteps` is present (writing the ops would be defeated by the
252
- * user state that produced the steps). Advisory bindings contribute their
253
- * `note` / `ensureFileTracked` ops here so external fixers can surface
254
- * them. Part of the json output contract — see docs/json-output.md.
255
- */
256
- readonly fix: readonly FixOp[];
257
- /** Manual remediation steps, verbatim from the check (see CheckStatus). */
258
- readonly manualSteps?: readonly string[];
259
- /**
260
- * Pinned to {@link ConfigValue} (no `null`) so it stays in lockstep with
261
- * `CheckStatus.violation.expected`. Widening to ConfigScalar would have
262
- * advertised a `null` outcome that no current rule can produce.
263
- */
161
+ readonly remediation?: Remediation;
264
162
  readonly expected?: ConfigValue;
265
163
  readonly actual?: ConfigReadValue;
266
164
  /** Official PM doc anchor for the setting this finding is about, if any. */
@@ -272,32 +170,54 @@ interface LintResult {
272
170
  }
273
171
  //#endregion
274
172
  //#region src/domain/ports/reporter.d.ts
275
- /**
276
- * Renderer from `LintResult` to user-facing output.
277
- *
278
- * Reporters never touch the filesystem and never spawn processes — every
279
- * output byte flows through the injected `IO` port. They MAY however
280
- * consult `process.env` for environmental shape (TTY colour support,
281
- * NO_COLOR / FORCE_COLOR, CI detection) because that information has no
282
- * `IO`-port equivalent and treating it as I/O would force the application
283
- * layer to thread a snapshot through every call site for a value the
284
- * adapter can read in a single line.
285
- *
286
- * Implementations live in the adapter layer (src/adapters/reporters/),
287
- * so the env access stays out of the domain.
288
- */
289
173
  interface Reporter<Name extends string = string> {
290
174
  readonly name: Name;
291
175
  format: (result: LintResult, io: IO) => void;
292
176
  }
177
+ //#endregion
178
+ //#region src/domain/entities/siro-config.d.ts
179
+ /** Per-rule setting. `'off'` disables; a Severity overrides the default level. */
180
+ type RuleSetting = Severity | 'off';
293
181
  /**
294
- * Structural guard for an embedder-supplied reporter. The `Reporter` contract
295
- * is compile-time only (`defineConfig` / typed options), so a hand-written JS
296
- * config or a dynamically-built object can still pass a malformed value; this
297
- * lets each boundary reject it with its own error type before `format` is
298
- * called on something that isn't a function.
182
+ * User-facing config returned by `defineConfig` in `siro.config.{ts,mjs,js}`.
183
+ *
184
+ * defineConfig({
185
+ * pms: ['npm', 'pnpm'], // restrict detection
186
+ * rules: { provenance: 'off' }, // disable / override severity
187
+ * customRules: [myRule], // extend
188
+ * reporters: [mySarifReporter], // extend
189
+ * })
299
190
  */
300
- declare const isReporterShape: (value: unknown) => value is Reporter;
191
+ interface SiroConfig {
192
+ readonly pms?: readonly PM[];
193
+ readonly projectType?: ProjectType;
194
+ readonly rules?: Readonly<Partial<Record<BuiltinRuleId | (string & Record<never, never>), RuleSetting>>>;
195
+ readonly customRules?: readonly Rule[];
196
+ readonly reporters?: readonly Reporter[];
197
+ }
198
+ /** Identity helper for type-checked config files. */
199
+ declare const defineConfig: (config: SiroConfig) => SiroConfig;
200
+ //#endregion
201
+ //#region src/application/lint.d.ts
202
+ interface LintOptions {
203
+ readonly cwd: AbsPath;
204
+ readonly fs?: FileSystem;
205
+ readonly pm?: PM;
206
+ readonly projectType?: ProjectType;
207
+ /** Explicit configuration; the library never imports files from the target repository. */
208
+ readonly config?: SiroConfig;
209
+ }
210
+ declare const lint: (options: LintOptions) => LintResult;
211
+ //#endregion
212
+ //#region src/adapters/config-loader.d.ts
213
+ /** Load the first matching config; executable imports always use the real filesystem. */
214
+ declare const loadConfig: (cwd: AbsPath, nodeVersion?: string) => Promise<SiroConfig | undefined>;
215
+ //#endregion
216
+ //#region src/adapters/node-file-system.d.ts
217
+ declare const nodeFileSystem: FileSystem;
218
+ //#endregion
219
+ //#region src/adapters/node-io.d.ts
220
+ declare const nodeIO: IO;
301
221
  //#endregion
302
222
  //#region src/adapters/reporters/github.d.ts
303
223
  /** Emit GitHub Actions workflow commands (annotations on PRs). */
@@ -315,62 +235,17 @@ declare const BUILTINS: readonly [Reporter<"pretty">, Reporter<"json">, Reporter
315
235
  declare const BUILTIN_REPORTER_NAMES: readonly BuiltinReporterName[];
316
236
  /** Literal union of every built-in reporter name. */
317
237
  type BuiltinReporterName = (typeof BUILTINS)[number]['name'];
318
- /** Reporter lookup table — pass an explicit value to keep calls hermetic. */
319
- interface ReporterRegistry {
320
- get: (name: string) => Reporter | undefined;
321
- list: () => readonly string[];
322
- }
323
- /** Build a registry from the builtins plus any extras (later wins on collision). */
324
- declare const createRegistry: (extras?: readonly Reporter[]) => ReporterRegistry;
325
238
  //#endregion
326
239
  //#region src/application/commands/lint.d.ts
327
- interface LintOptions {
328
- /**
329
- * Absolute repo root. Callers are responsible for resolving any relative
330
- * path before branding it; siro's CLI does this in `cli.ts`. Keeping the
331
- * brand here lets the application layer stay free of `node:path`.
332
- */
333
- cwd: AbsPath;
334
- /** Restrict to a single PM; otherwise PMs are auto-detected. */
335
- pm?: PM;
336
- /** Select application or published-package policy; otherwise infer it. */
337
- projectType?: ProjectType;
338
- /** Reporter name or instance; defaults to `pretty`. */
339
- reporter?: string | Reporter;
340
- /** Extra reporters to make available by name (merged with the user config). */
341
- reporters?: readonly Reporter[];
342
- /**
343
- * Programmatic custom rules to evaluate alongside the builtins and any
344
- * `customRules` from the user config. Mirrors `SiroConfig.customRules`
345
- * but is supplied at the call site, so embedders can compose rulesets
346
- * without writing a config file. Ids must be unique across builtins,
347
- * config-supplied custom rules, and this list — collisions throw a
348
- * `ConfigError` (exit 2), matching how `loadConfig` rejects them.
349
- */
350
- customRules?: readonly Rule[];
351
- /** Show (and fail on) findings at or above this severity. */
352
- severity?: Severity;
353
- /**
354
- * Inject a non-default FS (e.g. memfs in tests). Caveat: `siro.config.{ts,mjs,js}`
355
- * is imported from the REAL disk — only the config's existence is probed
356
- * through this FS. A config that lives solely in an injected FS won't load.
357
- */
358
- fs?: FileSystem;
240
+ interface LintCommandOptions extends LintOptions {
241
+ readonly reporter?: string | Reporter;
242
+ readonly severity?: Severity;
359
243
  }
360
- /** `siro lint`: detect PMs, evaluate rules, report findings. */
361
- declare const lintCommand: (options: LintOptions, io: IO) => Promise<number>;
244
+ /** Evaluate and report. Executable config loading belongs to the CLI adapter. */
245
+ declare const lintCommand: (options: LintCommandOptions, io: IO) => Promise<number>;
362
246
  //#endregion
363
247
  //#region src/domain/entities/config-files.d.ts
364
- /**
365
- * Canonical {@link ConfigFileRef}s for every package-manager config file siro
366
- * knows how to read. Centralizing them keeps each rule module from hardcoding
367
- * `kind` / `path` pairs, so renaming a file (or fixing a typo in its path) is a
368
- * single-line change. This is also the one place `RelPath` is minted for a
369
- * config ref — every downstream binding inherits the brand, so no rule needs
370
- * an ad-hoc `asRelPath(ref.path)` cast at the FS boundary.
371
- *
372
- * Add a new entry here when introducing support for a new package manager.
373
- */
248
+ /** Known configuration locations and their parsers. */
374
249
  declare const CONFIG_FILES: {
375
250
  readonly aubeWorkspace: {
376
251
  readonly kind: "yaml";
@@ -402,119 +277,19 @@ declare const CONFIG_FILES: {
402
277
  };
403
278
  };
404
279
  //#endregion
405
- //#region src/domain/entities/signals.d.ts
406
- /**
407
- * Filenames that identify a package manager. `lockfiles[0]` is the
408
- * canonical/preferred one (used by lint messages and error
409
- * messages); the rest are legacy/alternative forms the PM writes itself.
410
- *
411
- * `lockfiles` and `configs` are **detection evidence** — their presence means
412
- * the PM is in use. `reusesLockfiles` is NOT evidence: it lists other PMs'
413
- * lockfile shapes that this PM will reuse rather than writing its own (aube),
414
- * so `commit-lockfile` accepts them but `detectPMs` ignores them — otherwise a
415
- * plain pnpm/npm repo would false-positive as aube. Keeping the two lists
416
- * separate is what lets detection stay a simple "any signal present?" check.
417
- */
418
- interface PMSignals {
419
- readonly lockfiles: readonly [string, ...string[]];
420
- readonly configs: readonly string[];
421
- /** Other PMs' lockfiles this PM reuses; satisfies commit-lockfile, not detection. */
422
- readonly reusesLockfiles?: readonly string[];
423
- }
424
- declare const PM_SIGNALS: {
425
- readonly aube: {
426
- readonly configs: readonly [RelPath];
427
- readonly lockfiles: readonly ["aube-lock.yaml"];
428
- readonly reusesLockfiles: readonly ["pnpm-lock.yaml", "package-lock.json", "npm-shrinkwrap.json", "yarn.lock", "bun.lock", "bun.lockb", "deno.lock"];
429
- };
430
- readonly bun: {
431
- readonly configs: readonly [RelPath];
432
- readonly lockfiles: readonly ["bun.lock", "bun.lockb"];
433
- };
434
- readonly deno: {
435
- readonly configs: readonly [RelPath];
436
- readonly lockfiles: readonly ["deno.lock"];
437
- };
438
- readonly npm: {
439
- readonly configs: readonly [];
440
- readonly lockfiles: readonly ["package-lock.json", "npm-shrinkwrap.json"];
441
- };
442
- readonly pnpm: {
443
- readonly configs: readonly [RelPath];
444
- readonly lockfiles: readonly ["pnpm-lock.yaml"];
445
- };
446
- readonly yarn: {
447
- readonly configs: readonly [RelPath];
448
- readonly lockfiles: readonly ["yarn.lock"];
449
- };
450
- };
451
- //#endregion
452
- //#region src/domain/builtin-rules.d.ts
453
- declare const rules: readonly [Rule<"advisory-check">, Rule<"approved-git-repos">, Rule<"audit-suppression">, Rule<"block-auto-install">, Rule<"block-exotic-subdeps">, Rule<"bun-security-scanner">, Rule<"checksum-verification">, Rule<"commit-lockfile">, Rule<"dependency-overrides">, Rule<"disable-lifecycle-scripts">, Rule<"enforce-strict-ssl">, Rule<"files-field">, Rule<"frozen-lockfile">, Rule<"frozen-store">, Rule<"hardened-mode">, Rule<"minimum-release-age">, Rule<"named-registries">, Rule<"paranoid-mode">, Rule<"patched-dependencies">, Rule<"pin-exact-versions">, Rule<"provenance">, Rule<"publish-access">, Rule<"store-server">, Rule<"strict-allow-scripts">, Rule<"strict-release-age">, Rule<"strict-store-integrity">, Rule<"trust-policy">];
454
- type BuiltinRuleId = (typeof rules)[number]['id'];
455
- //#endregion
456
- //#region src/domain/entities/siro-config.d.ts
457
- /** Per-rule setting. `'off'` disables; a Severity overrides the default level. */
458
- type RuleSetting = Severity | 'off';
459
- /**
460
- * User-facing config returned by `defineConfig` in `siro.config.{ts,mjs,js}`.
461
- *
462
- * defineConfig({
463
- * pms: ['npm', 'pnpm'], // restrict detection
464
- * rules: { provenance: 'off' }, // disable / override severity
465
- * customRules: [myRule], // extend
466
- * reporters: [mySarifReporter], // extend
467
- * })
468
- */
469
- interface SiroConfig {
470
- readonly pms?: readonly PM[];
471
- readonly projectType?: ProjectType;
472
- readonly rules?: Readonly<Partial<Record<BuiltinRuleId | (string & Record<never, never>), RuleSetting>>>;
473
- readonly customRules?: readonly Rule[];
474
- readonly reporters?: readonly Reporter[];
475
- }
476
- /** Identity helper for type-checked config files. */
477
- declare const defineConfig: (config: SiroConfig) => SiroConfig;
478
- //#endregion
479
- //#region src/domain/ports/config-codec.d.ts
480
- /** Reads a single config-file format into siro's structural view. */
481
- interface ConfigCodec {
482
- parse: (text: string) => ParsedConfig;
483
- }
484
- /** Resolve the codec for a given file kind. Total over `CodecKind`. */
485
- type CodecFor = (kind: CodecKind) => ConfigCodec;
486
- //#endregion
487
280
  //#region src/domain/rules/builders/require-config-key.d.ts
488
281
  interface RequireConfigKeySpec {
489
282
  readonly file: ConfigFileRef;
490
283
  readonly keyPath: KeyPath;
491
- /** Value `fix` will write and (when no `accept` predicate is given) the value `check` expects. */
284
+ /** Expected value and proposed replacement; `accept` may allow other values. */
492
285
  readonly value: ConfigValue;
493
286
  readonly message: string;
494
287
  readonly docs?: string;
495
288
  readonly severity?: Severity;
496
289
  accept?: (actual: unknown) => boolean;
497
290
  /**
498
- * Extra key writes appended after the auto-generated one (e.g. clearing
499
- * save-prefix alongside save-exact on the same .npmrc). The target file
500
- * is implicitly `spec.file` — extras can't redirect to a different file
501
- * because `check` would then never validate them, leaving the fix ops
502
- * and `lint` permanently out of step. A rule that legitimately needs to write
503
- * across multiple files belongs in a hand-written binding (see
504
- * `disable-lifecycle-scripts` → `overrideBindings`).
505
- */
506
- readonly extraFix?: readonly KeyAssignment[];
507
- /**
508
- * PM-documented default for this key. When the user has not set the key
509
- * AND this default would satisfy `accept`/`value`, the finding is
510
- * downgraded to {@link defaultSatisfiedSeverity} (default `'info'`) — the
511
- * threat is mitigated by the PM but explicit pinning is still recommended.
512
- * - unset: no PM-default protection (legacy behaviour).
513
- *
514
- * A CONDITIONAL default (e.g. CI-only: pnpm `frozenLockfile`, aube
515
- * `preferFrozenLockfile`) may use this field, but the binding's `message`
516
- * MUST name the condition — the downgrade then reads "covered where it
517
- * matters most", not "covered unconditionally".
291
+ * An omitted value that is safe across every supported version and target
292
+ * environment emits info. Version-dependent defaults retain full severity.
518
293
  */
519
294
  readonly documentedDefault?: ConfigValue;
520
295
  /**
@@ -536,68 +311,24 @@ interface RequireConfigKeyOptions<Id extends string = string> {
536
311
  /** Return false to short-circuit `check` as N/A (e.g. private packages). */
537
312
  applies?: (ctx: RepoContext) => boolean;
538
313
  }
539
- /**
540
- * Replace one or more bindings on an existing rule, returning a fresh Rule
541
- * object. Used by rules whose shape outgrows {@link requireConfigKey} for a
542
- * subset of PMs — they build the simple slots via the builder, then splice
543
- * the hand-written bindings in via this helper rather than rebuilding from
544
- * scratch or mutating the source rule.
545
- */
546
314
  declare const overrideBindings: <Id extends string>(rule: Rule<Id>, overrides: Partial<Rule["bindings"]>) => Rule<Id>;
547
315
  /** Build a Rule from a per-PM table of {file, keyPath, value, message}. */
548
316
  declare const requireConfigKey: <const Id extends string>(options: RequireConfigKeyOptions<Id>) => Rule<Id>;
549
317
  //#endregion
550
- //#region src/domain/services/render-version-note.d.ts
551
- declare const renderVersionNoteMessage: (message: string, versionNote: VersionNote | undefined) => string;
552
- //#endregion
553
- //#region src/domain/services/detect-pms.d.ts
554
- declare const detectPMs: (ctx: RepoContext) => PM[];
555
- //#endregion
556
- //#region src/domain/services/filter.d.ts
557
- /** Keep only findings at or above `threshold`, recomputing the summary. */
558
- declare const filterBySeverity: (result: LintResult, threshold: Severity) => LintResult;
559
- /**
560
- * Exit code for a lint run. Non-zero when any finding meets `threshold`
561
- * (default: only `error` fails the run).
562
- */
563
- declare const exitCodeForLint: (result: LintResult, threshold?: Severity) => number;
564
- //#endregion
565
- //#region src/shared/siro-error.d.ts
566
- /**
567
- * Structured errors used across siro. The CLI maps them to exit codes in one
568
- * place so individual commands never have to think about exit semantics.
569
- * The exit-code table lives in docs/configuration.md S"Exit codes" and
570
- * src/cli/help.ts (HELP_LINT) -- not restated here.
571
- */
318
+ //#region src/shared/errors.d.ts
572
319
  declare class SiroError extends Error {
573
- /** Recommended process exit code for this error. */
574
320
  readonly exitCode: number;
575
321
  constructor(message: string, exitCode: number);
576
322
  }
577
- //#endregion
578
- //#region src/shared/config-error.d.ts
579
323
  declare class ConfigError extends SiroError {
580
324
  constructor(message: string);
581
325
  }
582
- //#endregion
583
- //#region src/shared/usage-error.d.ts
584
326
  declare class UsageError extends SiroError {
585
327
  constructor(message: string);
586
328
  }
587
329
  //#endregion
588
- //#region src/shared/errors.d.ts
589
- /**
590
- * Run `fn` and wrap any non-`ConfigError` failure as a `ConfigError` prefixed
591
- * with `filePath`. Codec `parse` calls hit raw libraries that
592
- * throw bare `Error`s; without this wrap the CLI would surface those as
593
- * exit-1 internal errors and break CI that branches on exit codes. A
594
- * `ConfigError` that bubbles up from a nested call is re-thrown unchanged so
595
- * the original `path: message` framing is preserved.
596
- */
597
- declare const wrapCodecError: <TResult>(filePath: string, fn: () => TResult) => TResult;
598
- //#endregion
599
330
  //#region src/version.d.ts
600
- declare const version = "0.3.0";
331
+ declare const version: string;
601
332
  //#endregion
602
- export { type AbsPath, type AdvisoryRuleBinding, type AutoRuleBinding, BUILTIN_REPORTER_NAMES, type BuiltinReporterName, CONFIG_FILES, type CheckStatus, type CodecFor, type ConfigCodec, ConfigError, type ConfigFileRef, type ConfigReadValue, type ConfigScalar, type ConfigValue, type FileSystem, type Finding, type FixKind, type FixOp, type IO, type KeyAssignment, type KeyPath, type LintOptions, type LintResult, type PM, PMS, type PMSignals, PM_SIGNALS, PROJECT_TYPES, type PackageJson, type ParsedConfig, type ProjectType, type RelPath, type RepoContext, type Reporter, type ReporterRegistry, type RequireConfigKeyOptions, type Rule, type RuleBinding, type RuleSetting, SEVERITIES, type Severity, type SiroConfig, SiroError, UsageError, type VersionNote, asAbsPath, asRelPath, createRegistry, defineConfig, detectPMs, exitCodeForLint, filterBySeverity, getByPath, githubReporter, isPM, isReporterShape, isSeverity, jsonReporter, lintCommand, nodeFileSystem, nodeIO, overrideBindings, prettyReporter, renderVersionNoteMessage, requireConfigKey, version, wrapCodecError };
333
+ export { type AbsPath, BUILTIN_REPORTER_NAMES, type BuiltinReporterName, CONFIG_FILES, type CheckStatus, ConfigError, type ConfigFileRef, type ConfigReadValue, type ConfigValue, type FileSystem, type Finding, type IO, type KeyPath, type LintCommandOptions, type LintOptions, type LintResult, type PM, PMS, PROJECT_TYPES, type ParsedConfig, type ProjectType, type RelPath, type Remediation, type RepoContext, type Reporter, type RequireConfigKeyOptions, type Rule, type RuleBinding, type RuleContext, type RuleSetting, SEVERITIES, type SetKeyOperation, type Severity, type SiroConfig, SiroError, UsageError, type VersionNote, asAbsPath, asRelPath, defineConfig, defineRule, getByPath, githubReporter, isPM, isSeverity, jsonReporter, lint, lintCommand, loadConfig, nodeFileSystem, nodeIO, overrideBindings, prettyReporter, requireConfigKey, version };
603
334
  //# sourceMappingURL=index.d.mts.map