@xenos1996/usat 1.0.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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +335 -0
  3. package/USAT.md +596 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +438 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config.d.ts +7 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +72 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/detect/index.d.ts +58 -0
  13. package/dist/detect/index.d.ts.map +1 -0
  14. package/dist/detect/index.js +329 -0
  15. package/dist/detect/index.js.map +1 -0
  16. package/dist/engine/audit.d.ts +21 -0
  17. package/dist/engine/audit.d.ts.map +1 -0
  18. package/dist/engine/audit.js +295 -0
  19. package/dist/engine/audit.js.map +1 -0
  20. package/dist/engine/diff.d.ts +24 -0
  21. package/dist/engine/diff.d.ts.map +1 -0
  22. package/dist/engine/diff.js +136 -0
  23. package/dist/engine/diff.js.map +1 -0
  24. package/dist/engine/evaluate.d.ts +19 -0
  25. package/dist/engine/evaluate.d.ts.map +1 -0
  26. package/dist/engine/evaluate.js +377 -0
  27. package/dist/engine/evaluate.js.map +1 -0
  28. package/dist/engine/gate.d.ts +19 -0
  29. package/dist/engine/gate.d.ts.map +1 -0
  30. package/dist/engine/gate.js +47 -0
  31. package/dist/engine/gate.js.map +1 -0
  32. package/dist/engine/loader.d.ts +22 -0
  33. package/dist/engine/loader.d.ts.map +1 -0
  34. package/dist/engine/loader.js +360 -0
  35. package/dist/engine/loader.js.map +1 -0
  36. package/dist/engine/maturity.d.ts +20 -0
  37. package/dist/engine/maturity.d.ts.map +1 -0
  38. package/dist/engine/maturity.js +157 -0
  39. package/dist/engine/maturity.js.map +1 -0
  40. package/dist/engine/score.d.ts +19 -0
  41. package/dist/engine/score.d.ts.map +1 -0
  42. package/dist/engine/score.js +141 -0
  43. package/dist/engine/score.js.map +1 -0
  44. package/dist/engine/sections.d.ts +14 -0
  45. package/dist/engine/sections.d.ts.map +1 -0
  46. package/dist/engine/sections.js +50 -0
  47. package/dist/engine/sections.js.map +1 -0
  48. package/dist/index.d.ts +23 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +17 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/report/markdown.d.ts +16 -0
  53. package/dist/report/markdown.d.ts.map +1 -0
  54. package/dist/report/markdown.js +488 -0
  55. package/dist/report/markdown.js.map +1 -0
  56. package/dist/types.d.ts +282 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +16 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/util/glob.d.ts +11 -0
  61. package/dist/util/glob.d.ts.map +1 -0
  62. package/dist/util/glob.js +86 -0
  63. package/dist/util/glob.js.map +1 -0
  64. package/dist/util/project.d.ts +72 -0
  65. package/dist/util/project.d.ts.map +1 -0
  66. package/dist/util/project.js +586 -0
  67. package/dist/util/project.js.map +1 -0
  68. package/dist/util/yaml.d.ts +28 -0
  69. package/dist/util/yaml.d.ts.map +1 -0
  70. package/dist/util/yaml.js +48 -0
  71. package/dist/util/yaml.js.map +1 -0
  72. package/docs/ARCHITECTURE.md +119 -0
  73. package/docs/README.md +27 -0
  74. package/docs/adr/0001-record-architecture-decisions.md +35 -0
  75. package/docs/adr/0002-typescript-engine-over-python.md +49 -0
  76. package/docs/adr/0003-rules-are-data-not-code.md +50 -0
  77. package/docs/adr/0004-markdown-only-output.md +41 -0
  78. package/docs/adr/0005-maturity-dampens-severity.md +56 -0
  79. package/docs/adr/0006-severity-status-two-axes.md +48 -0
  80. package/docs/adr/0007-suppressions-are-visible-and-expiring.md +46 -0
  81. package/docs/adr/0008-report-trailer-and-diff.md +48 -0
  82. package/docs/adr/0009-fail-closed-on-malformed-input.md +56 -0
  83. package/docs/adr/0010-detector-design.md +54 -0
  84. package/docs/adr/0011-coexist-with-deep-scanners.md +52 -0
  85. package/docs/adr/README.md +32 -0
  86. package/docs/agent-integration.md +129 -0
  87. package/docs/ci-integration.md +163 -0
  88. package/docs/concepts.md +196 -0
  89. package/docs/configuration.md +105 -0
  90. package/docs/detectors.md +186 -0
  91. package/docs/getting-started.md +99 -0
  92. package/docs/maturity-profiles.md +156 -0
  93. package/docs/reference/api.md +193 -0
  94. package/docs/reference/cli.md +412 -0
  95. package/docs/rule-packs.md +278 -0
  96. package/docs/standards-mapping.md +171 -0
  97. package/package.json +96 -0
  98. package/rules/core/architecture.yaml +190 -0
  99. package/rules/core/cicd.yaml +212 -0
  100. package/rules/core/code-quality.yaml +261 -0
  101. package/rules/core/dependencies.yaml +132 -0
  102. package/rules/core/documentation.yaml +119 -0
  103. package/rules/core/future-readiness.yaml +91 -0
  104. package/rules/core/release.yaml +131 -0
  105. package/rules/core/repo.yaml +303 -0
  106. package/rules/core/security.yaml +494 -0
  107. package/rules/core/supply-chain.yaml +357 -0
  108. package/rules/core/testing.yaml +260 -0
  109. package/rules/detectors.yaml +2255 -0
  110. package/rules/index.yaml +41 -0
  111. package/rules/profiles/maturity.yaml +135 -0
  112. package/rules/stacks/ai-era.yaml +193 -0
  113. package/rules/stacks/api-backend.yaml +121 -0
  114. package/rules/stacks/cli.yaml +105 -0
  115. package/rules/stacks/compliance.yaml +157 -0
  116. package/rules/stacks/containers.yaml +124 -0
  117. package/rules/stacks/data.yaml +165 -0
  118. package/rules/stacks/go.yaml +134 -0
  119. package/rules/stacks/iac.yaml +128 -0
  120. package/rules/stacks/jvm.yaml +150 -0
  121. package/rules/stacks/ml-ai.yaml +140 -0
  122. package/rules/stacks/mobile.yaml +121 -0
  123. package/rules/stacks/node-typescript.yaml +166 -0
  124. package/rules/stacks/python.yaml +175 -0
  125. package/rules/stacks/rust.yaml +129 -0
  126. package/rules/stacks/solidity.yaml +139 -0
  127. package/rules/stacks/web-frontend.yaml +159 -0
  128. package/templates/AGENTS.audit.md +135 -0
  129. package/templates/AUDIT_REPORT.md +155 -0
