@xenos1996/usa 2.27.0 → 2.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +3 -3
  2. package/dist/cli-help.d.ts.map +1 -1
  3. package/dist/cli-help.js +13 -0
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/cli-intent.d.ts +4 -0
  6. package/dist/cli-intent.d.ts.map +1 -0
  7. package/dist/cli-intent.js +108 -0
  8. package/dist/cli-intent.js.map +1 -0
  9. package/dist/cli-scan.d.ts +12 -0
  10. package/dist/cli-scan.d.ts.map +1 -0
  11. package/dist/cli-scan.js +142 -0
  12. package/dist/cli-scan.js.map +1 -0
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +4 -0
  15. package/dist/cli.js.map +1 -1
  16. package/dist/engine/evaluate.d.ts.map +1 -1
  17. package/dist/engine/evaluate.js +31 -8
  18. package/dist/engine/evaluate.js.map +1 -1
  19. package/dist/intent/match.d.ts +38 -0
  20. package/dist/intent/match.d.ts.map +1 -0
  21. package/dist/intent/match.js +108 -0
  22. package/dist/intent/match.js.map +1 -0
  23. package/dist/intent/otm.d.ts +16 -0
  24. package/dist/intent/otm.d.ts.map +1 -0
  25. package/dist/intent/otm.js +144 -0
  26. package/dist/intent/otm.js.map +1 -0
  27. package/dist/intent/types.d.ts +111 -0
  28. package/dist/intent/types.d.ts.map +1 -0
  29. package/dist/intent/types.js +16 -0
  30. package/dist/intent/types.js.map +1 -0
  31. package/dist/scanner/adapters/codeql.d.ts +14 -0
  32. package/dist/scanner/adapters/codeql.d.ts.map +1 -0
  33. package/dist/scanner/adapters/codeql.js +134 -0
  34. package/dist/scanner/adapters/codeql.js.map +1 -0
  35. package/dist/scanner/adapters/dependency-cruiser.d.ts +3 -0
  36. package/dist/scanner/adapters/dependency-cruiser.d.ts.map +1 -0
  37. package/dist/scanner/adapters/dependency-cruiser.js +195 -0
  38. package/dist/scanner/adapters/dependency-cruiser.js.map +1 -0
  39. package/dist/scanner/adapters/ort.d.ts +12 -0
  40. package/dist/scanner/adapters/ort.d.ts.map +1 -0
  41. package/dist/scanner/adapters/ort.js +259 -0
  42. package/dist/scanner/adapters/ort.js.map +1 -0
  43. package/dist/scanner/adapters/scorecard.d.ts +7 -0
  44. package/dist/scanner/adapters/scorecard.d.ts.map +1 -0
  45. package/dist/scanner/adapters/scorecard.js +209 -0
  46. package/dist/scanner/adapters/scorecard.js.map +1 -0
  47. package/dist/scanner/adapters/semgrep.d.ts +3 -0
  48. package/dist/scanner/adapters/semgrep.d.ts.map +1 -0
  49. package/dist/scanner/adapters/semgrep.js +163 -0
  50. package/dist/scanner/adapters/semgrep.js.map +1 -0
  51. package/dist/scanner/adapters/trivy.d.ts +3 -0
  52. package/dist/scanner/adapters/trivy.d.ts.map +1 -0
  53. package/dist/scanner/adapters/trivy.js +163 -0
  54. package/dist/scanner/adapters/trivy.js.map +1 -0
  55. package/dist/scanner/config.d.ts +4 -0
  56. package/dist/scanner/config.d.ts.map +1 -0
  57. package/dist/scanner/config.js +15 -0
  58. package/dist/scanner/config.js.map +1 -0
  59. package/dist/scanner/identity.d.ts +17 -0
  60. package/dist/scanner/identity.d.ts.map +1 -0
  61. package/dist/scanner/identity.js +50 -0
  62. package/dist/scanner/identity.js.map +1 -0
  63. package/dist/scanner/normalize.d.ts +40 -0
  64. package/dist/scanner/normalize.d.ts.map +1 -0
  65. package/dist/scanner/normalize.js +85 -0
  66. package/dist/scanner/normalize.js.map +1 -0
  67. package/dist/scanner/registry.d.ts +19 -0
  68. package/dist/scanner/registry.d.ts.map +1 -0
  69. package/dist/scanner/registry.js +43 -0
  70. package/dist/scanner/registry.js.map +1 -0
  71. package/dist/scanner/run.d.ts +71 -0
  72. package/dist/scanner/run.d.ts.map +1 -0
  73. package/dist/scanner/run.js +461 -0
  74. package/dist/scanner/run.js.map +1 -0
  75. package/dist/scanner/sarif.d.ts +21 -0
  76. package/dist/scanner/sarif.d.ts.map +1 -0
  77. package/dist/scanner/sarif.js +156 -0
  78. package/dist/scanner/sarif.js.map +1 -0
  79. package/dist/scanner/types.d.ts +242 -0
  80. package/dist/scanner/types.d.ts.map +1 -0
  81. package/dist/scanner/types.js +11 -0
  82. package/dist/scanner/types.js.map +1 -0
  83. package/package.json +2 -1
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Intended vs observed.
3
+ *
4
+ * The join key is the CWE id: a threat declares `cwes: ["CWE-79"]`, and scanner
5
+ * evidence that names the same CWE is the observation. That is deterministic and
6
+ * auditable — no similarity scoring, no LLM.
7
+ *
8
+ * What it deliberately does NOT do: treat "no evidence" as "mitigated". A threat
9
+ * with no matching observation is `UNKNOWN` and says so, because the scanners
10
+ * that ran may simply not cover it.
11
+ */
12
+ import { normaliseCwe } from './otm.js';
13
+ /** Every CWE token in a piece of evidence, with where it was found. */
14
+ export function cwesOf(evidence) {
15
+ // A tool that stated its CWE is authoritative; only fall back to scanning the
16
+ // text when it did not, and never invent a relationship from a substring.
17
+ if (Array.isArray(evidence.cwes) && evidence.cwes.length > 0) {
18
+ return evidence.cwes.map((cwe) => ({ cwe: normaliseCwe(cwe), field: 'cwes' }));
19
+ }
20
+ const found = [];
21
+ const scan = (text, field) => {
22
+ if (!text)
23
+ return;
24
+ for (const match of text.matchAll(/\bCWE[-_ ]?(\d{1,5})\b/gi)) {
25
+ found.push({ cwe: `CWE-${Number(match[1])}`, field });
26
+ }
27
+ };
28
+ scan(evidence.source?.identifier, 'source.identifier');
29
+ scan(evidence.claim, 'claim');
30
+ return found;
31
+ }
32
+ export function matchThreats(model, evidence) {
33
+ const byCwe = indexEvidence(evidence);
34
+ const matches = model.threats.map((threat) => {
35
+ const hits = new Set();
36
+ const seenCwes = [];
37
+ for (const cwe of threat.cwes) {
38
+ const ids = byCwe.get(cwe);
39
+ if (!ids)
40
+ continue;
41
+ seenCwes.push(cwe);
42
+ for (const id of ids)
43
+ hits.add(id);
44
+ }
45
+ if (threat.cwes.length === 0) {
46
+ return {
47
+ threat,
48
+ verdict: 'UNKNOWN',
49
+ evidenceIds: [],
50
+ reason: 'the threat declares no CWE, so no scanner observation can be joined to it',
51
+ };
52
+ }
53
+ if (hits.size === 0) {
54
+ return {
55
+ threat,
56
+ verdict: 'NOT_OBSERVED',
57
+ evidenceIds: [],
58
+ reason: `no evidence mentions ${threat.cwes.join(', ')} — this does not prove the threat is mitigated`,
59
+ };
60
+ }
61
+ return {
62
+ threat,
63
+ verdict: 'OBSERVED',
64
+ evidenceIds: [...hits].sort(),
65
+ reason: `evidence cites ${seenCwes.join(', ')}`,
66
+ };
67
+ });
68
+ const declared = new Set(model.threats.flatMap((t) => t.cwes));
69
+ const unmodeled = [...byCwe.entries()]
70
+ .filter(([cwe]) => !declared.has(cwe))
71
+ .map(([cwe, ids]) => ({ cwe, evidenceIds: [...ids].sort() }))
72
+ .sort((a, b) => a.cwe.localeCompare(b.cwe));
73
+ const usedZones = new Set(model.components.map((c) => c.trustZone).filter(Boolean));
74
+ return {
75
+ model,
76
+ matches,
77
+ unmodeled,
78
+ emptyTrustZones: model.trustZones.filter((z) => !usedZones.has(z.id)),
79
+ };
80
+ }
81
+ function indexEvidence(evidence) {
82
+ const index = new Map();
83
+ for (const item of evidence) {
84
+ for (const { cwe } of cwesOf(item)) {
85
+ const set = index.get(cwe) ?? new Set();
86
+ set.add(item.id);
87
+ index.set(cwe, set);
88
+ }
89
+ }
90
+ return index;
91
+ }
92
+ /** Convenience for a caller holding an untyped `usa scan --json` payload. */
93
+ export function evidenceFromScanJson(payload) {
94
+ const list = payload?.evidence;
95
+ if (!Array.isArray(list))
96
+ return [];
97
+ return list.map((raw) => {
98
+ const o = (raw ?? {});
99
+ return {
100
+ id: typeof o.id === 'string' ? o.id : '',
101
+ claim: typeof o.claim === 'string' ? o.claim : '',
102
+ source: (o.source ?? {}),
103
+ cwes: Array.isArray(o.cwes) ? o.cwes : undefined,
104
+ };
105
+ });
106
+ }
107
+ export { normaliseCwe };
108
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/intent/match.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * OTM (Open Threat Model) parser.
3
+ *
4
+ * Total, like the scanner normalisers: a field the format does not require
5
+ * becomes an empty value, an entity type we do not model is listed in
6
+ * `unrecognised`, and a document that is not OTM at all throws a single named
7
+ * error rather than half-parsing.
8
+ */
9
+ import type { IntentModel } from './types.js';
10
+ export declare class IntentFormatError extends Error {
11
+ constructor(message: string);
12
+ }
13
+ export declare function parseOtm(raw: string): IntentModel;
14
+ /** `CWE-79`, `cwe-79`, `CWE 79` and `79` all become `CWE-79`. */
15
+ export declare function normaliseCwe(value: unknown): string;
16
+ //# sourceMappingURL=otm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otm.d.ts","sourceRoot":"","sources":["../../src/intent/otm.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAKV,WAAW,EAGZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAeD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAuCjD;AA2ED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKnD"}
@@ -0,0 +1,144 @@
1
+ export class IntentFormatError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'IntentFormatError';
5
+ }
6
+ }
7
+ /** Keys this parser models. Anything else in the document is reported, not dropped. */
8
+ const MODELLED = new Set([
9
+ 'otmVersion',
10
+ 'project',
11
+ 'assets',
12
+ 'components',
13
+ 'dataflows',
14
+ 'trustZones',
15
+ 'threats',
16
+ 'mitigations',
17
+ 'representations',
18
+ ]);
19
+ export function parseOtm(raw) {
20
+ let doc;
21
+ try {
22
+ doc = JSON.parse(raw);
23
+ }
24
+ catch (err) {
25
+ throw new IntentFormatError(`not valid JSON: ${err.message}`);
26
+ }
27
+ if (typeof doc !== 'object' || doc === null) {
28
+ throw new IntentFormatError('not an object');
29
+ }
30
+ const root = doc;
31
+ if (typeof root.otmVersion !== 'string') {
32
+ // Threat Dragon also exports its internal diagram format; saying which one
33
+ // this is beats "parse failed".
34
+ throw new IntentFormatError("not an OTM document (no otmVersion). Threat Dragon's internal diagram export is not supported — use its OTM export.");
35
+ }
36
+ const project = asRecord(root.project);
37
+ return {
38
+ format: 'otm',
39
+ version: root.otmVersion,
40
+ project: {
41
+ id: str(project.id),
42
+ name: str(project.name),
43
+ description: str(project.description),
44
+ owner: str(project.owner),
45
+ },
46
+ assets: list(root.assets).map(parseAsset),
47
+ components: list(root.components).map(parseComponent),
48
+ dataFlows: list(root.dataflows).map(parseFlow),
49
+ trustZones: list(root.trustZones).map(parseZone),
50
+ threats: list(root.threats).map(parseThreat),
51
+ mitigations: list(root.mitigations).map(parseMitigation),
52
+ // `$`-prefixed keys are annotations (a fixture note, a schema hint), not
53
+ // model content, so they are not reported as unmodelled entities.
54
+ unrecognised: Object.keys(root).filter((k) => !MODELLED.has(k) && !k.startsWith('$')),
55
+ };
56
+ }
57
+ function parseAsset(raw) {
58
+ const o = asRecord(raw);
59
+ const risk = asRecord(o.risk);
60
+ return {
61
+ id: str(o.id),
62
+ name: str(o.name),
63
+ description: str(o.description),
64
+ risk: {
65
+ confidentiality: num(risk.confidentiality),
66
+ integrity: num(risk.integrity),
67
+ availability: num(risk.availability),
68
+ },
69
+ };
70
+ }
71
+ function parseComponent(raw) {
72
+ const o = asRecord(raw);
73
+ const parent = asRecord(o.parent);
74
+ return {
75
+ id: str(o.id),
76
+ name: str(o.name),
77
+ type: str(o.type),
78
+ trustZone: parent.trustZone ? str(parent.trustZone) : undefined,
79
+ };
80
+ }
81
+ function parseFlow(raw) {
82
+ const o = asRecord(raw);
83
+ return {
84
+ id: str(o.id),
85
+ name: str(o.name),
86
+ source: str(o.source),
87
+ destination: str(o.destination),
88
+ bidirectional: o.bidirectional === true,
89
+ assets: list(o.assets).map(str).filter(Boolean),
90
+ };
91
+ }
92
+ function parseZone(raw) {
93
+ const o = asRecord(raw);
94
+ const risk = asRecord(o.risk);
95
+ return {
96
+ id: str(o.id),
97
+ name: str(o.name),
98
+ type: str(o.type),
99
+ trustRating: num(risk.trustRating),
100
+ };
101
+ }
102
+ function parseThreat(raw) {
103
+ const o = asRecord(raw);
104
+ const risk = asRecord(o.risk);
105
+ return {
106
+ id: str(o.id),
107
+ name: str(o.name),
108
+ description: str(o.description),
109
+ categories: list(o.categories).map(str).filter(Boolean),
110
+ cwes: list(o.cwes).map(normaliseCwe).filter(Boolean),
111
+ likelihood: num(risk.likelihood),
112
+ impact: num(risk.impact),
113
+ };
114
+ }
115
+ function parseMitigation(raw) {
116
+ const o = asRecord(raw);
117
+ return {
118
+ id: str(o.id),
119
+ name: str(o.name),
120
+ description: str(o.description),
121
+ riskReduction: num(o.riskReduction),
122
+ };
123
+ }
124
+ /** `CWE-79`, `cwe-79`, `CWE 79` and `79` all become `CWE-79`. */
125
+ export function normaliseCwe(value) {
126
+ const text = str(value)
127
+ .toUpperCase()
128
+ .replace(/[^0-9]/g, '');
129
+ return text ? `CWE-${Number(text)}` : '';
130
+ }
131
+ function asRecord(value) {
132
+ return typeof value === 'object' && value !== null ? value : {};
133
+ }
134
+ function list(value) {
135
+ return Array.isArray(value) ? value : [];
136
+ }
137
+ function str(value) {
138
+ return typeof value === 'string' ? value : '';
139
+ }
140
+ function num(value) {
141
+ const n = Number(value);
142
+ return Number.isFinite(n) ? n : undefined;
143
+ }
144
+ //# sourceMappingURL=otm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otm.js","sourceRoot":"","sources":["../../src/intent/otm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * The intent model — what the project says it is, as distinct from what the
3
+ * scanners observe.
4
+ *
5
+ * Shapes come from the **Open Threat Model** format (OTM 0.2.0) that Threat
6
+ * Dragon exports, verified against the project's own example model rather than
7
+ * from memory:
8
+ *
9
+ * { otmVersion, project, assets[], components[], dataflows[],
10
+ * trustZones[], threats[], mitigations[] }
11
+ *
12
+ * We import the *concepts*, not the application: no Threat Dragon process runs,
13
+ * no diagram is rendered, and the model is a plain file under version control.
14
+ */
15
+ export interface IntentModel {
16
+ format: 'otm';
17
+ version: string;
18
+ project: IntentProject;
19
+ assets: IntentAsset[];
20
+ components: IntentComponent[];
21
+ dataFlows: IntentDataFlow[];
22
+ trustZones: IntentTrustZone[];
23
+ threats: IntentThreat[];
24
+ mitigations: IntentMitigation[];
25
+ /** Anything the parser recognised but does not model. Never dropped silently. */
26
+ unrecognised: string[];
27
+ }
28
+ export interface IntentProject {
29
+ id: string;
30
+ name: string;
31
+ description: string;
32
+ owner: string;
33
+ }
34
+ export interface IntentAsset {
35
+ id: string;
36
+ name: string;
37
+ description: string;
38
+ /** Confidentiality / integrity / availability, 0–100, when declared. */
39
+ risk?: {
40
+ confidentiality?: number;
41
+ integrity?: number;
42
+ availability?: number;
43
+ };
44
+ }
45
+ export interface IntentComponent {
46
+ id: string;
47
+ name: string;
48
+ type: string;
49
+ /** The trust zone this component sits in, when declared. */
50
+ trustZone?: string;
51
+ }
52
+ export interface IntentDataFlow {
53
+ id: string;
54
+ name: string;
55
+ source: string;
56
+ destination: string;
57
+ bidirectional: boolean;
58
+ /** Asset ids carried across this flow. */
59
+ assets: string[];
60
+ }
61
+ export interface IntentTrustZone {
62
+ id: string;
63
+ name: string;
64
+ type: string;
65
+ /** 0–100; lower means less trusted. */
66
+ trustRating?: number;
67
+ }
68
+ export interface IntentThreat {
69
+ id: string;
70
+ name: string;
71
+ description: string;
72
+ /** STRIDE categories, e.g. ["Spoofing", "Tampering"]. */
73
+ categories: string[];
74
+ /** CWE ids this threat is about — the join key to scanner evidence. */
75
+ cwes: string[];
76
+ likelihood?: number;
77
+ impact?: number;
78
+ }
79
+ export interface IntentMitigation {
80
+ id: string;
81
+ name: string;
82
+ description: string;
83
+ riskReduction?: number;
84
+ }
85
+ /**
86
+ * What the model claims vs what the evidence shows, per threat.
87
+ *
88
+ * `UNKNOWN` is the default and the honest answer when nothing was observed: a
89
+ * threat with no matching evidence is not "mitigated", it is *unexamined*.
90
+ */
91
+ export type ThreatVerdict = 'OBSERVED' | 'NOT_OBSERVED' | 'UNKNOWN';
92
+ export interface ThreatMatch {
93
+ threat: IntentThreat;
94
+ verdict: ThreatVerdict;
95
+ /** Evidence ids that cite one of the threat's CWEs. */
96
+ evidenceIds: string[];
97
+ /** Why the verdict is what it is — mandatory, never blank. */
98
+ reason: string;
99
+ }
100
+ export interface IntentReport {
101
+ model: IntentModel;
102
+ matches: ThreatMatch[];
103
+ /** CWE ids seen in evidence that no declared threat mentions. */
104
+ unmodeled: {
105
+ cwe: string;
106
+ evidenceIds: string[];
107
+ }[];
108
+ /** Declared trust zones with no component inside them. */
109
+ emptyTrustZones: IntentTrustZone[];
110
+ }
111
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/intent/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The intent model — what the project says it is, as distinct from what the
3
+ * scanners observe.
4
+ *
5
+ * Shapes come from the **Open Threat Model** format (OTM 0.2.0) that Threat
6
+ * Dragon exports, verified against the project's own example model rather than
7
+ * from memory:
8
+ *
9
+ * { otmVersion, project, assets[], components[], dataflows[],
10
+ * trustZones[], threats[], mitigations[] }
11
+ *
12
+ * We import the *concepts*, not the application: no Threat Dragon process runs,
13
+ * no diagram is rendered, and the model is a plain file under version control.
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/intent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,14 @@
1
+ import type { ScannerAdapter } from '../types.js';
2
+ /** Where `database analyze` writes its SARIF, relative to the scan workdir. */
3
+ export declare const CODEQL_SARIF = "codeql-results.sarif";
4
+ export declare const codeqlAdapter: ScannerAdapter;
5
+ /**
6
+ * The analyze leg, exposed so tests and callers can build it without running create.
7
+ *
8
+ * `packs` is a *positional* argument, so an empty string is not "no packs" — it
9
+ * is one empty specifier, and CodeQL rejects the whole run with
10
+ * `Invalid package specification:` and writes no SARIF. Measured on 2.27.3: with
11
+ * no specifier at all, CodeQL runs the language's default (code-scanning) suite.
12
+ */
13
+ export declare function codeqlAnalyzeCommand(db: string, packs: string, out: string): string[];
14
+ //# sourceMappingURL=codeql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeql.d.ts","sourceRoot":"","sources":["../../../src/scanner/adapters/codeql.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAA0B,cAAc,EAAiB,MAAM,aAAa,CAAC;AAGzF,+EAA+E;AAC/E,eAAO,MAAM,YAAY,yBAAyB,CAAC;AAEnD,eAAO,MAAM,aAAa,EAAE,cAiE3B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAWrF"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * CodeQL — Tier 1, opt-in and heavyweight.
3
+ *
4
+ * Two-step by nature: `database create` then `database analyze`. Both are
5
+ * constructed here and parsed through the shared SARIF normaliser.
6
+ *
7
+ * `analyze` writes SARIF to a **file** (`--output=`) and logs to stdout, so the
8
+ * adapter declares the file as its artifact. Before the runner could read
9
+ * artifacts, this adapter parsed stdout and therefore parsed log lines: the
10
+ * SARIF never reached `parse`. That is a structural bug the fixture-based tests
11
+ * could not see, because they called `parse` directly.
12
+ *
13
+ * Verified end-to-end against CodeQL 2.27.3 on `fixtures/insecure-app`: two
14
+ * stages, one artifact, two findings. Three bugs only a run could find —
15
+ *
16
+ * 1. the query specifier is positional, so the default empty `packs` was passed
17
+ * as one empty specifier and the run died with `Invalid package
18
+ * specification:` and no SARIF;
19
+ * 2. `codeql --version` prints a sentence, so `[\d.]+` recorded `2.27.3.`;
20
+ * 3. (in the shared SARIF normaliser) CodeQL omits `result.level`, which made
21
+ * every finding INFO until the rule's `defaultConfiguration.level` was used.
22
+ *
23
+ * Security boundary, enforced and not aspirational: **the engine never runs a
24
+ * build command**. CodeQL's `--command` is arbitrary project code; the adapter
25
+ * will only emit it when the project config sets
26
+ * `allowBuildCommands: true`, which the runner refuses unless the audit opts in.
27
+ * Enforced twice, on purpose: once here, once in the tests.
28
+ */
29
+ import { spawnSync } from 'node:child_process';
30
+ import { statSync } from 'node:fs';
31
+ import path from 'node:path';
32
+ import { evidenceFromSarif } from '../sarif.js';
33
+ /** Where `database analyze` writes its SARIF, relative to the scan workdir. */
34
+ export const CODEQL_SARIF = 'codeql-results.sarif';
35
+ export const codeqlAdapter = {
36
+ id: 'codeql',
37
+ name: 'CodeQL data-flow analysis (opt-in)',
38
+ needsNetwork: true,
39
+ defaultConfig() {
40
+ return { language: 'javascript-typescript', packs: '', allowBuildCommands: false };
41
+ },
42
+ probe() {
43
+ const executable = which('codeql');
44
+ if (!executable) {
45
+ return {
46
+ available: false,
47
+ version: '',
48
+ reason: 'codeql executable not found on PATH (download from github/codeql-action)',
49
+ };
50
+ }
51
+ return { available: true, version: versionOf(executable), executable };
52
+ },
53
+ buildCommand(target, config) {
54
+ const language = String(config.language ?? 'javascript-typescript');
55
+ if (config.allowBuildCommands) {
56
+ throw new Error('allowBuildCommands must be granted by the audit, not by an adapter: the runner refuses build steps by default');
57
+ }
58
+ const db = path.join(target.workdir, 'codeql-db');
59
+ return {
60
+ prepare: [
61
+ {
62
+ argv: [
63
+ 'codeql',
64
+ 'database',
65
+ 'create',
66
+ db,
67
+ '--language',
68
+ language,
69
+ '--source-root',
70
+ target.path,
71
+ '--no-run-unnecessary-builds',
72
+ ],
73
+ timeoutMs: 900_000,
74
+ },
75
+ ],
76
+ argv: codeqlAnalyzeCommand(db, String(config.packs ?? ''), path.join(target.workdir, CODEQL_SARIF)),
77
+ artifacts: [CODEQL_SARIF],
78
+ timeoutMs: 900_000,
79
+ network: true,
80
+ };
81
+ },
82
+ parse(raw, context) {
83
+ return evidenceFromSarif(raw, {
84
+ tool: 'codeql',
85
+ kind: 'dataflow-finding',
86
+ adapterVersion: context.adapterVersion,
87
+ confidence: 1.0,
88
+ });
89
+ },
90
+ };
91
+ /**
92
+ * The analyze leg, exposed so tests and callers can build it without running create.
93
+ *
94
+ * `packs` is a *positional* argument, so an empty string is not "no packs" — it
95
+ * is one empty specifier, and CodeQL rejects the whole run with
96
+ * `Invalid package specification:` and writes no SARIF. Measured on 2.27.3: with
97
+ * no specifier at all, CodeQL runs the language's default (code-scanning) suite.
98
+ */
99
+ export function codeqlAnalyzeCommand(db, packs, out) {
100
+ const specifier = packs.trim();
101
+ return [
102
+ 'codeql',
103
+ 'database',
104
+ 'analyze',
105
+ db,
106
+ ...(specifier ? [specifier] : []),
107
+ '--format=sarif-latest',
108
+ `--output=${out}`,
109
+ ];
110
+ }
111
+ function which(binary) {
112
+ for (const dir of (process.env.PATH ?? '').split(path.delimiter)) {
113
+ if (!dir)
114
+ continue;
115
+ const candidate = path.join(dir, binary);
116
+ try {
117
+ if (statSync(candidate).isFile())
118
+ return candidate;
119
+ }
120
+ catch {
121
+ /* keep looking */
122
+ }
123
+ }
124
+ return null;
125
+ }
126
+ function versionOf(executable) {
127
+ const proc = spawnSync(executable, ['--version'], { encoding: 'utf8', timeout: 30_000 });
128
+ // `codeql --version` prints "CodeQL command-line toolchain release 2.27.3."
129
+ // A `[\d.]+` class captures the sentence's full stop, and the version is
130
+ // recorded as "2.27.3." in every manifest.
131
+ const match = /(\d+\.\d+\.\d+)/.exec(String(proc.stdout ?? ''));
132
+ return match?.[1] ?? 'unknown';
133
+ }
134
+ //# sourceMappingURL=codeql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeql.js","sourceRoot":"","sources":["../../../src/scanner/adapters/codeql.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ScannerAdapter } from '../types.js';
2
+ export declare const dependencyCruiserAdapter: ScannerAdapter;
3
+ //# sourceMappingURL=dependency-cruiser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-cruiser.d.ts","sourceRoot":"","sources":["../../../src/scanner/adapters/dependency-cruiser.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAGV,cAAc,EAGf,MAAM,aAAa,CAAC;AAIrB,eAAO,MAAM,wBAAwB,EAAE,cAkFtC,CAAC"}