@opensip-cli/tool-osv-scanner 0.1.15
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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +33 -0
- package/dist/__tests__/parse-osv-json.test.d.ts +8 -0
- package/dist/__tests__/parse-osv-json.test.d.ts.map +1 -0
- package/dist/__tests__/parse-osv-json.test.js +271 -0
- package/dist/__tests__/parse-osv-json.test.js.map +1 -0
- package/dist/__tests__/tool.test.d.ts +12 -0
- package/dist/__tests__/tool.test.d.ts.map +1 -0
- package/dist/__tests__/tool.test.js +187 -0
- package/dist/__tests__/tool.test.js.map +1 -0
- package/dist/__tests__/worker-e2e.test.d.ts +28 -0
- package/dist/__tests__/worker-e2e.test.d.ts.map +1 -0
- package/dist/__tests__/worker-e2e.test.js +320 -0
- package/dist/__tests__/worker-e2e.test.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/parse-osv-json.d.ts +35 -0
- package/dist/parse-osv-json.d.ts.map +1 -0
- package/dist/parse-osv-json.js +164 -0
- package/dist/parse-osv-json.js.map +1 -0
- package/dist/tool.d.ts +58 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +116 -0
- package/dist/tool.js.map +1 -0
- package/package.json +138 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OSV-Scanner JSON → normalized `Signal[]` (ADR-0090 §4, brief §4).
|
|
3
|
+
*
|
|
4
|
+
* OSV-Scanner emits a nested document: `results[]` (one per scanned source, e.g. a
|
|
5
|
+
* lockfile) → `packages[]` (one per resolved dependency) → `vulnerabilities[]`
|
|
6
|
+
* (one per advisory) plus a sibling `groups[]` (advisories collapsed by alias,
|
|
7
|
+
* carrying `max_severity` — a CVSS base-score string). One normalized
|
|
8
|
+
* `security` {@link Signal} is emitted per vulnerability.
|
|
9
|
+
*
|
|
10
|
+
* Severity resolution (richest first):
|
|
11
|
+
* 1. `groups[].max_severity` — a CVSS base score string ("7.5") → {@link
|
|
12
|
+
* cvssToSeverity} (FIRST/NVD v3 bands).
|
|
13
|
+
* 2. `database_specific.severity` — the GHSA LABEL (`CRITICAL|HIGH|MODERATE|LOW`;
|
|
14
|
+
* **MODERATE ⇒ medium**, the only non-obvious mapping).
|
|
15
|
+
* 3. neither present ⇒ default `medium` (a known vulnerability with an unknown
|
|
16
|
+
* score is still worth surfacing; documented).
|
|
17
|
+
* The raw label is preserved on `metadata.nativeSeverity`; the raw CVSS string on
|
|
18
|
+
* `metadata.cvss`.
|
|
19
|
+
*
|
|
20
|
+
* OSV carries no per-line anchor (the finding is the lockfile-pinned dependency),
|
|
21
|
+
* so `code.line`/`code.column` are omitted — only `code.file` (the source path) is
|
|
22
|
+
* set. No credentials are present, so there is nothing to redact.
|
|
23
|
+
*
|
|
24
|
+
* Pure: defensive JSON navigation (never throws on malformed input → `[]`).
|
|
25
|
+
*/
|
|
26
|
+
import type { Signal } from '@opensip-cli/core';
|
|
27
|
+
import type { AdapterRunContext, ParsedScannerOutput } from '@opensip-cli/external-tool-adapter';
|
|
28
|
+
/**
|
|
29
|
+
* Parse OSV-Scanner JSON output into normalized signals. An empty/clean run
|
|
30
|
+
* (`{"results":[]}`, or "nothing scanned") yields no findings; each vulnerability
|
|
31
|
+
* maps to a `security` signal whose severity comes from the CVSS `max_severity`
|
|
32
|
+
* (preferred) or the GHSA label (`MODERATE ⇒ medium`), defaulting to `medium`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseOsvJson(raw: ParsedScannerOutput, _ctx: AdapterRunContext): readonly Signal[];
|
|
35
|
+
//# sourceMappingURL=parse-osv-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-osv-json.d.ts","sourceRoot":"","sources":["../src/parse-osv-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAaH,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AA+IjG;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,iBAAiB,GAAG,SAAS,MAAM,EAAE,CAYjG"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OSV-Scanner JSON → normalized `Signal[]` (ADR-0090 §4, brief §4).
|
|
3
|
+
*
|
|
4
|
+
* OSV-Scanner emits a nested document: `results[]` (one per scanned source, e.g. a
|
|
5
|
+
* lockfile) → `packages[]` (one per resolved dependency) → `vulnerabilities[]`
|
|
6
|
+
* (one per advisory) plus a sibling `groups[]` (advisories collapsed by alias,
|
|
7
|
+
* carrying `max_severity` — a CVSS base-score string). One normalized
|
|
8
|
+
* `security` {@link Signal} is emitted per vulnerability.
|
|
9
|
+
*
|
|
10
|
+
* Severity resolution (richest first):
|
|
11
|
+
* 1. `groups[].max_severity` — a CVSS base score string ("7.5") → {@link
|
|
12
|
+
* cvssToSeverity} (FIRST/NVD v3 bands).
|
|
13
|
+
* 2. `database_specific.severity` — the GHSA LABEL (`CRITICAL|HIGH|MODERATE|LOW`;
|
|
14
|
+
* **MODERATE ⇒ medium**, the only non-obvious mapping).
|
|
15
|
+
* 3. neither present ⇒ default `medium` (a known vulnerability with an unknown
|
|
16
|
+
* score is still worth surfacing; documented).
|
|
17
|
+
* The raw label is preserved on `metadata.nativeSeverity`; the raw CVSS string on
|
|
18
|
+
* `metadata.cvss`.
|
|
19
|
+
*
|
|
20
|
+
* OSV carries no per-line anchor (the finding is the lockfile-pinned dependency),
|
|
21
|
+
* so `code.line`/`code.column` are omitted — only `code.file` (the source path) is
|
|
22
|
+
* set. No credentials are present, so there is nothing to redact.
|
|
23
|
+
*
|
|
24
|
+
* Pure: defensive JSON navigation (never throws on malformed input → `[]`).
|
|
25
|
+
*/
|
|
26
|
+
import { createSignal } from '@opensip-cli/core';
|
|
27
|
+
import { asArray, asObject, cvssToSeverity, getString, parseCvss, safeParseJson, withNativeSeverity, } from '@opensip-cli/external-tool-adapter';
|
|
28
|
+
/** Read the parsed OSV document from the descriptor payload, defensively. */
|
|
29
|
+
function osvDocument(raw) {
|
|
30
|
+
// The run loop pre-parses JSON for `kind: 'json'`; fall back to the raw bytes
|
|
31
|
+
// (the acceptance-harness path) so the parser is total either way.
|
|
32
|
+
if (raw.json !== undefined)
|
|
33
|
+
return asObject(raw.json);
|
|
34
|
+
const parsed = safeParseJson(raw.raw);
|
|
35
|
+
return parsed.ok ? asObject(parsed.value) : undefined;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Map a GHSA `database_specific.severity` LABEL to a four-bucket severity.
|
|
39
|
+
* `MODERATE` (GHSA's term) and `MEDIUM` both collapse to `medium`; an unknown
|
|
40
|
+
* label yields `undefined` so the caller can fall through to the default.
|
|
41
|
+
*/
|
|
42
|
+
function labelToSeverity(label) {
|
|
43
|
+
switch (label?.toUpperCase()) {
|
|
44
|
+
case 'CRITICAL': {
|
|
45
|
+
return 'critical';
|
|
46
|
+
}
|
|
47
|
+
case 'HIGH': {
|
|
48
|
+
return 'high';
|
|
49
|
+
}
|
|
50
|
+
case 'MODERATE':
|
|
51
|
+
case 'MEDIUM': {
|
|
52
|
+
return 'medium';
|
|
53
|
+
}
|
|
54
|
+
case 'LOW': {
|
|
55
|
+
return 'low';
|
|
56
|
+
}
|
|
57
|
+
default: {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The `max_severity` CVSS string for a vulnerability: the `groups[]` entry whose
|
|
64
|
+
* `ids` include this vuln id carries it (OSV collapses aliased advisories into one
|
|
65
|
+
* group). Empty/absent ⇒ `undefined`.
|
|
66
|
+
*/
|
|
67
|
+
function maxSeverityForVuln(groups, vulnId) {
|
|
68
|
+
for (const group of groups) {
|
|
69
|
+
const ids = asArray(asObject(group)?.ids) ?? [];
|
|
70
|
+
if (ids.includes(vulnId)) {
|
|
71
|
+
const score = getString(group, 'max_severity');
|
|
72
|
+
if (score !== undefined && score.length > 0)
|
|
73
|
+
return score;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
/** Compose the human message: `<summary> (<pkg>@<version>)`, with defensive fallbacks. */
|
|
79
|
+
function buildMessage(summary, ruleId, pkg, installed) {
|
|
80
|
+
const base = summary ?? ruleId;
|
|
81
|
+
if (pkg === undefined)
|
|
82
|
+
return base;
|
|
83
|
+
const ref = installed === undefined ? pkg : `${pkg}@${installed}`;
|
|
84
|
+
return `${base} (${ref})`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Normalize one OSV vulnerability (within a package + source) to a {@link Signal}.
|
|
88
|
+
* Returns `undefined` for a non-object entry so a malformed element is skipped
|
|
89
|
+
* rather than throwing.
|
|
90
|
+
*/
|
|
91
|
+
function normalizeVulnerability(entry, groups, context) {
|
|
92
|
+
const vuln = asObject(entry);
|
|
93
|
+
if (vuln === undefined)
|
|
94
|
+
return undefined;
|
|
95
|
+
const ruleId = getString(vuln, 'id') ?? 'osv-vulnerability';
|
|
96
|
+
const summary = getString(vuln, 'summary');
|
|
97
|
+
const details = getString(vuln, 'details');
|
|
98
|
+
const aliases = (asArray(vuln.aliases) ?? []).filter((a) => typeof a === 'string');
|
|
99
|
+
const label = getString(asObject(vuln.database_specific), 'severity');
|
|
100
|
+
// Severity: CVSS max_severity (numeric) first, then the GHSA label, then default.
|
|
101
|
+
const cvss = maxSeverityForVuln(groups, ruleId);
|
|
102
|
+
const cvssScore = parseCvss(cvss);
|
|
103
|
+
const severity = cvssScore === undefined ? (labelToSeverity(label) ?? 'medium') : cvssToSeverity(cvssScore);
|
|
104
|
+
const metadata = withNativeSeverity({
|
|
105
|
+
aliases,
|
|
106
|
+
ecosystem: context.ecosystem ?? null,
|
|
107
|
+
pkg: context.pkg ?? null,
|
|
108
|
+
installed: context.installed ?? null,
|
|
109
|
+
cvss: cvss ?? null,
|
|
110
|
+
},
|
|
111
|
+
// Preserve the scanner's own severity label (null when it emits none).
|
|
112
|
+
label ?? null);
|
|
113
|
+
return createSignal({
|
|
114
|
+
source: 'osv-scanner',
|
|
115
|
+
category: 'security',
|
|
116
|
+
severity,
|
|
117
|
+
ruleId,
|
|
118
|
+
message: buildMessage(summary, ruleId, context.pkg, context.installed),
|
|
119
|
+
...(details === undefined ? {} : { suggestion: details }),
|
|
120
|
+
// OSV anchors a finding at the lockfile (no line) — set only `code.file`.
|
|
121
|
+
code: { file: context.sourcePath },
|
|
122
|
+
metadata,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/** Normalize every vulnerability inside one `packages[]` entry. */
|
|
126
|
+
function normalizePackage(entry, sourcePath) {
|
|
127
|
+
const packageEntry = asObject(entry);
|
|
128
|
+
if (packageEntry === undefined)
|
|
129
|
+
return [];
|
|
130
|
+
const pkgInfo = asObject(packageEntry.package);
|
|
131
|
+
const context = {
|
|
132
|
+
sourcePath,
|
|
133
|
+
pkg: getString(pkgInfo, 'name'),
|
|
134
|
+
installed: getString(pkgInfo, 'version'),
|
|
135
|
+
ecosystem: getString(pkgInfo, 'ecosystem'),
|
|
136
|
+
};
|
|
137
|
+
const groups = asArray(packageEntry.groups) ?? [];
|
|
138
|
+
const signals = [];
|
|
139
|
+
for (const vuln of asArray(packageEntry.vulnerabilities) ?? []) {
|
|
140
|
+
const signal = normalizeVulnerability(vuln, groups, context);
|
|
141
|
+
if (signal !== undefined)
|
|
142
|
+
signals.push(signal);
|
|
143
|
+
}
|
|
144
|
+
return signals;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Parse OSV-Scanner JSON output into normalized signals. An empty/clean run
|
|
148
|
+
* (`{"results":[]}`, or "nothing scanned") yields no findings; each vulnerability
|
|
149
|
+
* maps to a `security` signal whose severity comes from the CVSS `max_severity`
|
|
150
|
+
* (preferred) or the GHSA label (`MODERATE ⇒ medium`), defaulting to `medium`.
|
|
151
|
+
*/
|
|
152
|
+
export function parseOsvJson(raw, _ctx) {
|
|
153
|
+
const doc = osvDocument(raw);
|
|
154
|
+
const results = asArray(doc?.results) ?? [];
|
|
155
|
+
const signals = [];
|
|
156
|
+
for (const result of results) {
|
|
157
|
+
const sourcePath = getString(asObject(result)?.source, 'path') ?? '';
|
|
158
|
+
for (const packageEntry of asArray(asObject(result)?.packages) ?? []) {
|
|
159
|
+
signals.push(...normalizePackage(packageEntry, sourcePath));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return signals;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=parse-osv-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-osv-json.js","sourceRoot":"","sources":["../src/parse-osv-json.ts"],"names":[],"mappings":"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"}
|
package/dist/tool.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@opensip-cli/tool-osv-scanner` Tool descriptor (ADR-0090 / ADR-0091 / ADR-0092).
|
|
3
|
+
*
|
|
4
|
+
* The second External Tool Adapter: it wraps the user-installed `osv-scanner`
|
|
5
|
+
* dependency-vulnerability scanner as an ordinary opensip-cli `Tool` via {@link
|
|
6
|
+
* defineExternalToolAdapter}. The substrate owns binary resolution, the run loop
|
|
7
|
+
* (resolve → execFile → ingest → normalize → persist via the host artifact seam),
|
|
8
|
+
* provenance, and the auto-added `doctor`/`version` commands; this module declares
|
|
9
|
+
* only the osv-scanner identity, the wrapped binary, and the `scan` command (args
|
|
10
|
+
* + JSON parser).
|
|
11
|
+
*
|
|
12
|
+
* Like gitleaks, this is a JSON adapter (it routes OSV-Scanner's `--format json`,
|
|
13
|
+
* which is richer than its SARIF output, through a per-adapter `parse`, NOT the
|
|
14
|
+
* shared `ingestSarif`).
|
|
15
|
+
*
|
|
16
|
+
* Layer 4: imports the substrate + `@opensip-cli/core` ONLY — never the CLI,
|
|
17
|
+
* output, or any other adapter (dependency-cruiser enforced).
|
|
18
|
+
*
|
|
19
|
+
* This is an OPT-IN, installed tool (NOT in `bundled-tools.manifest.json`): the
|
|
20
|
+
* host never imports this runtime; an `opensip osv-scanner` / `opensip osv`
|
|
21
|
+
* invocation forks a worker that re-discovers + imports it and runs the handler.
|
|
22
|
+
* Installed tools are deny-by-default — a run needs
|
|
23
|
+
* `OPENSIP_CLI_ALLOW_INSTALLED_TOOLS` to include the osv-scanner id.
|
|
24
|
+
*/
|
|
25
|
+
import type { Tool, ToolIdentity } from '@opensip-cli/core';
|
|
26
|
+
import type { AdapterRunContext } from '@opensip-cli/external-tool-adapter';
|
|
27
|
+
/** Human/aliased identity (`opensip osv-scanner` / `opensip osv`). */
|
|
28
|
+
export declare const OSV_SCANNER_IDENTITY: ToolIdentity;
|
|
29
|
+
/** Stable UUID identity (ADR-0048); mirrors `opensipTools.stableId` in package.json. */
|
|
30
|
+
export declare const OSV_SCANNER_STABLE_ID = "d25a4471-3289-4660-b5ab-63830072d0e1";
|
|
31
|
+
/**
|
|
32
|
+
* Normalize the `osv-scanner --version` stdout to a bare semver. OSV-Scanner
|
|
33
|
+
* prints a multi-line banner whose first line is e.g. `osv-scanner version: 1.9.1`
|
|
34
|
+
* (or, on some builds, just `1.9.1`); take the first semver-shaped token and strip
|
|
35
|
+
* a leading `v`.
|
|
36
|
+
*
|
|
37
|
+
* VERIFY-against-installed-binary: exact `osv-scanner --version` output format.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseOsvVersion(stdout: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Build the osv-scanner scan argv (no shell — args are passed to `execFile`).
|
|
42
|
+
* Scans the project recursively (`-r <root>`) and writes a JSON report to the
|
|
43
|
+
* host-owned artifact path the substrate composes for this run. OSV-Scanner ships
|
|
44
|
+
* an embedded/offline advisory DB, so the scan is local-only (no network, no auth).
|
|
45
|
+
*
|
|
46
|
+
* VERIFY-against-installed-binary: this is the stable v1.x flat invocation
|
|
47
|
+
* (`osv-scanner --format json --output <path> -r <root>`). OSV-Scanner v2.x
|
|
48
|
+
* reorganized the surface to `osv-scanner scan source -r <root>`; if v2 becomes the
|
|
49
|
+
* floor, switch on the doctor-detected version. (The flags `--format`, `--output`,
|
|
50
|
+
* `-r` are stable across both.)
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildScanArgs(ctx: AdapterRunContext): readonly string[];
|
|
53
|
+
/**
|
|
54
|
+
* The osv-scanner external-tool adapter `Tool`. The host loads it by name through
|
|
55
|
+
* the installed-tool worker-dispatch path (the barrel re-exports it as `tool`).
|
|
56
|
+
*/
|
|
57
|
+
export declare const tool: Tool;
|
|
58
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,EAAE,YAGlC,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,qBAAqB,yCAAyC,CAAC;AAE5E;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,SAAS,MAAM,EAAE,CAEvE;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,EAAE,IAgDjB,CAAC"}
|
package/dist/tool.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@opensip-cli/tool-osv-scanner` Tool descriptor (ADR-0090 / ADR-0091 / ADR-0092).
|
|
3
|
+
*
|
|
4
|
+
* The second External Tool Adapter: it wraps the user-installed `osv-scanner`
|
|
5
|
+
* dependency-vulnerability scanner as an ordinary opensip-cli `Tool` via {@link
|
|
6
|
+
* defineExternalToolAdapter}. The substrate owns binary resolution, the run loop
|
|
7
|
+
* (resolve → execFile → ingest → normalize → persist via the host artifact seam),
|
|
8
|
+
* provenance, and the auto-added `doctor`/`version` commands; this module declares
|
|
9
|
+
* only the osv-scanner identity, the wrapped binary, and the `scan` command (args
|
|
10
|
+
* + JSON parser).
|
|
11
|
+
*
|
|
12
|
+
* Like gitleaks, this is a JSON adapter (it routes OSV-Scanner's `--format json`,
|
|
13
|
+
* which is richer than its SARIF output, through a per-adapter `parse`, NOT the
|
|
14
|
+
* shared `ingestSarif`).
|
|
15
|
+
*
|
|
16
|
+
* Layer 4: imports the substrate + `@opensip-cli/core` ONLY — never the CLI,
|
|
17
|
+
* output, or any other adapter (dependency-cruiser enforced).
|
|
18
|
+
*
|
|
19
|
+
* This is an OPT-IN, installed tool (NOT in `bundled-tools.manifest.json`): the
|
|
20
|
+
* host never imports this runtime; an `opensip osv-scanner` / `opensip osv`
|
|
21
|
+
* invocation forks a worker that re-discovers + imports it and runs the handler.
|
|
22
|
+
* Installed tools are deny-by-default — a run needs
|
|
23
|
+
* `OPENSIP_CLI_ALLOW_INSTALLED_TOOLS` to include the osv-scanner id.
|
|
24
|
+
*/
|
|
25
|
+
import { readPackageVersion } from '@opensip-cli/core';
|
|
26
|
+
import { defineExternalToolAdapter } from '@opensip-cli/external-tool-adapter';
|
|
27
|
+
import { parseOsvJson } from './parse-osv-json.js';
|
|
28
|
+
/** Human/aliased identity (`opensip osv-scanner` / `opensip osv`). */
|
|
29
|
+
export const OSV_SCANNER_IDENTITY = {
|
|
30
|
+
name: 'osv-scanner',
|
|
31
|
+
aliases: ['osv'],
|
|
32
|
+
};
|
|
33
|
+
/** Stable UUID identity (ADR-0048); mirrors `opensipTools.stableId` in package.json. */
|
|
34
|
+
export const OSV_SCANNER_STABLE_ID = 'd25a4471-3289-4660-b5ab-63830072d0e1';
|
|
35
|
+
/**
|
|
36
|
+
* Normalize the `osv-scanner --version` stdout to a bare semver. OSV-Scanner
|
|
37
|
+
* prints a multi-line banner whose first line is e.g. `osv-scanner version: 1.9.1`
|
|
38
|
+
* (or, on some builds, just `1.9.1`); take the first semver-shaped token and strip
|
|
39
|
+
* a leading `v`.
|
|
40
|
+
*
|
|
41
|
+
* VERIFY-against-installed-binary: exact `osv-scanner --version` output format.
|
|
42
|
+
*/
|
|
43
|
+
export function parseOsvVersion(stdout) {
|
|
44
|
+
// Fully bounded ({1,5} digit runs, {1,2} dotted segments) so the matcher is
|
|
45
|
+
// linear — major.minor[.patch], optional leading `v`.
|
|
46
|
+
const match = /v?(\d{1,5}(?:\.\d{1,5}){1,2})/.exec(stdout);
|
|
47
|
+
return match?.[1] ?? stdout.trim();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build the osv-scanner scan argv (no shell — args are passed to `execFile`).
|
|
51
|
+
* Scans the project recursively (`-r <root>`) and writes a JSON report to the
|
|
52
|
+
* host-owned artifact path the substrate composes for this run. OSV-Scanner ships
|
|
53
|
+
* an embedded/offline advisory DB, so the scan is local-only (no network, no auth).
|
|
54
|
+
*
|
|
55
|
+
* VERIFY-against-installed-binary: this is the stable v1.x flat invocation
|
|
56
|
+
* (`osv-scanner --format json --output <path> -r <root>`). OSV-Scanner v2.x
|
|
57
|
+
* reorganized the surface to `osv-scanner scan source -r <root>`; if v2 becomes the
|
|
58
|
+
* floor, switch on the doctor-detected version. (The flags `--format`, `--output`,
|
|
59
|
+
* `-r` are stable across both.)
|
|
60
|
+
*/
|
|
61
|
+
export function buildScanArgs(ctx) {
|
|
62
|
+
return ['--format', 'json', '--output', ctx.artifactPath('osv.json'), '-r', ctx.projectRoot];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The osv-scanner external-tool adapter `Tool`. The host loads it by name through
|
|
66
|
+
* the installed-tool worker-dispatch path (the barrel re-exports it as `tool`).
|
|
67
|
+
*/
|
|
68
|
+
export const tool = defineExternalToolAdapter({
|
|
69
|
+
identity: OSV_SCANNER_IDENTITY,
|
|
70
|
+
metadata: {
|
|
71
|
+
id: OSV_SCANNER_STABLE_ID,
|
|
72
|
+
version: readPackageVersion(import.meta.url),
|
|
73
|
+
description: 'Dependency vulnerability scanning via OSV-Scanner',
|
|
74
|
+
adapterPackage: '@opensip-cli/tool-osv-scanner',
|
|
75
|
+
},
|
|
76
|
+
binary: {
|
|
77
|
+
command: 'osv-scanner',
|
|
78
|
+
versionArgs: ['--version'],
|
|
79
|
+
versionParse: parseOsvVersion,
|
|
80
|
+
// The flat `--format json --output -r` invocation is stable from v1.4.
|
|
81
|
+
// VERIFY-against-installed-binary (v2.x moved verbs under `scan source`).
|
|
82
|
+
minVersion: '1.4.0',
|
|
83
|
+
// Operator pin (config `binaries.osv-scanner.path` / `OPENSIP_OSV_SCANNER_BIN`)
|
|
84
|
+
// beats PATH; resolution never fetches a binary.
|
|
85
|
+
resolution: ['config', 'path'],
|
|
86
|
+
installHint: 'Install osv-scanner: https://google.github.io/osv-scanner/installation/ (brew install osv-scanner)',
|
|
87
|
+
},
|
|
88
|
+
// OSV-Scanner queries its embedded/offline advisory DB via execFile — no
|
|
89
|
+
// network, no credentials.
|
|
90
|
+
network: 'local-only',
|
|
91
|
+
commands: [
|
|
92
|
+
{
|
|
93
|
+
name: 'scan',
|
|
94
|
+
description: 'Scan project dependencies for known vulnerabilities (OSV-Scanner)',
|
|
95
|
+
args: buildScanArgs,
|
|
96
|
+
output: { kind: 'json', path: 'osv.json' },
|
|
97
|
+
// ADR-0091 Phase-0 decision 4 (OSV): `0` clean, `1` findings, `>=2` fault.
|
|
98
|
+
// The exception is `128` ("no packages/lockfiles found") — a genuinely CLEAN
|
|
99
|
+
// no-op (a project with no dependency manifests), NOT a fault, so it joins the
|
|
100
|
+
// `ok` set. With `errorFrom: 2`, `127` (general/usage error) still faults.
|
|
101
|
+
// VERIFY-against-installed-binary: the exact nothing-scanned code (recollection
|
|
102
|
+
// 128) across versions.
|
|
103
|
+
exitCodes: { ok: [0, 128], findings: [1], errorFrom: 2 },
|
|
104
|
+
parse: parseOsvJson,
|
|
105
|
+
// A3 (no `excludeScan`): OSV-Scanner only parses recognized lockfiles/SBOMs,
|
|
106
|
+
// never an arbitrary JSON report, so it does NOT re-detect opensip's own
|
|
107
|
+
// persisted reports under `.runtime/` — there is no fingerprint churn to guard
|
|
108
|
+
// against, and OSV-Scanner v1.x exposes no path-exclude flag (only `--no-ignore`
|
|
109
|
+
// for .gitignore and vuln-id ignores). It is therefore left without an exclusion.
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
// Scanner output is line-volatile → the line-shift-tolerant message hash, not the
|
|
113
|
+
// host `ruleId|file|line|col` default. Stamped worker-side in the run loop.
|
|
114
|
+
fingerprintStrategy: 'message-hash',
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=tool.js.map
|
package/dist/tool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAE/E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKnD,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAiB;IAChD,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,CAAC,KAAK,CAAC;CACjB,CAAC;AAEF,wFAAwF;AACxF,MAAM,CAAC,MAAM,qBAAqB,GAAG,sCAAsC,CAAC;AAE5E;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,4EAA4E;IAC5E,sDAAsD;IACtD,MAAM,KAAK,GAAG,+BAA+B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,GAAsB;IAClD,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;AAC/F,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAS,yBAAyB,CAAC;IAClD,QAAQ,EAAE,oBAAoB;IAC9B,QAAQ,EAAE;QACR,EAAE,EAAE,qBAAqB;QACzB,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAC5C,WAAW,EAAE,mDAAmD;QAChE,cAAc,EAAE,+BAA+B;KAChD;IACD,MAAM,EAAE;QACN,OAAO,EAAE,aAAa;QACtB,WAAW,EAAE,CAAC,WAAW,CAAC;QAC1B,YAAY,EAAE,eAAe;QAC7B,uEAAuE;QACvE,0EAA0E;QAC1E,UAAU,EAAE,OAAO;QACnB,gFAAgF;QAChF,iDAAiD;QACjD,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC9B,WAAW,EACT,oGAAoG;KACvG;IACD,yEAAyE;IACzE,2BAA2B;IAC3B,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,mEAAmE;YAChF,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE;YAC1C,2EAA2E;YAC3E,6EAA6E;YAC7E,+EAA+E;YAC/E,2EAA2E;YAC3E,gFAAgF;YAChF,wBAAwB;YACxB,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;YACxD,KAAK,EAAE,YAAY;YACnB,6EAA6E;YAC7E,yEAAyE;YACzE,+EAA+E;YAC/E,iFAAiF;YACjF,kFAAkF;SACnF;KACF;IACD,kFAAkF;IAClF,4EAA4E;IAC5E,mBAAmB,EAAE,cAAc;CACpC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opensip-cli/tool-osv-scanner",
|
|
3
|
+
"version": "0.1.15",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"description": "External Tool Adapter for OSV-Scanner — wraps the osv-scanner dependency vulnerability scanner as an opensip-cli tool (opensip osv-scanner / opensip osv)",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"opensip-cli",
|
|
8
|
+
"static-analysis",
|
|
9
|
+
"code-quality"
|
|
10
|
+
],
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/opensip-ai/opensip-cli.git",
|
|
14
|
+
"directory": "packages/tool-osv-scanner"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/opensip-ai/opensip-cli",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/opensip-ai/opensip-cli/issues"
|
|
19
|
+
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"NOTICE"
|
|
30
|
+
],
|
|
31
|
+
"opensipTools": {
|
|
32
|
+
"kind": "tool",
|
|
33
|
+
"id": "osv-scanner",
|
|
34
|
+
"identity": {
|
|
35
|
+
"name": "osv-scanner",
|
|
36
|
+
"aliases": [
|
|
37
|
+
"osv"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"stableId": "d25a4471-3289-4660-b5ab-63830072d0e1",
|
|
41
|
+
"apiVersion": 1,
|
|
42
|
+
"requires": [
|
|
43
|
+
{
|
|
44
|
+
"resource": "subprocess",
|
|
45
|
+
"reason": "Executes the user-installed osv-scanner binary via execFile (no shell)"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"resource": "filesystem",
|
|
49
|
+
"reason": "Reads the project working tree and writes the raw scan artifact under .runtime/artifacts"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"commands": [
|
|
53
|
+
{
|
|
54
|
+
"name": "osv-scanner",
|
|
55
|
+
"description": "Scan project dependencies for known vulnerabilities (OSV-Scanner)",
|
|
56
|
+
"aliases": [
|
|
57
|
+
"osv"
|
|
58
|
+
],
|
|
59
|
+
"commonFlags": [
|
|
60
|
+
"json",
|
|
61
|
+
"cwd",
|
|
62
|
+
"quiet",
|
|
63
|
+
"verbose",
|
|
64
|
+
"debug",
|
|
65
|
+
"reportTo",
|
|
66
|
+
"apiKey",
|
|
67
|
+
"open"
|
|
68
|
+
],
|
|
69
|
+
"options": [
|
|
70
|
+
{
|
|
71
|
+
"flag": "--gate-save",
|
|
72
|
+
"description": "Architecture-gate: save current findings as baseline in the project SQLite store (mutually exclusive with --gate-compare)",
|
|
73
|
+
"default": false
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"flag": "--gate-compare",
|
|
77
|
+
"description": "Architecture-gate: compare current findings against the saved baseline; exit 1 on regression",
|
|
78
|
+
"default": false
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"scope": "project",
|
|
82
|
+
"output": "raw-stream",
|
|
83
|
+
"rawStreamReason": "runtime-render-dispatch"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "doctor",
|
|
87
|
+
"description": "Check that the osv-scanner binary is installed and ready",
|
|
88
|
+
"parent": "osv-scanner",
|
|
89
|
+
"commonFlags": [
|
|
90
|
+
"json",
|
|
91
|
+
"cwd"
|
|
92
|
+
],
|
|
93
|
+
"scope": "none",
|
|
94
|
+
"output": "raw-stream",
|
|
95
|
+
"rawStreamReason": "diagnostic-gate"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "version",
|
|
99
|
+
"description": "Print the resolved osv-scanner binary version",
|
|
100
|
+
"parent": "osv-scanner",
|
|
101
|
+
"commonFlags": [
|
|
102
|
+
"json",
|
|
103
|
+
"cwd"
|
|
104
|
+
],
|
|
105
|
+
"scope": "none",
|
|
106
|
+
"output": "raw-stream",
|
|
107
|
+
"rawStreamReason": "diagnostic-gate"
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
"config": {
|
|
111
|
+
"namespace": "osv-scanner",
|
|
112
|
+
"schema": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"properties": {
|
|
115
|
+
"binaries": {
|
|
116
|
+
"type": "object"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"dependencies": {
|
|
123
|
+
"typescript": "~6.0.3",
|
|
124
|
+
"@opensip-cli/external-tool-adapter": "0.1.15",
|
|
125
|
+
"@opensip-cli/contracts": "0.1.15",
|
|
126
|
+
"@opensip-cli/core": "0.1.15"
|
|
127
|
+
},
|
|
128
|
+
"devDependencies": {
|
|
129
|
+
"@types/node": "^24.13.2",
|
|
130
|
+
"vitest": "^4.1.8"
|
|
131
|
+
},
|
|
132
|
+
"scripts": {
|
|
133
|
+
"build": "tsc",
|
|
134
|
+
"test": "vitest run --passWithNoTests",
|
|
135
|
+
"typecheck": "tsc --noEmit",
|
|
136
|
+
"clean": "rm -rf dist"
|
|
137
|
+
}
|
|
138
|
+
}
|