@@ -0,0 +1,329 @@
1
+ import { parse as parseYaml } from 'yaml';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ /**
5
+ * Paths a detection scan must ignore. Prose, tests, and examples *talk about*
6
+ * technology; they are not evidence that the project uses it. Without this,
7
+ * auditing any repo that mentions "postgres" in its docs reports a Postgres
8
+ * dependency.
9
+ */
10
+ const CONTENT_EXCLUDES = [
11
+ '**/*.md',
12
+ '**/*.mdx',
13
+ '**/*.rst',
14
+ 'README*',
15
+ '**/README*',
16
+ // NB: deliberately NOT '**/*.txt' — requirements.txt is a manifest, not prose.
17
+ '**/docs/**',
18
+ '**/doc/**',
19
+ '**/examples/**',
20
+ '**/example/**',
21
+ '**/templates/**',
22
+ '**/fixtures/**',
23
+ '**/__mocks__/**',
24
+ '**/test/**',
25
+ '**/tests/**',
26
+ '**/__tests__/**',
27
+ '**/spec/**',
28
+ '**/*.test.*',
29
+ '**/*.spec.*',
30
+ '**/*.stories.*',
31
+ '**/test_*',
32
+ '**/*_test.*',
33
+ 'LICENSE*',
34
+ 'CHANGELOG*',
35
+ ];
36
+ /** Load the detector registry. */
37
+ export function loadDetectors(file) {
38
+ let raw;
39
+ try {
40
+ raw = fs.readFileSync(file, 'utf8');
41
+ }
42
+ catch {
43
+ return [];
44
+ }
45
+ const doc = parseYaml(raw);
46
+ return Array.isArray(doc?.detectors) ? doc.detectors : [];
47
+ }
48
+ /** Run every detector against the project and derive the fact set. */
49
+ export function detect(project, detectors, git, extraFacts = []) {
50
+ const flags = new Set(extraFacts);
51
+ const metrics = {
52
+ commits: git.commits,
53
+ contributors: git.contributors,
54
+ tags: git.tags,
55
+ branches: git.branches,
56
+ files: project.files.length,
57
+ ...(git.daysSinceLastCommit !== undefined
58
+ ? { daysSinceLastCommit: git.daysSinceLastCommit }
59
+ : {}),
60
+ };
61
+ const fired = [];
62
+ // Fixed-point resolution: `implies` chains of any length resolve regardless
63
+ // of declaration order. Bounded by detectors.length + 1 passes (each pass
64
+ // must fire at least one new fact to continue), so a malformed registry
65
+ // cannot hang detection. Two hardcoded passes silently dropped chains of
66
+ // length 3+ declared worst-first, inflating score and confidence.
67
+ for (let pass = 0; pass <= detectors.length; pass++) {
68
+ let changed = false;
69
+ for (const d of detectors) {
70
+ if (processDetector(d, project, flags, metrics, fired))
71
+ changed = true;
72
+ }
73
+ if (!changed)
74
+ break;
75
+ }
76
+ const { maturity, signals } = classifyMaturity(flags, metrics, project);
77
+ flags.add(`maturity:${maturity}`);
78
+ return { facts: { flags, metrics }, detectorsFired: fired, maturity, maturitySignals: signals };
79
+ }
80
+ function processDetector(d, project, flags, metrics, fired) {
81
+ if (flags.has(d.fact))
82
+ return false;
83
+ let hit = false;
84
+ if (d.implies?.length) {
85
+ hit = d.implies.every((f) => flags.has(f));
86
+ }
87
+ if (!hit && d.match) {
88
+ hit = evalMatch(d.match, project, flags, metrics);
89
+ }
90
+ if (!hit)
91
+ return false;
92
+ flags.add(d.fact);
93
+ if (!fired.some((f) => f.fact === d.fact)) {
94
+ fired.push({ fact: d.fact, title: d.title, category: d.category });
95
+ }
96
+ return true;
97
+ }
98
+ function evalMatch(m, project, flags, metrics) {
99
+ const checks = [
100
+ ...matchAnyFile(m, project),
101
+ ...matchFileExists(m, project),
102
+ ...matchDirExists(m, project),
103
+ ...matchContent(m, project),
104
+ ...matchManifest(m, project),
105
+ ...matchMetric(m, metrics),
106
+ ...matchAnyOf(m, project, flags, metrics),
107
+ ...matchAllOf(m, project, flags, metrics),
108
+ ];
109
+ return checks.length > 0 && checks.every(Boolean);
110
+ }
111
+ /** Each matcher returns [] when its clause is absent, else a single verdict. */
112
+ function matchAnyFile(m, project) {
113
+ return m.any_file?.length ? [project.anyFile(m.any_file)] : [];
114
+ }
115
+ function matchFileExists(m, project) {
116
+ return m.file_exists?.length ? [m.file_exists.some((f) => project.glob([f]).length > 0)] : [];
117
+ }
118
+ function matchDirExists(m, project) {
119
+ return m.dir_exists?.length ? [m.dir_exists.some((d) => project.dirExists(d))] : [];
120
+ }
121
+ function matchContent(m, project) {
122
+ if (!m.content)
123
+ return [];
124
+ const { include, pattern } = m.content;
125
+ return [project.grep(pattern, include, CONTENT_EXCLUDES).length > 0];
126
+ }
127
+ function matchManifest(m, project) {
128
+ return m.manifest ? [manifestHas(project, m.manifest)] : [];
129
+ }
130
+ function matchMetric(m, metrics) {
131
+ if (!m.metric)
132
+ return [];
133
+ const v = metrics[m.metric.name] ?? 0;
134
+ if (m.metric.min !== undefined && v < m.metric.min)
135
+ return [false];
136
+ if (m.metric.max !== undefined && v > m.metric.max)
137
+ return [false];
138
+ return [true];
139
+ }
140
+ function matchAnyOf(m, project, flags, metrics) {
141
+ return m.any_of?.length ? [m.any_of.some((c) => evalMatch(c, project, flags, metrics))] : [];
142
+ }
143
+ function matchAllOf(m, project, flags, metrics) {
144
+ return m.all_of?.length ? [m.all_of.every((c) => evalMatch(c, project, flags, metrics))] : [];
145
+ }
146
+ /** Dotted key lookup across JSON manifests, with a TOML/YAML text fallback. */
147
+ function manifestHas(project, m) {
148
+ const matches = project.glob([m.file]);
149
+ if (matches.length === 0)
150
+ return false;
151
+ const file = matches[0];
152
+ const parts = m.key.split('.');
153
+ return file.endsWith('.json')
154
+ ? manifestHasJson(project, file, parts, m.contains)
155
+ : manifestHasText(project, file, parts, m.contains);
156
+ }
157
+ function manifestHasJson(project, file, parts, contains) {
158
+ const json = project.readJson(file);
159
+ const value = deepGet(json, parts.join('.'));
160
+ // No root-leaf fallback: when sections were specified (`a.b.c`) but the
161
+ // full path missed, a root-level key equal to the leaf (`{"c": …}`) must
162
+ // not count as a section-scoped hit. That fallback fired on any JSON with
163
+ // a coincidentally named top-level key.
164
+ if (value === undefined)
165
+ return false;
166
+ if (contains === undefined)
167
+ return true;
168
+ return String(value).includes(contains);
169
+ }
170
+ function manifestHasText(project, file, parts, contains) {
171
+ // TOML / YAML / go.mod: section-scoped text search.
172
+ const text = project.read(file);
173
+ if (text === null)
174
+ return false;
175
+ const leaf = parts[parts.length - 1];
176
+ const sections = parts.slice(0, -1);
177
+ // Word boundaries on both sides: without the leading one, leaf `test`
178
+ // matches inside `latest = …`; without the trailing one, similar affix
179
+ // collisions apply. Manifest keys are identifiers, so \b is the right gate.
180
+ const leafRe = new RegExp(`["']?\\b${escapeRe(leaf)}\\b["']?\\s*[=:]`, 'm');
181
+ if (sections.length > 0) {
182
+ const secName = sections[sections.length - 1];
183
+ const block = extractSection(text, secName);
184
+ if (block) {
185
+ // The section exists: decide solely on its content. A dependency named
186
+ // elsewhere (comments, other sections) must not satisfy a
187
+ // section-scoped query, and `contains` is checked against the block.
188
+ return leafRe.test(block) && containsOk(block, contains);
189
+ }
190
+ // No such section block. In a section-structured file (TOML/INI) that
191
+ // means the requested structure is absent — fail, don't rummage the
192
+ // whole file. In a flat file (YAML, go.mod) there are no blocks to
193
+ // match, so fall through to the whole-text search below.
194
+ if (hasSectionHeaders(text))
195
+ return false;
196
+ }
197
+ if (leafRe.test(text))
198
+ return containsOk(text, contains);
199
+ return false;
200
+ }
201
+ /** True when the text contains at least one `[section]`-style header. */
202
+ function hasSectionHeaders(text) {
203
+ return /^\s*\[[^\]]*\]\s*$/m.test(text);
204
+ }
205
+ function containsOk(text, contains) {
206
+ return contains === undefined || text.includes(contains);
207
+ }
208
+ /** Grabs the bodies of ini/TOML sections like `[dependencies]` or `[tool.poetry]`. */
209
+ function extractSection(text, section) {
210
+ const lines = text.split(/\r?\n/);
211
+ const want = section.toLowerCase();
212
+ let collecting = false;
213
+ let found = false;
214
+ let out = '';
215
+ for (const line of lines) {
216
+ const header = /^\s*\[([^\]]*)\]\s*$/.exec(line);
217
+ if (header) {
218
+ collecting = isWantedSection(header[1], want);
219
+ if (collecting)
220
+ found = true;
221
+ continue;
222
+ }
223
+ if (collecting)
224
+ out += line + '\n';
225
+ }
226
+ return found ? out : null;
227
+ }
228
+ /**
229
+ * The requested name must equal a full dot-segment of the header,
230
+ * case-insensitively. The old `\bname\b` substring test matched
231
+ * `[dev-dependencies]` for `dependencies` (`-` is a non-word char) and missed
232
+ * `[tool.Poetry]` for `poetry` (case). All matching blocks are gathered, not
233
+ * just the first — a repeated section later in the file counts too.
234
+ */
235
+ function isWantedSection(headerBody, want) {
236
+ const segments = headerBody.split('.').map((s) => s.trim().replace(/^["']|["']$/g, ''));
237
+ const last = segments[segments.length - 1] ?? '';
238
+ return last.toLowerCase() === want;
239
+ }
240
+ function deepGet(obj, dotted) {
241
+ let cur = obj;
242
+ for (const key of dotted.split('.')) {
243
+ if (cur === null || typeof cur !== 'object')
244
+ return undefined;
245
+ cur = cur[key];
246
+ }
247
+ return cur;
248
+ }
249
+ function escapeRe(s) {
250
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
251
+ }
252
+ /* --------------------------------------------------------------- maturity -- */
253
+ /**
254
+ * Lifecycle classification. Deliberately conservative: a project is only
255
+ * called "production" when it has release tags, CI, tests and recent activity.
256
+ * The result drives severity dampening so a prototype is not graded like a
257
+ * bank.
258
+ */
259
+ export function classifyMaturity(flags, metrics, project) {
260
+ const signals = [];
261
+ let score = 0;
262
+ const bump = (n, why, cond) => {
263
+ if (cond) {
264
+ score += n;
265
+ signals.push(`+${n} ${why}`);
266
+ }
267
+ else {
268
+ signals.push(`+0 ${why} (absent)`);
269
+ }
270
+ };
271
+ bump(1, 'tests present', flags.has('has:tests'));
272
+ bump(1, 'CI configured', flags.has('has:ci'));
273
+ bump(1, 'CHANGELOG maintained', flags.has('doc:changelog'));
274
+ bump(1, 'release tags published', metrics['tags'] > 0);
275
+ bump(1, 'meaningful history (>=50 commits)', metrics['commits'] >= 50);
276
+ bump(1, 'security policy published', flags.has('doc:security-policy'));
277
+ bump(0.5, 'containerised', flags.has('has:containers'));
278
+ bump(0.5, 'monitoring configured', flags.has('has:monitoring'));
279
+ bump(0.5, 'contributing guide', flags.has('doc:contributing'));
280
+ const days = metrics['daysSinceLastCommit'];
281
+ const stale = typeof days === 'number' && days > 365;
282
+ const abandoned = typeof days === 'number' && days > 540;
283
+ const stage = decideMaturityStage(score, metrics['tags'], days, stale, abandoned, flags);
284
+ let maturity = stage.maturity;
285
+ if (stage.signal)
286
+ signals.push(stage.signal);
287
+ // A 0.x version with no tags is never "production".
288
+ if (maturity === 'production' && project && isPrereleaseVersion(project)) {
289
+ maturity = 'beta';
290
+ signals.push('downgraded: 0.x version with no stable release');
291
+ }
292
+ signals.push(`maturity score ${score.toFixed(1)}/7.5 → ${maturity}`);
293
+ return { maturity, signals };
294
+ }
295
+ function decideMaturityStage(score, tags, days, stale, abandoned, flags) {
296
+ if (abandoned) {
297
+ return { maturity: 'legacy', signal: `legacy: last commit ${days}d ago` };
298
+ }
299
+ if (stale && !flags.has('has:ci')) {
300
+ return { maturity: 'legacy', signal: `legacy: ${days}d since last commit and no CI` };
301
+ }
302
+ if (score >= 7 && tags > 0)
303
+ return { maturity: 'production' };
304
+ if (score >= 5)
305
+ return { maturity: 'beta' };
306
+ if (score >= 2.5)
307
+ return { maturity: 'mvp' };
308
+ return { maturity: 'prototype' };
309
+ }
310
+ function isPrereleaseVersion(project) {
311
+ const pkg = project.readJson('package.json');
312
+ const v = pkg?.version;
313
+ if (typeof v === 'string' && /^0\./.test(v))
314
+ return true;
315
+ return false;
316
+ }
317
+ /* ------------------------------------------------------------------ helpers */
318
+ export function factsByPrefix(facts, prefix) {
319
+ const out = [];
320
+ for (const f of facts.flags) {
321
+ if (f.startsWith(`${prefix}:`))
322
+ out.push(f.slice(prefix.length + 1));
323
+ }
324
+ return out.sort();
325
+ }
326
+ export function loadDetectorFile(rulesDir) {
327
+ return loadDetectors(path.join(rulesDir, 'detectors.yaml'));
328
+ }
329
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { AuditReport, Depth, Maturity, UsatConfig } from '../types.js';
2
+ import { type MaturityProfile } from './maturity.js';
3
+ export interface AuditOptions {
4
+ target: string;
5
+ rulesDir?: string;
6
+ depth?: Depth;
7
+ profile?: Maturity | 'auto';
8
+ config?: UsatConfig;
9
+ allowCommands?: boolean;
10
+ usatVersion?: string;
11
+ /** Force these pack ids on/off regardless of detection. */
12
+ includePacks?: string[];
13
+ excludePacks?: string[];
14
+ }
15
+ export interface AuditOutcome {
16
+ report: AuditReport;
17
+ warnings: string[];
18
+ profile: MaturityProfile;
19
+ }
20
+ export declare function runAudit(options: AuditOptions): AuditOutcome;
21
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/engine/audit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,KAAK,EAGL,QAAQ,EAGR,UAAU,EACX,MAAM,aAAa,CAAC;AAQrB,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AA6B3E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;CAC1B;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,CAwE5D"}
@@ -0,0 +1,295 @@
1
+ import path from 'node:path';
2
+ import { SEVERITY_LADDER } from './loader.js';
3
+ import { Project } from '../util/project.js';
4
+ import { detect, loadDetectorFile } from '../detect/index.js';
5
+ import { loadRulePacks, applyRuleOverrides } from './loader.js';
6
+ import { evaluateRule, packApplies, ruleApplies } from './evaluate.js';
7
+ import { loadSections } from './sections.js';
8
+ import { loadProfiles, dampen } from './maturity.js';
9
+ import { loadConfig } from '../config.js';
10
+ import fs from 'node:fs';
11
+ import { fileURLToPath } from 'node:url';
12
+ /** `rules/`, resolved relative to the installed package (works from src and dist). */
13
+ const DEFAULT_RULES_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'rules');
14
+ /** Version of this build, read from package.json so it never drifts. */
15
+ const DEFAULT_VERSION = (() => {
16
+ try {
17
+ const pkg = JSON.parse(fs.readFileSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json'), 'utf8'));
18
+ return pkg.version ?? '0.0.0';
19
+ }
20
+ catch {
21
+ return '0.0.0';
22
+ }
23
+ })();
24
+ import { score } from './score.js';
25
+ export function runAudit(options) {
26
+ // The programmatic entry point must be usable with nothing but a target, so
27
+ // every knob the CLI exposes gets a sane default here rather than a crash.
28
+ const config = options.config ?? loadConfig(options.target);
29
+ const opts = normalizeAuditOptions(options, config);
30
+ const warnings = [];
31
+ const project = new Project(opts.target, config.ignore ?? []);
32
+ const git = project.gitInfo();
33
+ const detectors = loadDetectorFile(opts.rulesDir);
34
+ const detection = detect(project, detectors, git, config.facts ?? []);
35
+ const { packs, warnings: packWarnings } = loadRulePacks(opts.rulesDir);
36
+ warnings.push(...packWarnings);
37
+ const { disabled, overrides } = collectRuleSettings(config, warnings);
38
+ applyRuleOverrides(packs, overrides);
39
+ const suppressions = resolveSuppressions(config.suppressions, warnings);
40
+ const { include, exclude } = resolvePackSets(options, config);
41
+ // A pack may assert extra facts simply by applying (e.g. "we are a monorepo").
42
+ const facts = detection.facts;
43
+ const selection = selectInitialPacks(packs, facts, include, exclude);
44
+ // Packs can contribute facts, which can make another pack apply. Resolve to a
45
+ // fixed point (bounded, so a malformed pack cannot hang the audit).
46
+ resolvePackFacts(packs, facts, include, exclude, selection);
47
+ const sections = selectSections(loadSections(opts.rulesDir), config.sections, warnings);
48
+ const profiles = loadProfiles(opts.rulesDir);
49
+ const maturity = resolveMaturity(opts.profile, config.maturity, detection.maturity, warnings);
50
+ const profile = profiles[maturity];
51
+ const ctx = {
52
+ project,
53
+ facts,
54
+ depth: opts.depth,
55
+ allowCommands: opts.allowCommands,
56
+ disabled,
57
+ suppressions,
58
+ };
59
+ const evaluatedAll = evaluatePacks(selection.activePacks, facts, opts.depth, include, ctx, profile);
60
+ // A `sections:` restriction narrows both the scored set and the report, so a
61
+ // scoped audit cannot leak findings it promised to exclude.
62
+ const sectionFilter = config.sections ?? [];
63
+ const wanted = new Set(sections.map((s) => s.id));
64
+ const evaluated = sectionFilter.length > 0
65
+ ? evaluatedAll.filter((e) => wanted.has(e.finding.section))
66
+ : evaluatedAll;
67
+ const card = score(evaluated, sections, profile);
68
+ const report = buildReport(opts, git, detection, facts, maturity, card, evaluated, selection.packsLoaded, selection.packsSkipped);
69
+ return { report, warnings, profile };
70
+ }
71
+ function normalizeAuditOptions(options, config) {
72
+ return {
73
+ rulesDir: options.rulesDir ?? DEFAULT_RULES_DIR,
74
+ depth: options.depth ?? 'standard',
75
+ profile: options.profile ?? 'auto',
76
+ allowCommands: options.allowCommands ?? false,
77
+ usatVersion: options.usatVersion ?? DEFAULT_VERSION,
78
+ target: options.target,
79
+ config,
80
+ };
81
+ }
82
+ /**
83
+ * Expired (or undated) waivers fail closed: an `until` date in the past — or
84
+ * one that cannot be parsed — excludes the suppression and raises a warning,
85
+ * so an audit never silently honours dead risk acceptances.
86
+ */
87
+ function resolveSuppressions(suppressions, warnings) {
88
+ const map = new Map();
89
+ for (const s of suppressions ?? []) {
90
+ if (!s.rule)
91
+ continue;
92
+ if (s.until && isSuppressionExpired(s.rule, s.until, warnings))
93
+ continue;
94
+ map.set(s.rule, s.reason);
95
+ }
96
+ return map;
97
+ }
98
+ function isSuppressionExpired(rule, until, warnings) {
99
+ const t = Date.parse(until);
100
+ if (Number.isNaN(t)) {
101
+ warnings.push(`suppression for ${rule} has an unparseable "until" date ("${until}") — waiver ignored`);
102
+ return true;
103
+ }
104
+ if (t < Date.now()) {
105
+ warnings.push(`suppression for ${rule} expired on ${until} — treating as an active finding`);
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ const MATURITIES = ['prototype', 'mvp', 'beta', 'production', 'legacy'];
111
+ /**
112
+ * CLI --profile wins; otherwise a valid config `maturity` pins the bar;
113
+ * otherwise auto-detection stands. Invalid config values warn and fall back.
114
+ */
115
+ function resolveMaturity(cliProfile, configMaturity, detected, warnings) {
116
+ if (cliProfile !== 'auto')
117
+ return cliProfile;
118
+ if (configMaturity === undefined)
119
+ return detected;
120
+ if (MATURITIES.includes(configMaturity))
121
+ return configMaturity;
122
+ warnings.push(`.usat.yaml: invalid maturity "${String(configMaturity)}" — using auto-detected ${detected}`);
123
+ return detected;
124
+ }
125
+ /** Restrict scoring and reporting to the configured sections, if any. */
126
+ function selectSections(all, wanted, warnings) {
127
+ if (!wanted || wanted.length === 0)
128
+ return all;
129
+ const known = new Set(all.map((s) => s.id));
130
+ for (const id of wanted) {
131
+ if (!known.has(id))
132
+ warnings.push(`.usat.yaml: unknown section "${id}" in sections — ignored`);
133
+ }
134
+ return all.filter((s) => wanted.includes(s.id));
135
+ }
136
+ function resolvePackSets(options, config) {
137
+ return {
138
+ include: new Set(options.includePacks ?? config.include ?? []),
139
+ exclude: new Set(options.excludePacks ?? config.exclude ?? []),
140
+ };
141
+ }
142
+ function collectRuleSettings(config, warnings) {
143
+ const disabled = new Set();
144
+ const overrides = {};
145
+ for (const [id, o] of Object.entries(config.rules ?? {})) {
146
+ if (o.disabled)
147
+ disabled.add(id);
148
+ const severity = validateOverrideSeverity(id, o.severity, warnings);
149
+ const weight = validateOverrideWeight(id, o.weight, warnings);
150
+ if (severity !== undefined || weight !== undefined) {
151
+ overrides[id] = { severity, weight };
152
+ }
153
+ }
154
+ return { disabled, overrides };
155
+ }
156
+ /**
157
+ * Config overrides flow straight into scoring arithmetic — an invalid severity
158
+ * yields NaN totals and a negative weight yields scores outside 0–100.
159
+ * Reject loudly rather than corrupt the report.
160
+ */
161
+ function validateOverrideSeverity(id, v, warnings) {
162
+ if (v === undefined)
163
+ return undefined;
164
+ if (SEVERITY_LADDER.includes(String(v))) {
165
+ return String(v);
166
+ }
167
+ warnings.push(`rules.${id}: invalid severity "${String(v)}" — override ignored`);
168
+ return undefined;
169
+ }
170
+ function validateOverrideWeight(id, v, warnings) {
171
+ if (v === undefined)
172
+ return undefined;
173
+ if (typeof v === 'number' && Number.isFinite(v) && v >= 0)
174
+ return v;
175
+ warnings.push(`rules.${id}: invalid weight "${String(v)}" (must be a finite number ≥ 0) — override ignored`);
176
+ return undefined;
177
+ }
178
+ function selectInitialPacks(packs, facts, include, exclude) {
179
+ const selection = { activePacks: [], packsLoaded: [], packsSkipped: [] };
180
+ selection.activePacks = packs.filter((p) => selectPack(p, facts, include, exclude, selection));
181
+ return selection;
182
+ }
183
+ function selectPack(pack, facts, include, exclude, selection) {
184
+ if (exclude.has(pack.id)) {
185
+ selection.packsSkipped.push(pack.id);
186
+ return false;
187
+ }
188
+ if (include.has(pack.id)) {
189
+ selection.packsLoaded.push(pack.id);
190
+ pack.provides?.forEach((f) => facts.flags.add(f));
191
+ return true;
192
+ }
193
+ if (!packApplies(pack, facts)) {
194
+ selection.packsSkipped.push(pack.id);
195
+ return false;
196
+ }
197
+ selection.packsLoaded.push(pack.id);
198
+ pack.provides?.forEach((f) => facts.flags.add(f));
199
+ return true;
200
+ }
201
+ function resolvePackFacts(packs, facts, include, exclude, selection) {
202
+ for (let pass = 0; pass < 3; pass++) {
203
+ let changed = false;
204
+ for (const p of packs) {
205
+ if (selection.packsLoaded.includes(p.id) || exclude.has(p.id) || include.has(p.id))
206
+ continue;
207
+ if (!packApplies(p, facts))
208
+ continue;
209
+ selection.packsLoaded.push(p.id);
210
+ p.provides?.forEach((f) => facts.flags.add(f));
211
+ selection.activePacks.push(p);
212
+ changed = true;
213
+ }
214
+ if (!changed)
215
+ break;
216
+ }
217
+ }
218
+ function evaluatePacks(activePacks, facts, depth, include, ctx, profile) {
219
+ const evaluated = [];
220
+ for (const pack of activePacks) {
221
+ for (const rule of pack.rules) {
222
+ if (!ruleApplies(rule, facts, depth, include.has(pack.id)))
223
+ continue;
224
+ evaluated.push(scoreFinding(rule, ctx, profile));
225
+ }
226
+ }
227
+ return evaluated;
228
+ }
229
+ function scoreFinding(rule, ctx, profile) {
230
+ const finding = evaluateRule(rule, ctx);
231
+ if (finding.status === 'PASS' || finding.status === 'NOT_APPLICABLE') {
232
+ return { rule, finding };
233
+ }
234
+ const { severity, dampened } = dampen(rule.severity, rule.ruleClass, profile);
235
+ finding.severity = severity;
236
+ finding.dampened = dampened;
237
+ return { rule, finding };
238
+ }
239
+ function buildReport(opts, git, detection, facts, maturity, card, evaluated, packsLoaded, packsSkipped) {
240
+ return {
241
+ schema: 'usat-report-v1',
242
+ generatedAt: new Date().toISOString(),
243
+ usatVersion: opts.usatVersion,
244
+ target: {
245
+ path: path.resolve(opts.target),
246
+ name: path.basename(path.resolve(opts.target)) || opts.target,
247
+ commit: git.commit,
248
+ ref: git.ref,
249
+ repoUrl: git.repoUrl,
250
+ },
251
+ detection: {
252
+ maturity,
253
+ maturitySignals: detection.maturitySignals,
254
+ projectTypes: pick(facts, 'project'),
255
+ platforms: pick(facts, 'platform'),
256
+ languages: pick(facts, 'lang'),
257
+ frameworks: pick(facts, 'fw'),
258
+ packageManagers: pick(facts, 'pm'),
259
+ databases: pick(facts, 'db'),
260
+ flags: [...facts.flags].filter((f) => f.startsWith('has:')).sort(),
261
+ metrics: facts.metrics,
262
+ },
263
+ options: {
264
+ depth: opts.depth,
265
+ profile: opts.profile,
266
+ rulesDir: opts.rulesDir,
267
+ packsLoaded,
268
+ packsSkipped,
269
+ },
270
+ score: card,
271
+ findings: evaluated
272
+ .map((e) => e.finding)
273
+ .filter((f) => f.status !== 'NOT_APPLICABLE')
274
+ .sort(bySeverityThenSection),
275
+ };
276
+ }
277
+ function pick(facts, prefix) {
278
+ const out = [];
279
+ for (const f of facts.flags) {
280
+ if (f.startsWith(`${prefix}:`))
281
+ out.push(f.slice(prefix.length + 1));
282
+ }
283
+ return out.sort();
284
+ }
285
+ const ORDER = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3, FUTURE: 4 };
286
+ function bySeverityThenSection(a, b) {
287
+ const sa = ORDER[a.severity] ?? 9;
288
+ const sb = ORDER[b.severity] ?? 9;
289
+ if (sa !== sb)
290
+ return sa - sb;
291
+ if (a.section !== b.section)
292
+ return a.section.localeCompare(b.section, undefined, { numeric: true });
293
+ return a.ruleId.localeCompare(b.ruleId);
294
+ }
295
+ //# sourceMappingURL=audit.js.map