@xenos1996/usa 2.27.0 → 2.28.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/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +2 -0
- package/dist/cli-help.js.map +1 -1
- package/dist/cli-intent.d.ts +4 -0
- package/dist/cli-intent.d.ts.map +1 -0
- package/dist/cli-intent.js +108 -0
- package/dist/cli-intent.js.map +1 -0
- package/dist/cli-scan.d.ts +12 -0
- package/dist/cli-scan.d.ts.map +1 -0
- package/dist/cli-scan.js +142 -0
- package/dist/cli-scan.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/engine/evaluate.d.ts.map +1 -1
- package/dist/engine/evaluate.js +31 -8
- package/dist/engine/evaluate.js.map +1 -1
- package/dist/intent/match.d.ts +38 -0
- package/dist/intent/match.d.ts.map +1 -0
- package/dist/intent/match.js +108 -0
- package/dist/intent/match.js.map +1 -0
- package/dist/intent/otm.d.ts +16 -0
- package/dist/intent/otm.d.ts.map +1 -0
- package/dist/intent/otm.js +144 -0
- package/dist/intent/otm.js.map +1 -0
- package/dist/intent/types.d.ts +111 -0
- package/dist/intent/types.d.ts.map +1 -0
- package/dist/intent/types.js +16 -0
- package/dist/intent/types.js.map +1 -0
- package/dist/scanner/adapters/codeql.d.ts +14 -0
- package/dist/scanner/adapters/codeql.d.ts.map +1 -0
- package/dist/scanner/adapters/codeql.js +134 -0
- package/dist/scanner/adapters/codeql.js.map +1 -0
- package/dist/scanner/adapters/dependency-cruiser.d.ts +3 -0
- package/dist/scanner/adapters/dependency-cruiser.d.ts.map +1 -0
- package/dist/scanner/adapters/dependency-cruiser.js +174 -0
- package/dist/scanner/adapters/dependency-cruiser.js.map +1 -0
- package/dist/scanner/adapters/ort.d.ts +12 -0
- package/dist/scanner/adapters/ort.d.ts.map +1 -0
- package/dist/scanner/adapters/ort.js +259 -0
- package/dist/scanner/adapters/ort.js.map +1 -0
- package/dist/scanner/adapters/scorecard.d.ts +7 -0
- package/dist/scanner/adapters/scorecard.d.ts.map +1 -0
- package/dist/scanner/adapters/scorecard.js +209 -0
- package/dist/scanner/adapters/scorecard.js.map +1 -0
- package/dist/scanner/adapters/semgrep.d.ts +3 -0
- package/dist/scanner/adapters/semgrep.d.ts.map +1 -0
- package/dist/scanner/adapters/semgrep.js +163 -0
- package/dist/scanner/adapters/semgrep.js.map +1 -0
- package/dist/scanner/adapters/trivy.d.ts +3 -0
- package/dist/scanner/adapters/trivy.d.ts.map +1 -0
- package/dist/scanner/adapters/trivy.js +163 -0
- package/dist/scanner/adapters/trivy.js.map +1 -0
- package/dist/scanner/config.d.ts +4 -0
- package/dist/scanner/config.d.ts.map +1 -0
- package/dist/scanner/config.js +15 -0
- package/dist/scanner/config.js.map +1 -0
- package/dist/scanner/identity.d.ts +17 -0
- package/dist/scanner/identity.d.ts.map +1 -0
- package/dist/scanner/identity.js +50 -0
- package/dist/scanner/identity.js.map +1 -0
- package/dist/scanner/normalize.d.ts +40 -0
- package/dist/scanner/normalize.d.ts.map +1 -0
- package/dist/scanner/normalize.js +85 -0
- package/dist/scanner/normalize.js.map +1 -0
- package/dist/scanner/registry.d.ts +19 -0
- package/dist/scanner/registry.d.ts.map +1 -0
- package/dist/scanner/registry.js +43 -0
- package/dist/scanner/registry.js.map +1 -0
- package/dist/scanner/run.d.ts +70 -0
- package/dist/scanner/run.d.ts.map +1 -0
- package/dist/scanner/run.js +419 -0
- package/dist/scanner/run.js.map +1 -0
- package/dist/scanner/sarif.d.ts +21 -0
- package/dist/scanner/sarif.d.ts.map +1 -0
- package/dist/scanner/sarif.js +156 -0
- package/dist/scanner/sarif.js.map +1 -0
- package/dist/scanner/types.d.ts +236 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +11 -0
- package/dist/scanner/types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenSSF Scorecard — Tier 2.
|
|
3
|
+
*
|
|
4
|
+
* Two modes, because the tool has two natures and they are not interchangeable:
|
|
5
|
+
*
|
|
6
|
+
* - `--local <folder>` reads a checkout and runs the **file-based** checks
|
|
7
|
+
* offline. Verified here (v5.6.0): SAST, License, Pinned-Dependencies,
|
|
8
|
+
* Dependency-Update-Tool, Binary-Artifacts, Fuzzing, Packaging.
|
|
9
|
+
* - `--repo <url>` reaches the platform API and runs the **platform** checks
|
|
10
|
+
* (Branch-Protection, Token-Permissions, Signed-Releases, Code-Review, …).
|
|
11
|
+
* It needs network and a token.
|
|
12
|
+
*
|
|
13
|
+
* Measured in local mode, the platform checks do not degrade to `?` — they make
|
|
14
|
+
* the whole run fail (`Unsupported RequestType [0] by check: Branch-Protection`).
|
|
15
|
+
* So the check list is explicit in local mode; leaving it off is a crash, not a
|
|
16
|
+
* partial result.
|
|
17
|
+
*
|
|
18
|
+
* The aggregate score is deliberately NOT emitted as evidence. Scorecard's own
|
|
19
|
+
* README says the aggregate "tells you nothing about what individual behaviors a
|
|
20
|
+
* repository is or is not doing"; a per-check reason is evidence, a 7.5/10 is a
|
|
21
|
+
* headline.
|
|
22
|
+
*/
|
|
23
|
+
import { spawnSync } from 'node:child_process';
|
|
24
|
+
import { statSync } from 'node:fs';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
import { buildEvidence } from '../identity.js';
|
|
27
|
+
import { DETERMINISTIC_CONFIDENCE, dig, tryParseJson } from '../normalize.js';
|
|
28
|
+
/** The file-based checks that survive `--local` (verified against v5.6.0). */
|
|
29
|
+
export const LOCAL_CHECKS = [
|
|
30
|
+
'SAST',
|
|
31
|
+
'License',
|
|
32
|
+
'Pinned-Dependencies',
|
|
33
|
+
'Dependency-Update-Tool',
|
|
34
|
+
'Binary-Artifacts',
|
|
35
|
+
'Fuzzing',
|
|
36
|
+
'Packaging',
|
|
37
|
+
];
|
|
38
|
+
export const scorecardAdapter = {
|
|
39
|
+
id: 'scorecard',
|
|
40
|
+
name: 'OpenSSF Scorecard repository posture probes',
|
|
41
|
+
/** Only the repo mode reaches the network; local mode is fully offline. */
|
|
42
|
+
needsNetwork: false,
|
|
43
|
+
defaultConfig() {
|
|
44
|
+
return { mode: 'local', checks: LOCAL_CHECKS };
|
|
45
|
+
},
|
|
46
|
+
probe() {
|
|
47
|
+
const executable = which('scorecard');
|
|
48
|
+
if (!executable) {
|
|
49
|
+
return {
|
|
50
|
+
available: false,
|
|
51
|
+
version: '',
|
|
52
|
+
reason: 'scorecard executable not found on PATH (release binary from ossf/scorecard)',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return { available: true, version: versionOf(executable), executable };
|
|
56
|
+
},
|
|
57
|
+
buildCommand(target, config) {
|
|
58
|
+
const mode = String(config.mode ?? 'local');
|
|
59
|
+
const checks = Array.isArray(config.checks) ? config.checks : LOCAL_CHECKS;
|
|
60
|
+
if (mode === 'repo') {
|
|
61
|
+
const repo = String(config.repo ?? '') || deriveRepoSlug(target.path);
|
|
62
|
+
return {
|
|
63
|
+
argv: ['scorecard', '--repo', repo, '--format', 'json', '--show-details'],
|
|
64
|
+
timeoutMs: 300_000,
|
|
65
|
+
network: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
argv: [
|
|
70
|
+
'scorecard',
|
|
71
|
+
'--local',
|
|
72
|
+
target.workdir,
|
|
73
|
+
'--format',
|
|
74
|
+
'json',
|
|
75
|
+
'--checks',
|
|
76
|
+
checks.join(','),
|
|
77
|
+
],
|
|
78
|
+
timeoutMs: 300_000,
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
parse(raw, context) {
|
|
82
|
+
const parsed = tryParseJson(raw);
|
|
83
|
+
if (!parsed.ok) {
|
|
84
|
+
return [unknown(context, `scorecard output was not valid JSON: ${parsed.error}`)];
|
|
85
|
+
}
|
|
86
|
+
const checks = dig(parsed.value, ['checks']);
|
|
87
|
+
if (!Array.isArray(checks)) {
|
|
88
|
+
return [unknown(context, 'scorecard JSON carried no checks array')];
|
|
89
|
+
}
|
|
90
|
+
const toolVersion = String(dig(parsed.value, ['scorecard', 'version']) ?? context.adapterVersion);
|
|
91
|
+
return checks.flatMap((check, index) => checkToEvidence(check, index, toolVersion));
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
/** One probe → one evidence row carrying the tool's own reason. */
|
|
95
|
+
function checkToEvidence(check, index, toolVersion) {
|
|
96
|
+
const name = String(dig(check, ['name']) ?? 'unknown-check');
|
|
97
|
+
const score = Number(dig(check, ['score']));
|
|
98
|
+
const reason = String(dig(check, ['reason']) ?? 'no reason given');
|
|
99
|
+
const docUrl = String(dig(check, ['documentation', 'url']) ?? '');
|
|
100
|
+
const source = {
|
|
101
|
+
tool: 'scorecard',
|
|
102
|
+
kind: 'posture-probe',
|
|
103
|
+
version: toolVersion,
|
|
104
|
+
identifier: name,
|
|
105
|
+
};
|
|
106
|
+
// A negative score is scorecard's "could not evaluate" — UNKNOWN, never a fail
|
|
107
|
+
// and never a pass. The reason string says why, and that is the evidence.
|
|
108
|
+
if (!Number.isFinite(score) || score < 0) {
|
|
109
|
+
return [
|
|
110
|
+
buildEvidence({
|
|
111
|
+
source,
|
|
112
|
+
provenance: placeholder(),
|
|
113
|
+
claim: `${name}: could not be evaluated — ${reason}`,
|
|
114
|
+
severity: 'INFO',
|
|
115
|
+
confidence: DETERMINISTIC_CONFIDENCE,
|
|
116
|
+
status: 'UNKNOWN',
|
|
117
|
+
location: null,
|
|
118
|
+
rawReference: { jsonPath: `checks[${index}]`, excerpt: reason.slice(0, 160) },
|
|
119
|
+
}),
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
// Scorecard's 0–10 is a scale, not a verdict, and the same number means
|
|
123
|
+
// different things per probe: License 9 is "detected, not identified" while
|
|
124
|
+
// Binary-Artifacts 6 is "binaries present". Collapsing either to FAIL loses
|
|
125
|
+
// the distinction and collapsing to PASS launders the caveat, so the adapter
|
|
126
|
+
// emits PARTIAL and carries the number in the claim. A rule decides what
|
|
127
|
+
// threshold means a failure — that is a policy question, not a parsing one.
|
|
128
|
+
const status = score >= 10 ? 'PASS' : 'PARTIAL';
|
|
129
|
+
return [
|
|
130
|
+
buildEvidence({
|
|
131
|
+
source,
|
|
132
|
+
provenance: placeholder(),
|
|
133
|
+
claim: `${name} (${score}/10): ${reason}`,
|
|
134
|
+
severity: status === 'PASS' ? 'INFO' : 'MEDIUM',
|
|
135
|
+
confidence: DETERMINISTIC_CONFIDENCE,
|
|
136
|
+
status,
|
|
137
|
+
location: null,
|
|
138
|
+
rawReference: { jsonPath: `checks[${index}]`, excerpt: docUrl.slice(0, 160) },
|
|
139
|
+
}),
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
function unknown(context, reason) {
|
|
143
|
+
return {
|
|
144
|
+
id: `UNKNOWN-scorecard-${reason}`.replace(/[^A-Za-z0-9-]/g, '-').slice(0, 48),
|
|
145
|
+
source: {
|
|
146
|
+
tool: 'scorecard',
|
|
147
|
+
version: context.adapterVersion,
|
|
148
|
+
kind: 'check',
|
|
149
|
+
identifier: 'UNKNOWN',
|
|
150
|
+
},
|
|
151
|
+
provenance: placeholder(),
|
|
152
|
+
claim: reason,
|
|
153
|
+
severity: 'INFO',
|
|
154
|
+
severitySource: 'adapter-default',
|
|
155
|
+
confidence: DETERMINISTIC_CONFIDENCE,
|
|
156
|
+
status: 'UNKNOWN',
|
|
157
|
+
location: null,
|
|
158
|
+
rawReference: {},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function placeholder() {
|
|
162
|
+
return {
|
|
163
|
+
executionId: '',
|
|
164
|
+
command: [],
|
|
165
|
+
config: {},
|
|
166
|
+
repositoryRevision: '',
|
|
167
|
+
timestamp: '',
|
|
168
|
+
executable: '',
|
|
169
|
+
timeoutMs: 0,
|
|
170
|
+
elapsedMs: 0,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/** `git@github.com:org/repo.git` or `https://github.com/org/repo.git` → `org/repo`. */
|
|
174
|
+
export function deriveRepoSlug(targetPath) {
|
|
175
|
+
const proc = spawnSync('git', ['remote', 'get-url', 'origin'], {
|
|
176
|
+
cwd: targetPath,
|
|
177
|
+
encoding: 'utf8',
|
|
178
|
+
timeout: 15_000,
|
|
179
|
+
});
|
|
180
|
+
const url = String(proc.stdout ?? '').trim();
|
|
181
|
+
const match = /github\.com[:/]([\w.-]+\/[\w.-]+?)(?:\.git)?\/?$/.exec(url);
|
|
182
|
+
return match?.[1] ?? '';
|
|
183
|
+
}
|
|
184
|
+
function which(binary) {
|
|
185
|
+
for (const dir of (process.env.PATH ?? '').split(path.delimiter)) {
|
|
186
|
+
if (!dir)
|
|
187
|
+
continue;
|
|
188
|
+
const candidate = path.join(dir, binary);
|
|
189
|
+
try {
|
|
190
|
+
if (statSync(candidate).isFile())
|
|
191
|
+
return candidate;
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
/* keep looking */
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* `scorecard version` prints an ASCII-art banner before the number, so the
|
|
201
|
+
* pattern demands a full semver — a loose `[\d.]+` matches the art instead.
|
|
202
|
+
* The JSON report also carries the version, and the parser prefers that one.
|
|
203
|
+
*/
|
|
204
|
+
function versionOf(executable) {
|
|
205
|
+
const proc = spawnSync(executable, ['version'], { encoding: 'utf8', timeout: 20_000 });
|
|
206
|
+
const match = /\bv?(\d+\.\d+\.\d+)\b/.exec(String(proc.stdout ?? proc.stderr ?? ''));
|
|
207
|
+
return match?.[1] ?? 'unknown';
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=scorecard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scorecard.js","sourceRoot":"","sources":["../../../src/scanner/adapters/scorecard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semgrep.d.ts","sourceRoot":"","sources":["../../../src/scanner/adapters/semgrep.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAA0B,cAAc,EAAiB,MAAM,aAAa,CAAC;AAWzF,eAAO,MAAM,cAAc,EAAE,cAmF5B,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semgrep — Tier 1.
|
|
3
|
+
*
|
|
4
|
+
* Verified by installing semgrep 1.182.0 and running it against
|
|
5
|
+
* `fixtures/insecure-app` with a vendored rule; the committed fixture is a real
|
|
6
|
+
* capture. Two measured details shape this adapter: `path` is absolute when the
|
|
7
|
+
* target is absolute (so it is relativised to the scan root), and
|
|
8
|
+
* `extra.fingerprint` is the literal string "requires login" on the OSS engine
|
|
9
|
+
* without an account (so the evidence id is content-derived, never the
|
|
10
|
+
* fingerprint).
|
|
11
|
+
*
|
|
12
|
+
* Exit-code behaviour is verified from the CLI reference: default `scan`
|
|
13
|
+
* **exits 0 even with findings**; only `--error` exits 1. The runner never
|
|
14
|
+
* infers a verdict from the status code, so this does not affect semantics —
|
|
15
|
+
* but it is why the adapter does not pass `--error`.
|
|
16
|
+
*/
|
|
17
|
+
import { spawnSync } from 'node:child_process';
|
|
18
|
+
import { statSync } from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { buildEvidence } from '../identity.js';
|
|
21
|
+
import { DETERMINISTIC_CONFIDENCE, dig, lineNumber, relativePath, severity, tryParseJson, } from '../normalize.js';
|
|
22
|
+
export const semgrepAdapter = {
|
|
23
|
+
id: 'semgrep',
|
|
24
|
+
name: 'Semgrep SAST scanner',
|
|
25
|
+
networkConfigKey: 'scanners.semgrep.rules',
|
|
26
|
+
defaultConfig() {
|
|
27
|
+
return { rules: '', severity: [] };
|
|
28
|
+
},
|
|
29
|
+
probe() {
|
|
30
|
+
const executable = which('semgrep');
|
|
31
|
+
if (!executable) {
|
|
32
|
+
return { available: false, version: '', reason: 'semgrep executable not found on PATH' };
|
|
33
|
+
}
|
|
34
|
+
return { available: true, version: versionOf(executable), executable };
|
|
35
|
+
},
|
|
36
|
+
buildCommand(_target, config) {
|
|
37
|
+
const rules = String(config.rules ?? '');
|
|
38
|
+
const argv = [
|
|
39
|
+
'semgrep',
|
|
40
|
+
'scan',
|
|
41
|
+
'--json',
|
|
42
|
+
// No --error: exit status is not a verdict, and 1-on-findings would look
|
|
43
|
+
// like a crash to any later naive consumer.
|
|
44
|
+
...(rules ? ['--config', rules] : ['--config', 'auto']),
|
|
45
|
+
// Network is only needed for --config auto; a vendored rules dir is offline.
|
|
46
|
+
...(rules ? [] : []),
|
|
47
|
+
];
|
|
48
|
+
return { argv, timeoutMs: 300_000, network: !rules };
|
|
49
|
+
},
|
|
50
|
+
parse(raw, context) {
|
|
51
|
+
const parsed = tryParseJson(raw);
|
|
52
|
+
if (!parsed.ok) {
|
|
53
|
+
return [unknown(context, `semgrep output was not valid JSON: ${parsed.error}`)];
|
|
54
|
+
}
|
|
55
|
+
const results = dig(parsed.value, ['results']);
|
|
56
|
+
if (!Array.isArray(results)) {
|
|
57
|
+
return [unknown(context, 'semgrep JSON had no results array (no rules ran?)')];
|
|
58
|
+
}
|
|
59
|
+
// `results: []` means "found nothing" only if semgrep actually read
|
|
60
|
+
// something. `paths.scanned` is the tool's own count, and an empty list
|
|
61
|
+
// there is a blind spot — the same distinction trivy's `Results` guard and
|
|
62
|
+
// dependency-cruiser's rules guard exist to keep. An absent key is not
|
|
63
|
+
// evidence of an empty scan (older builds omit it), so only a present,
|
|
64
|
+
// empty array fires.
|
|
65
|
+
const scanned = dig(parsed.value, ['paths', 'scanned']);
|
|
66
|
+
if (Array.isArray(scanned) && scanned.length === 0) {
|
|
67
|
+
return [
|
|
68
|
+
unknown(context, 'semgrep scanned no files — nothing was analysed, not a clean result'),
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
const out = [];
|
|
72
|
+
for (const [index, result] of results.entries()) {
|
|
73
|
+
out.push(buildEvidence({
|
|
74
|
+
source: {
|
|
75
|
+
tool: 'semgrep',
|
|
76
|
+
kind: 'sast-finding',
|
|
77
|
+
version: context.adapterVersion,
|
|
78
|
+
identifier: String(dig(result, ['check_id']) ?? 'unknown-rule'),
|
|
79
|
+
},
|
|
80
|
+
provenance: placeholder(),
|
|
81
|
+
claim: String(dig(result, ['extra', 'message']) ?? 'semgrep match').slice(0, 160),
|
|
82
|
+
severity: severity(dig(result, ['extra', 'severity'])),
|
|
83
|
+
// Heuristic rule engine, registry-dependent; the number is a policy
|
|
84
|
+
// statement from the adapter, not a measurement.
|
|
85
|
+
confidence: 0.9,
|
|
86
|
+
status: 'FAIL',
|
|
87
|
+
location: {
|
|
88
|
+
// The runner scans a scratch copy, so semgrep reports absolute
|
|
89
|
+
// paths there; evidence must name the file in the project.
|
|
90
|
+
file: relativePath(context.target.workdir, String(dig(result, ['path']) ?? 'unknown')),
|
|
91
|
+
line: lineNumber(dig(result, ['start', 'line'])),
|
|
92
|
+
},
|
|
93
|
+
rawReference: { jsonPath: `results[${index}]` },
|
|
94
|
+
cwes: cwesOf(dig(result, ['extra', 'metadata', 'cwe'])),
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
/** `["CWE-94: Improper Control…"]` → `["CWE-94"]`. */
|
|
101
|
+
function cwesOf(value) {
|
|
102
|
+
if (!Array.isArray(value))
|
|
103
|
+
return [];
|
|
104
|
+
const out = new Set();
|
|
105
|
+
for (const entry of value) {
|
|
106
|
+
const match = /CWE[-_ ]?(\d{1,5})/i.exec(String(entry));
|
|
107
|
+
if (match)
|
|
108
|
+
out.add(`CWE-${Number(match[1])}`);
|
|
109
|
+
}
|
|
110
|
+
return [...out];
|
|
111
|
+
}
|
|
112
|
+
function unknown(context, reason) {
|
|
113
|
+
return {
|
|
114
|
+
id: `UNKNOWN-semgrep-${reason}`.replace(/[^A-Za-z0-9-]/g, '-').slice(0, 48),
|
|
115
|
+
source: {
|
|
116
|
+
tool: 'semgrep',
|
|
117
|
+
version: context.adapterVersion,
|
|
118
|
+
kind: 'check',
|
|
119
|
+
identifier: 'UNKNOWN',
|
|
120
|
+
},
|
|
121
|
+
provenance: placeholder(),
|
|
122
|
+
claim: reason,
|
|
123
|
+
severity: 'INFO',
|
|
124
|
+
severitySource: 'adapter-default',
|
|
125
|
+
confidence: DETERMINISTIC_CONFIDENCE,
|
|
126
|
+
status: 'UNKNOWN',
|
|
127
|
+
location: null,
|
|
128
|
+
rawReference: {},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function placeholder() {
|
|
132
|
+
return {
|
|
133
|
+
executionId: '',
|
|
134
|
+
command: [],
|
|
135
|
+
config: {},
|
|
136
|
+
repositoryRevision: '',
|
|
137
|
+
timestamp: '',
|
|
138
|
+
executable: '',
|
|
139
|
+
timeoutMs: 0,
|
|
140
|
+
elapsedMs: 0,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function which(binary) {
|
|
144
|
+
for (const dir of (process.env.PATH ?? '').split(path.delimiter)) {
|
|
145
|
+
if (!dir)
|
|
146
|
+
continue;
|
|
147
|
+
const candidate = path.join(dir, binary);
|
|
148
|
+
try {
|
|
149
|
+
if (statSync(candidate).isFile())
|
|
150
|
+
return candidate;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* keep looking */
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
function versionOf(executable) {
|
|
159
|
+
const proc = spawnSync(executable, ['--version'], { encoding: 'utf8', timeout: 30_000 });
|
|
160
|
+
const match = /([\d.]+)/.exec(String(proc.stdout ?? ''));
|
|
161
|
+
return match?.[1] ?? 'unknown';
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=semgrep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semgrep.js","sourceRoot":"","sources":["../../../src/scanner/adapters/semgrep.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trivy.d.ts","sourceRoot":"","sources":["../../../src/scanner/adapters/trivy.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAA0B,cAAc,EAAiB,MAAM,aAAa,CAAC;AAIzF,eAAO,MAAM,YAAY,EAAE,cAyF1B,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trivy — Tier 1, and the reference adapter.
|
|
3
|
+
*
|
|
4
|
+
* Verified by running the real binary (v0.75.0) on a fixture package-lock and
|
|
5
|
+
* reading the actual JSON shape, including `PkgIdentifier.PURL`, which gives
|
|
6
|
+
* every finding a stable native identifier.
|
|
7
|
+
*/
|
|
8
|
+
import { spawnSync } from 'node:child_process';
|
|
9
|
+
import { statSync } from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { buildEvidence } from '../identity.js';
|
|
12
|
+
import { DETERMINISTIC_CONFIDENCE, dig, lineNumber, severity, tryParseJson } from '../normalize.js';
|
|
13
|
+
export const trivyAdapter = {
|
|
14
|
+
id: 'trivy',
|
|
15
|
+
name: 'Trivy vulnerability / secret / misconfiguration scanner',
|
|
16
|
+
defaultConfig() {
|
|
17
|
+
return { scanners: ['vuln', 'secret', 'misconfig'], severity: ['HIGH', 'CRITICAL'] };
|
|
18
|
+
},
|
|
19
|
+
probe() {
|
|
20
|
+
const executable = which('trivy');
|
|
21
|
+
if (!executable) {
|
|
22
|
+
return { available: false, version: '', reason: 'trivy executable not found on PATH' };
|
|
23
|
+
}
|
|
24
|
+
return { available: true, version: versionOf(executable), executable };
|
|
25
|
+
},
|
|
26
|
+
buildCommand(target, config) {
|
|
27
|
+
return {
|
|
28
|
+
argv: [
|
|
29
|
+
'trivy',
|
|
30
|
+
'fs',
|
|
31
|
+
'--format',
|
|
32
|
+
'json',
|
|
33
|
+
'--quiet',
|
|
34
|
+
'--scanners',
|
|
35
|
+
config.scanners?.join(',') ?? 'vuln,secret,misconfig',
|
|
36
|
+
// Exit 0 regardless of findings: exit status is never the verdict, so a
|
|
37
|
+
// findings-rich scan must not be smuggled in as a crash.
|
|
38
|
+
'--exit-code',
|
|
39
|
+
'0',
|
|
40
|
+
'--skip-version-check',
|
|
41
|
+
target.workdir,
|
|
42
|
+
],
|
|
43
|
+
timeoutMs: 300_000,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
parse(raw, context) {
|
|
47
|
+
const parsed = tryParseJson(raw);
|
|
48
|
+
if (!parsed.ok) {
|
|
49
|
+
return [unknown(context, `trivy output was not valid JSON: ${parsed.error}`)];
|
|
50
|
+
}
|
|
51
|
+
const results = dig(parsed.value, ['Results']);
|
|
52
|
+
if (!Array.isArray(results)) {
|
|
53
|
+
// An absent Results array means "nothing scanned", which is not
|
|
54
|
+
// "nothing found" — the difference the evidence model exists to keep.
|
|
55
|
+
return [unknown(context, 'trivy report carried no Results array (nothing scanned?)')];
|
|
56
|
+
}
|
|
57
|
+
const out = [];
|
|
58
|
+
for (const [index, result] of results.entries()) {
|
|
59
|
+
const target = String(dig(result, ['Target']) ?? 'unknown');
|
|
60
|
+
out.push(...evidenceOf(result, 'Vulnerabilities', index, 'vulnerability', context.adapterVersion, (item) => [
|
|
61
|
+
String(dig(item, ['VulnerabilityID']) ?? 'unknown'),
|
|
62
|
+
`${dig(item, ['PkgName'])} ${dig(item, ['InstalledVersion'])} is vulnerable to ${dig(item, ['VulnerabilityID'])} (fixed in ${dig(item, ['FixedVersion']) ?? 'unfixed'})`,
|
|
63
|
+
{ file: target },
|
|
64
|
+
]));
|
|
65
|
+
out.push(...evidenceOf(result, 'Secrets', index, 'secret', context.adapterVersion, (item) => [
|
|
66
|
+
String(dig(item, ['RuleID']) ?? 'unknown'),
|
|
67
|
+
`${dig(item, ['Title']) ?? 'possible credential'} detected`,
|
|
68
|
+
{ file: target, line: lineNumber(dig(item, ['StartLine'])) },
|
|
69
|
+
]));
|
|
70
|
+
out.push(...evidenceOf(result, 'Misconfigurations', index, 'misconfiguration', context.adapterVersion, (item) => [
|
|
71
|
+
String(dig(item, ['ID']) ?? 'unknown'),
|
|
72
|
+
`${dig(item, ['Title']) ?? 'misconfiguration'}: ${String(dig(item, ['Message']) ?? '').slice(0, 160)}`,
|
|
73
|
+
{ file: target, line: lineNumber(dig(item, ['CauseMetadata', 'StartLine'])) },
|
|
74
|
+
]));
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
/** One trivy result category → evidence rows. */
|
|
80
|
+
function evidenceOf(result, key, index, kind, adapterVersion, extract) {
|
|
81
|
+
const items = dig(result, [key]);
|
|
82
|
+
if (!Array.isArray(items))
|
|
83
|
+
return [];
|
|
84
|
+
const out = [];
|
|
85
|
+
for (const item of items) {
|
|
86
|
+
const [identifier, claim, location] = extract(item);
|
|
87
|
+
out.push(buildEvidence({
|
|
88
|
+
source: {
|
|
89
|
+
tool: 'trivy',
|
|
90
|
+
kind,
|
|
91
|
+
version: adapterVersion,
|
|
92
|
+
identifier,
|
|
93
|
+
},
|
|
94
|
+
provenance: placeholder(),
|
|
95
|
+
claim,
|
|
96
|
+
severity: severity(dig(item, ['Severity'])),
|
|
97
|
+
// Secrets are heuristic engine matches; the others are deterministic
|
|
98
|
+
// record reads. Saying so is a confidence a reviewer can check.
|
|
99
|
+
confidence: kind === 'secret' ? 0.9 : DETERMINISTIC_CONFIDENCE,
|
|
100
|
+
status: 'FAIL',
|
|
101
|
+
location,
|
|
102
|
+
rawReference: { jsonPath: `Results[${index}]`, excerpt: claim.slice(0, 160) },
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
/** The runner stamps real provenance on every row after parsing. */
|
|
108
|
+
function placeholder() {
|
|
109
|
+
return {
|
|
110
|
+
executionId: '',
|
|
111
|
+
command: [],
|
|
112
|
+
config: {},
|
|
113
|
+
repositoryRevision: '',
|
|
114
|
+
timestamp: '',
|
|
115
|
+
executable: '',
|
|
116
|
+
timeoutMs: 0,
|
|
117
|
+
elapsedMs: 0,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function unknown(context, reason) {
|
|
121
|
+
return {
|
|
122
|
+
id: `UNKNOWN-trivy-${reason}`.replace(/[^A-Za-z0-9-]/g, '-').slice(0, 48),
|
|
123
|
+
source: {
|
|
124
|
+
tool: 'trivy',
|
|
125
|
+
version: context.adapterVersion,
|
|
126
|
+
kind: 'check',
|
|
127
|
+
identifier: 'UNKNOWN',
|
|
128
|
+
},
|
|
129
|
+
provenance: placeholder(),
|
|
130
|
+
claim: reason,
|
|
131
|
+
severity: 'INFO',
|
|
132
|
+
severitySource: 'adapter-default',
|
|
133
|
+
confidence: DETERMINISTIC_CONFIDENCE,
|
|
134
|
+
status: 'UNKNOWN',
|
|
135
|
+
location: null,
|
|
136
|
+
rawReference: {},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/* ---------------------------------------------------------------- process */
|
|
140
|
+
function which(binary) {
|
|
141
|
+
for (const dir of (process.env.PATH ?? '').split(path.delimiter)) {
|
|
142
|
+
if (!dir)
|
|
143
|
+
continue;
|
|
144
|
+
const candidate = path.join(dir, binary);
|
|
145
|
+
try {
|
|
146
|
+
if (statSync(candidate).isFile())
|
|
147
|
+
return candidate;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
/* keep looking — a missing entry is not an error */
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
function versionOf(executable) {
|
|
156
|
+
const proc = spawnSync(executable, ['--version'], {
|
|
157
|
+
encoding: 'utf8',
|
|
158
|
+
timeout: 15_000,
|
|
159
|
+
});
|
|
160
|
+
const match = /Version:?\s*([\w.]+)/.exec(String(proc.stdout ?? ''));
|
|
161
|
+
return match?.[1] ?? 'unknown';
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=trivy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trivy.js","sourceRoot":"","sources":["../../../src/scanner/adapters/trivy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/scanner/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAU7E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { parse as parseYaml } from 'yaml';
|
|
4
|
+
/** Per-project scanner config, `.usa/scanners.yaml`. */
|
|
5
|
+
export function loadScannerConfig(root) {
|
|
6
|
+
const file = path.join(root, '.usa', 'scanners.yaml');
|
|
7
|
+
try {
|
|
8
|
+
const doc = parseYaml(fs.readFileSync(file, 'utf8'));
|
|
9
|
+
return doc?.scanners ?? {};
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/scanner/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAG1C,wDAAwD;AACxD,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAElD,CAAC;QACF,OAAO,GAAG,EAAE,QAAQ,IAAI,EAAE,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Evidence, EvidenceSource, EvidenceLocation, RawReference } from './types.js';
|
|
2
|
+
export declare function evidenceId(source: EvidenceSource, location: EvidenceLocation | null, claim: string): string;
|
|
3
|
+
export declare function buildEvidence(args: {
|
|
4
|
+
source: Omit<EvidenceSource, 'version'> & {
|
|
5
|
+
version?: string;
|
|
6
|
+
};
|
|
7
|
+
provenance: Evidence['provenance'];
|
|
8
|
+
claim: string;
|
|
9
|
+
severity: Evidence['severity'];
|
|
10
|
+
severitySource?: Evidence['severitySource'];
|
|
11
|
+
confidence: number;
|
|
12
|
+
status: Evidence['status'];
|
|
13
|
+
location: EvidenceLocation | null;
|
|
14
|
+
rawReference?: RawReference;
|
|
15
|
+
cwes?: string[];
|
|
16
|
+
}): Evidence;
|
|
17
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/scanner/identity.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS3F,wBAAgB,UAAU,CACxB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,KAAK,EAAE,MAAM,GACZ,MAAM,CAUR;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,UAAU,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,GAAG,QAAQ,CAoBX"}
|