@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,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-1 (in-process) tests for the osv-scanner adapter `Tool` (ADR-0090 D6
|
|
3
|
+
* Tier 1).
|
|
4
|
+
*
|
|
5
|
+
* Asserts the declarative surface (commandSpecs / identity / metadata), the binary
|
|
6
|
+
* helpers (version parse + scan args), the FROZEN exit model (Phase-0 decision 4 —
|
|
7
|
+
* incl. the `128` nothing-scanned no-op), the manifest↔runtime host-shape guards
|
|
8
|
+
* (`assertManifestMatchesTool` + `deriveAdapterManifestCommands` parity), and the
|
|
9
|
+
* full normalize→envelope path via the acceptance harness.
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { assertManifestMatchesTool } from '@opensip-cli/core';
|
|
14
|
+
import { DEFAULT_EXIT_MODEL, deriveAdapterConfigManifest, deriveAdapterManifestCommands, deriveAdapterManifestRequires, interpretExit, normalizedSignalShape, runAcceptanceCase, } from '@opensip-cli/external-tool-adapter';
|
|
15
|
+
import { describe, expect, it } from 'vitest';
|
|
16
|
+
import { parseOsvJson } from '../parse-osv-json.js';
|
|
17
|
+
import { buildScanArgs, OSV_SCANNER_STABLE_ID, parseOsvVersion, tool } from '../tool.js';
|
|
18
|
+
const PKG = JSON.parse(readFileSync(fileURLToPath(new URL('../../package.json', import.meta.url)), 'utf8'));
|
|
19
|
+
const GOLDEN_RAW = readFileSync(fileURLToPath(new URL('../../__fixtures__/osv-golden.json', import.meta.url)), 'utf8');
|
|
20
|
+
const EXPECTED = JSON.parse(readFileSync(fileURLToPath(new URL('../../__fixtures__/expected-signals.json', import.meta.url)), 'utf8'));
|
|
21
|
+
/** Reconstruct the admitted `ToolPluginManifest` the host builds from package.json. */
|
|
22
|
+
function manifestFromPackage() {
|
|
23
|
+
return {
|
|
24
|
+
...PKG.opensipTools,
|
|
25
|
+
name: PKG.name,
|
|
26
|
+
version: PKG.version,
|
|
27
|
+
apiVersion: PKG.opensipTools.apiVersion,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
describe('osv-scanner tool — identity + metadata', () => {
|
|
31
|
+
it('declares the osv-scanner identity with the `osv` alias', () => {
|
|
32
|
+
expect(tool.identity).toEqual({ name: 'osv-scanner', aliases: ['osv'] });
|
|
33
|
+
});
|
|
34
|
+
it('carries the stable UUID and a description', () => {
|
|
35
|
+
expect(tool.metadata.id).toBe(OSV_SCANNER_STABLE_ID);
|
|
36
|
+
expect(tool.metadata.name).toBe('osv-scanner');
|
|
37
|
+
expect(tool.metadata.description).toBe('Dependency vulnerability scanning via OSV-Scanner');
|
|
38
|
+
});
|
|
39
|
+
it('defaults to the line-shift-tolerant message-hash fingerprint strategy', () => {
|
|
40
|
+
expect(tool.extensionPoints?.fingerprintStrategy?.id).toBe('external-tool-adapter.sha256-file-rule-message');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
const byName = (name) => tool.commandSpecs?.find((c) => c.name === name);
|
|
44
|
+
describe('osv-scanner tool — commandSpecs', () => {
|
|
45
|
+
it('mounts the primary scan, plus nested doctor + version', () => {
|
|
46
|
+
const names = (tool.commandSpecs ?? []).map((c) => c.name);
|
|
47
|
+
expect(names).toEqual(['osv-scanner', 'doctor', 'version']);
|
|
48
|
+
});
|
|
49
|
+
it('the primary command is `osv-scanner` (aliased `osv`), project-scoped, raw-stream dispatch', () => {
|
|
50
|
+
const primary = byName('osv-scanner');
|
|
51
|
+
expect(primary?.parent).toBeUndefined();
|
|
52
|
+
expect(primary?.aliases).toEqual(['osv']);
|
|
53
|
+
expect(primary?.scope).toBe('project');
|
|
54
|
+
expect(primary?.output).toBe('raw-stream');
|
|
55
|
+
expect(primary?.rawStreamReason).toBe('runtime-render-dispatch');
|
|
56
|
+
});
|
|
57
|
+
it('doctor + version are nested under osv-scanner, scope:none, diagnostic-gate', () => {
|
|
58
|
+
for (const name of ['doctor', 'version']) {
|
|
59
|
+
const spec = byName(name);
|
|
60
|
+
expect(spec?.parent).toBe('osv-scanner');
|
|
61
|
+
expect(spec?.scope).toBe('none');
|
|
62
|
+
expect(spec?.output).toBe('raw-stream');
|
|
63
|
+
expect(spec?.rawStreamReason).toBe('diagnostic-gate');
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('osv-scanner tool — binary helpers', () => {
|
|
68
|
+
it('parses the osv-scanner version stdout (banner, bare semver, or leading v)', () => {
|
|
69
|
+
expect(parseOsvVersion('osv-scanner version: 1.9.1')).toBe('1.9.1');
|
|
70
|
+
expect(parseOsvVersion('1.7.0\n')).toBe('1.7.0');
|
|
71
|
+
expect(parseOsvVersion('v2.0.0')).toBe('2.0.0');
|
|
72
|
+
});
|
|
73
|
+
it('falls back to the trimmed stdout when no semver is present', () => {
|
|
74
|
+
expect(parseOsvVersion(' unknown ')).toBe('unknown');
|
|
75
|
+
});
|
|
76
|
+
it('builds the recursive-scan argv writing JSON to the run artifact path', () => {
|
|
77
|
+
const ctx = {
|
|
78
|
+
projectRoot: '/proj',
|
|
79
|
+
artifactPath: (name) => `/proj/.runtime/artifacts/osv-scanner/run1/${name}`,
|
|
80
|
+
};
|
|
81
|
+
expect(buildScanArgs(ctx)).toEqual([
|
|
82
|
+
'--format',
|
|
83
|
+
'json',
|
|
84
|
+
'--output',
|
|
85
|
+
'/proj/.runtime/artifacts/osv-scanner/run1/osv.json',
|
|
86
|
+
'-r',
|
|
87
|
+
'/proj',
|
|
88
|
+
]);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe('osv-scanner tool — exit model (Phase-0 decision 4)', () => {
|
|
92
|
+
// Frozen OSV model: `128` ("no packages found") is a CLEAN no-op, not a fault.
|
|
93
|
+
const model = { ok: [0, 128], findings: [1], errorFrom: 2 };
|
|
94
|
+
it('exit 0 ⇒ clean (no findings)', () => {
|
|
95
|
+
expect(interpretExit(0, model)).toBe('ok');
|
|
96
|
+
});
|
|
97
|
+
it('exit 1 + a valid artifact ⇒ findings', () => {
|
|
98
|
+
expect(interpretExit(1, model, { artifactValid: true })).toBe('findings');
|
|
99
|
+
});
|
|
100
|
+
it('exit 128 ⇒ clean no-op (no packages/lockfiles found), NOT a fault', () => {
|
|
101
|
+
expect(interpretExit(128, model)).toBe('ok');
|
|
102
|
+
});
|
|
103
|
+
it('exit 127 (general error) ⇒ fault', () => {
|
|
104
|
+
expect(interpretExit(127, model)).toBe('fault');
|
|
105
|
+
});
|
|
106
|
+
it('exit 2 ⇒ fault', () => {
|
|
107
|
+
expect(interpretExit(2, model)).toBe('fault');
|
|
108
|
+
});
|
|
109
|
+
it('matches the runtime command exit model, which EXTENDS the substrate default with 128', () => {
|
|
110
|
+
const primary = byName('osv-scanner');
|
|
111
|
+
// The runtime spec stores the exit model on the primary command's args closure
|
|
112
|
+
// indirectly; assert the frozen shape and that it diverges from the default by
|
|
113
|
+
// exactly the nothing-scanned code.
|
|
114
|
+
expect(model).not.toEqual(DEFAULT_EXIT_MODEL);
|
|
115
|
+
expect(model.ok).toEqual([0, 128]);
|
|
116
|
+
expect(primary).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('osv-scanner tool — manifest ↔ runtime host-shape guards', () => {
|
|
120
|
+
it('the package.json manifest matches the runtime tool (no drift)', () => {
|
|
121
|
+
expect(() => {
|
|
122
|
+
assertManifestMatchesTool(manifestFromPackage(), tool);
|
|
123
|
+
}).not.toThrow();
|
|
124
|
+
});
|
|
125
|
+
it('the generated manifest commands equal the derived runtime command shells', () => {
|
|
126
|
+
// The package.json `commands` are written by the shared manifest generator
|
|
127
|
+
// (which OMITS an empty `aliases`), while the substrate's
|
|
128
|
+
// `deriveAdapterManifestCommands` always emits `aliases: []`. Canonicalize that
|
|
129
|
+
// one representational difference (`aliases ?? []`) before comparing the
|
|
130
|
+
// substantive shells.
|
|
131
|
+
const canon = (c) => ({
|
|
132
|
+
...c,
|
|
133
|
+
aliases: c.aliases ?? [],
|
|
134
|
+
});
|
|
135
|
+
const generated = PKG.opensipTools.commands.map(canon);
|
|
136
|
+
const derived = deriveAdapterManifestCommands(tool).map((c) => canon(c));
|
|
137
|
+
expect(generated).toEqual(derived);
|
|
138
|
+
});
|
|
139
|
+
it('the generated manifest requires equal the posture-derived requires (no drift)', () => {
|
|
140
|
+
// A13: `requires` is DERIVED from the network posture, not hand-typed.
|
|
141
|
+
expect(PKG.opensipTools.requires).toEqual(deriveAdapterManifestRequires(tool));
|
|
142
|
+
});
|
|
143
|
+
it('derives subprocess + filesystem only (local-only posture, no network)', () => {
|
|
144
|
+
expect(PKG.opensipTools.requires.map((r) => r.resource)).toEqual([
|
|
145
|
+
'subprocess',
|
|
146
|
+
'filesystem',
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
it('the generated manifest config descriptor equals the derived namespace claim (A4)', () => {
|
|
150
|
+
const derived = deriveAdapterConfigManifest(tool);
|
|
151
|
+
expect(derived?.namespace).toBe('osv-scanner');
|
|
152
|
+
expect(PKG.opensipTools.config).toEqual(derived);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
describe('osv-scanner tool — acceptance harness (normalize → envelope)', () => {
|
|
156
|
+
const result = runAcceptanceCase({
|
|
157
|
+
tool: 'osv-scanner',
|
|
158
|
+
kind: 'json',
|
|
159
|
+
raw: GOLDEN_RAW,
|
|
160
|
+
parse: parseOsvJson,
|
|
161
|
+
fingerprintStrategy: 'message-hash',
|
|
162
|
+
});
|
|
163
|
+
it('produces the golden normalized signals', () => {
|
|
164
|
+
expect(result.signals.map(normalizedSignalShape)).toEqual(EXPECTED);
|
|
165
|
+
});
|
|
166
|
+
it('builds an envelope whose verdict FAILS (the high-severity vuln is error-rung)', () => {
|
|
167
|
+
expect(result.envelope.tool).toBe('osv-scanner');
|
|
168
|
+
expect(result.envelope.verdict.passed).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
it('stamps a message-hash fingerprint on every envelope signal worker-side', () => {
|
|
171
|
+
expect(result.envelope.signals).toHaveLength(2);
|
|
172
|
+
for (const s of result.envelope.signals) {
|
|
173
|
+
expect(s.fingerprint).toMatch(/^[0-9a-f]{64}$/);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
it('preserves provenance-friendly native severity + advisory metadata (no loss)', () => {
|
|
177
|
+
// A10: both golden members are 9.8/CRITICAL (lodash CVE-2019-10744 +
|
|
178
|
+
// minimist CVE-2021-44906), so the native label is CRITICAL and the CVSS is 9.8.
|
|
179
|
+
const [lodash, minimist] = result.signals;
|
|
180
|
+
expect(lodash?.metadata.nativeSeverity).toBe('CRITICAL');
|
|
181
|
+
expect(lodash?.metadata.cvss).toBe('9.8');
|
|
182
|
+
expect(minimist?.metadata.nativeSeverity).toBe('CRITICAL');
|
|
183
|
+
expect(minimist?.metadata.cvss).toBe('9.8');
|
|
184
|
+
expect(minimist?.metadata.aliases).toEqual(['CVE-2021-44906']);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
//# sourceMappingURL=tool.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.test.js","sourceRoot":"","sources":["../../src/__tests__/tool.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-2 worker E2E (ADR-0090 D6 Tier 2) — install / discover / dispatch the
|
|
3
|
+
* osv-scanner adapter over a REAL forked worker, end-to-end against the BUILT CLI.
|
|
4
|
+
*
|
|
5
|
+
* Unlike the in-process Tier-1 suites, this proves the FULL installed-tool path:
|
|
6
|
+
* - the osv-scanner package is presented as a genuinely INSTALLED npm tool in a
|
|
7
|
+
* throwaway project (symlinked into its `node_modules` so the worker resolves
|
|
8
|
+
* the adapter's workspace deps from the monorepo via realpath);
|
|
9
|
+
* - `OPENSIP_CLI_ALLOW_INSTALLED_TOOLS` trusts it (installed tools are
|
|
10
|
+
* deny-by-default);
|
|
11
|
+
* - a FAKE `osv-scanner` binary on PATH makes the run deterministic (it copies
|
|
12
|
+
* the committed golden to `--output` and exits 1, like real osv-scanner on
|
|
13
|
+
* findings). The worker fork curates its env to an allow-list, so the golden
|
|
14
|
+
* path is forwarded via the documented `OPENSIP_CLI_TOOL_ENV_PASSTHROUGH`.
|
|
15
|
+
*
|
|
16
|
+
* `opensip osv` forks a worker that re-discovers + imports the real runtime and
|
|
17
|
+
* runs the scan loop; this suite asserts the worker→host result + the host-side
|
|
18
|
+
* effects: normalized signals match the golden, the raw artifact lands at
|
|
19
|
+
* `.runtime/artifacts/osv-scanner/<runId>/osv.json` with mode 0600, the `--json`
|
|
20
|
+
* envelope is well-formed, the session row persists with provenance, native
|
|
21
|
+
* severity + provenance are preserved, and the full gate ratchet (gate-save →
|
|
22
|
+
* clean compare → net-new vuln surfaces) works.
|
|
23
|
+
*
|
|
24
|
+
* Requires `pnpm build` first (the CLI dist + the osv-scanner dist). Missing builds
|
|
25
|
+
* FAIL loudly (no silent skip).
|
|
26
|
+
*/
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=worker-e2e.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-e2e.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/worker-e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-2 worker E2E (ADR-0090 D6 Tier 2) — install / discover / dispatch the
|
|
3
|
+
* osv-scanner adapter over a REAL forked worker, end-to-end against the BUILT CLI.
|
|
4
|
+
*
|
|
5
|
+
* Unlike the in-process Tier-1 suites, this proves the FULL installed-tool path:
|
|
6
|
+
* - the osv-scanner package is presented as a genuinely INSTALLED npm tool in a
|
|
7
|
+
* throwaway project (symlinked into its `node_modules` so the worker resolves
|
|
8
|
+
* the adapter's workspace deps from the monorepo via realpath);
|
|
9
|
+
* - `OPENSIP_CLI_ALLOW_INSTALLED_TOOLS` trusts it (installed tools are
|
|
10
|
+
* deny-by-default);
|
|
11
|
+
* - a FAKE `osv-scanner` binary on PATH makes the run deterministic (it copies
|
|
12
|
+
* the committed golden to `--output` and exits 1, like real osv-scanner on
|
|
13
|
+
* findings). The worker fork curates its env to an allow-list, so the golden
|
|
14
|
+
* path is forwarded via the documented `OPENSIP_CLI_TOOL_ENV_PASSTHROUGH`.
|
|
15
|
+
*
|
|
16
|
+
* `opensip osv` forks a worker that re-discovers + imports the real runtime and
|
|
17
|
+
* runs the scan loop; this suite asserts the worker→host result + the host-side
|
|
18
|
+
* effects: normalized signals match the golden, the raw artifact lands at
|
|
19
|
+
* `.runtime/artifacts/osv-scanner/<runId>/osv.json` with mode 0600, the `--json`
|
|
20
|
+
* envelope is well-formed, the session row persists with provenance, native
|
|
21
|
+
* severity + provenance are preserved, and the full gate ratchet (gate-save →
|
|
22
|
+
* clean compare → net-new vuln surfaces) works.
|
|
23
|
+
*
|
|
24
|
+
* Requires `pnpm build` first (the CLI dist + the osv-scanner dist). Missing builds
|
|
25
|
+
* FAIL loudly (no silent skip).
|
|
26
|
+
*/
|
|
27
|
+
import { execFileSync } from 'node:child_process';
|
|
28
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, symlinkSync, writeFileSync, } from 'node:fs';
|
|
29
|
+
import { tmpdir } from 'node:os';
|
|
30
|
+
import { dirname, join } from 'node:path';
|
|
31
|
+
import { fileURLToPath } from 'node:url';
|
|
32
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
33
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
34
|
+
// .../packages/tool-osv-scanner/src/__tests__ → repo root is four levels up.
|
|
35
|
+
const REPO_ROOT = join(HERE, '..', '..', '..', '..');
|
|
36
|
+
const CLI_DIST = join(REPO_ROOT, 'packages', 'cli', 'dist', 'index.js');
|
|
37
|
+
const OSV_PKG_DIR = join(REPO_ROOT, 'packages', 'tool-osv-scanner');
|
|
38
|
+
const FIXTURES = join(OSV_PKG_DIR, '__fixtures__');
|
|
39
|
+
const GOLDEN_PATH = join(FIXTURES, 'osv-golden.json');
|
|
40
|
+
const OSV_SCANNER_STABLE_ID = 'd25a4471-3289-4660-b5ab-63830072d0e1';
|
|
41
|
+
const EXPECTED = JSON.parse(readFileSync(join(FIXTURES, 'expected-signals.json'), 'utf8'));
|
|
42
|
+
let projectDir;
|
|
43
|
+
let binDir;
|
|
44
|
+
let baseEnv;
|
|
45
|
+
/** Run the built CLI as a child process, capturing stdout/stderr + exit code. */
|
|
46
|
+
function runCli(args, extraEnv = {}, cwd = projectDir) {
|
|
47
|
+
try {
|
|
48
|
+
const stdout = execFileSync('node', [CLI_DIST, ...args], {
|
|
49
|
+
cwd,
|
|
50
|
+
env: { ...process.env, ...baseEnv, ...extraEnv },
|
|
51
|
+
encoding: 'utf8',
|
|
52
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
53
|
+
});
|
|
54
|
+
return { stdout, stderr: '', status: 0 };
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const e = error;
|
|
58
|
+
return { stdout: e.stdout ?? '', stderr: e.stderr ?? '', status: e.status ?? 1 };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Scaffold a throwaway opensip-cli project that resolves the installed osv-scanner tool. */
|
|
62
|
+
function makeOsvProject() {
|
|
63
|
+
const dir = mkdtempSync(join(tmpdir(), 'opensip-osv-gate-'));
|
|
64
|
+
writeFileSync(join(dir, 'opensip-cli.config.yml'), 'schemaVersion: 1\ntargets: {}\n', 'utf8');
|
|
65
|
+
const scopeDir = join(dir, 'node_modules', '@opensip-cli');
|
|
66
|
+
mkdirSync(scopeDir, { recursive: true });
|
|
67
|
+
symlinkSync(OSV_PKG_DIR, join(scopeDir, 'tool-osv-scanner'), 'dir');
|
|
68
|
+
return dir;
|
|
69
|
+
}
|
|
70
|
+
/** Read the `--json` outcome wrapper (`{ kind, status, exitCode, envelope?, data? }`) from a run. */
|
|
71
|
+
function outcomeJson(run) {
|
|
72
|
+
return JSON.parse(run.stdout);
|
|
73
|
+
}
|
|
74
|
+
beforeAll(() => {
|
|
75
|
+
if (!existsSync(CLI_DIST)) {
|
|
76
|
+
throw new Error(`built CLI not found at ${CLI_DIST} — run \`pnpm build\` first`);
|
|
77
|
+
}
|
|
78
|
+
if (!existsSync(join(OSV_PKG_DIR, 'dist', 'index.js'))) {
|
|
79
|
+
throw new Error('built tool-osv-scanner dist not found — run `pnpm build` first');
|
|
80
|
+
}
|
|
81
|
+
projectDir = mkdtempSync(join(tmpdir(), 'opensip-osv-e2e-'));
|
|
82
|
+
// Project marker so the worker's `scope: 'project'` bootstrap resolves a project.
|
|
83
|
+
writeFileSync(join(projectDir, 'opensip-cli.config.yml'), 'schemaVersion: 1\ntargets: {}\n', 'utf8');
|
|
84
|
+
// Present the REAL osv-scanner package as an installed npm tool. A SYMLINK (not a
|
|
85
|
+
// copy) so the worker resolves the adapter's `@opensip-cli/*` workspace deps from
|
|
86
|
+
// the monorepo via realpath — a copy would orphan them.
|
|
87
|
+
const scopeDir = join(projectDir, 'node_modules', '@opensip-cli');
|
|
88
|
+
mkdirSync(scopeDir, { recursive: true });
|
|
89
|
+
symlinkSync(OSV_PKG_DIR, join(scopeDir, 'tool-osv-scanner'), 'dir');
|
|
90
|
+
// A FAKE osv-scanner on PATH for determinism (copies the golden to --output,
|
|
91
|
+
// exits 1). PATH is auto-forwarded into the worker fork's curated env.
|
|
92
|
+
binDir = mkdtempSync(join(tmpdir(), 'opensip-osv-bin-'));
|
|
93
|
+
cpSync(join(FIXTURES, 'fake-osv-scanner'), join(binDir, 'osv-scanner'));
|
|
94
|
+
execFileSync('chmod', ['+x', join(binDir, 'osv-scanner')]);
|
|
95
|
+
baseEnv = {
|
|
96
|
+
PATH: `${binDir}:${process.env.PATH ?? ''}`,
|
|
97
|
+
// The committed fake binary reads the golden path from here; forward it through
|
|
98
|
+
// the worker fork's env allow-list via the documented passthrough.
|
|
99
|
+
FAKE_OSV_GOLDEN: GOLDEN_PATH,
|
|
100
|
+
OPENSIP_CLI_TOOL_ENV_PASSTHROUGH: 'FAKE_OSV_GOLDEN',
|
|
101
|
+
// Installed tools are deny-by-default — trust the osv-scanner id (the admission
|
|
102
|
+
// check keys on `opensipTools.id`; the UUID is included to match the ADR-0048
|
|
103
|
+
// stable id convention).
|
|
104
|
+
OPENSIP_CLI_ALLOW_INSTALLED_TOOLS: `${OSV_SCANNER_STABLE_ID} osv-scanner`,
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
afterAll(() => {
|
|
108
|
+
if (projectDir !== undefined)
|
|
109
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
110
|
+
if (binDir !== undefined)
|
|
111
|
+
rmSync(binDir, { recursive: true, force: true });
|
|
112
|
+
});
|
|
113
|
+
describe('osv-scanner worker E2E — opensip osv (real forked worker)', () => {
|
|
114
|
+
let scan;
|
|
115
|
+
let envelope;
|
|
116
|
+
beforeAll(() => {
|
|
117
|
+
// Invoke via the `osv` ALIAS to prove the aliased primary mounts + dispatches.
|
|
118
|
+
scan = runCli(['osv', '--json']);
|
|
119
|
+
const outcome = outcomeJson(scan);
|
|
120
|
+
envelope = outcome.envelope;
|
|
121
|
+
});
|
|
122
|
+
it('forks a worker and emits a well-formed signal envelope for osv-scanner', () => {
|
|
123
|
+
expect(envelope.tool).toBe('osv-scanner');
|
|
124
|
+
expect(envelope.runId).toMatch(/^RUN_/);
|
|
125
|
+
// A high-severity vuln ⇒ the run FAILS; the gate exit is non-zero (findings).
|
|
126
|
+
expect(envelope.verdict.passed).toBe(false);
|
|
127
|
+
expect(scan.status).toBe(1);
|
|
128
|
+
});
|
|
129
|
+
it('normalizes the worker scan output to the golden signal shapes', () => {
|
|
130
|
+
const shapes = envelope.signals.map((s) => ({
|
|
131
|
+
ruleId: s.ruleId,
|
|
132
|
+
severity: s.severity,
|
|
133
|
+
message: s.message,
|
|
134
|
+
file: s.filePath,
|
|
135
|
+
}));
|
|
136
|
+
expect(shapes).toEqual(EXPECTED);
|
|
137
|
+
});
|
|
138
|
+
it('stamps message-hash fingerprints + provenance + native severity worker-side', () => {
|
|
139
|
+
for (const s of envelope.signals) {
|
|
140
|
+
expect(s.fingerprint).toMatch(/^[0-9a-f]{64}$/);
|
|
141
|
+
const provenance = s.metadata.provenance;
|
|
142
|
+
expect(provenance.tool).toBe('osv-scanner');
|
|
143
|
+
expect(provenance.adapterPackage).toBe('@opensip-cli/tool-osv-scanner');
|
|
144
|
+
}
|
|
145
|
+
// Native scanner severity preserved beside the mapped four-bucket severity.
|
|
146
|
+
// A10: both golden members are 9.8/CRITICAL (lodash + minimist).
|
|
147
|
+
const [lodash, minimist] = envelope.signals;
|
|
148
|
+
expect(lodash?.metadata.nativeSeverity).toBe('CRITICAL');
|
|
149
|
+
expect(lodash?.metadata.cvss).toBe('9.8');
|
|
150
|
+
expect(minimist?.metadata.nativeSeverity).toBe('CRITICAL');
|
|
151
|
+
expect(minimist?.metadata.cvss).toBe('9.8');
|
|
152
|
+
});
|
|
153
|
+
it('lands the raw artifact under .runtime/artifacts/osv-scanner/<runId>/osv.json with mode 0600', () => {
|
|
154
|
+
const runDir = join(projectDir, 'opensip-cli', '.runtime', 'artifacts', 'osv-scanner');
|
|
155
|
+
expect(existsSync(runDir)).toBe(true);
|
|
156
|
+
const runs = readdirSync(runDir);
|
|
157
|
+
expect(runs.length).toBeGreaterThan(0);
|
|
158
|
+
const artifact = join(runDir, runs[0], 'osv.json');
|
|
159
|
+
expect(existsSync(artifact)).toBe(true);
|
|
160
|
+
// Owner-only read/write (0600) — the artifact carries the raw scanner output.
|
|
161
|
+
expect(statSync(artifact).mode & 0o777).toBe(0o600);
|
|
162
|
+
// The persisted artifact is the byte-preserved golden (two vulnerabilities).
|
|
163
|
+
const doc = JSON.parse(readFileSync(artifact, 'utf8'));
|
|
164
|
+
expect(doc.results[0].packages).toHaveLength(2);
|
|
165
|
+
});
|
|
166
|
+
it('persists a session row with the osv-scanner tool + provenance payload', () => {
|
|
167
|
+
const list = runCli(['sessions', 'list', '--json']);
|
|
168
|
+
expect(list.status).toBe(0);
|
|
169
|
+
const outcome = outcomeJson(list);
|
|
170
|
+
const data = outcome.data;
|
|
171
|
+
const sessions = data?.sessions ?? [];
|
|
172
|
+
const osvRow = sessions.find((s) => s.tool === 'osv-scanner');
|
|
173
|
+
expect(osvRow).toBeDefined();
|
|
174
|
+
expect(osvRow?.passed).toBe(false);
|
|
175
|
+
const payload = osvRow?.payload;
|
|
176
|
+
expect(payload?.binary?.path).toContain('osv-scanner');
|
|
177
|
+
expect(payload?.findings).toBe(2);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
describe('osv-scanner worker E2E — doctor / version diagnostics', () => {
|
|
181
|
+
it('doctor --json reports a ready, resolved binary (exit 0)', () => {
|
|
182
|
+
const run = runCli(['osv-scanner', 'doctor', '--json']);
|
|
183
|
+
expect(run.status).toBe(0);
|
|
184
|
+
const report = outcomeJson(run).data;
|
|
185
|
+
expect(report.tool).toBe('osv-scanner');
|
|
186
|
+
expect(report.ready).toBe(true);
|
|
187
|
+
expect(report.binary.found).toBe(true);
|
|
188
|
+
expect(report.version.detected).toBe('1.9.1');
|
|
189
|
+
expect(report.version.status).toBe('ok');
|
|
190
|
+
});
|
|
191
|
+
it('doctor reports NOT ready (exit 2) when the resolved binary is missing', () => {
|
|
192
|
+
// Pin the binary to a non-existent absolute path via the env layer (which beats
|
|
193
|
+
// PATH and hard-misses) so resolution fails WITHOUT breaking the toolchain/worker
|
|
194
|
+
// fork. Forward the pin into the worker (doctor probes worker-side) via the
|
|
195
|
+
// documented passthrough.
|
|
196
|
+
const run = runCli(['osv-scanner', 'doctor', '--json'], {
|
|
197
|
+
OPENSIP_OSV_SCANNER_BIN: '/nonexistent/path/to/osv-scanner',
|
|
198
|
+
OPENSIP_CLI_TOOL_ENV_PASSTHROUGH: 'FAKE_OSV_GOLDEN OPENSIP_OSV_SCANNER_BIN',
|
|
199
|
+
});
|
|
200
|
+
expect(run.status).toBe(2);
|
|
201
|
+
const report = outcomeJson(run).data;
|
|
202
|
+
expect(report.ready).toBe(false);
|
|
203
|
+
expect(report.binary.found).toBe(false);
|
|
204
|
+
});
|
|
205
|
+
it('version --json prints the resolved osv-scanner binary version', () => {
|
|
206
|
+
const run = runCli(['osv-scanner', 'version', '--json']);
|
|
207
|
+
expect(run.status).toBe(0);
|
|
208
|
+
const report = outcomeJson(run).data;
|
|
209
|
+
expect(report.found).toBe(true);
|
|
210
|
+
expect(report.version).toBe('1.9.1');
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
describe('osv-scanner worker E2E — installed tools are deny-by-default', () => {
|
|
214
|
+
it('without the trust allowlist, `opensip osv` is not admitted', () => {
|
|
215
|
+
const run = runCli(['osv', '--json'], { OPENSIP_CLI_ALLOW_INSTALLED_TOOLS: '' });
|
|
216
|
+
// Deny-by-default: the command never mounts (unknown command / not found), so
|
|
217
|
+
// the scan does NOT run.
|
|
218
|
+
expect(run.status).not.toBe(0);
|
|
219
|
+
expect(`${run.stdout}${run.stderr}`.toLowerCase()).toMatch(/unknown command|not found|osv/);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
/**
|
|
223
|
+
* §4.12 ratchet acceptance — the FULL baseline/gate loop over a REAL forked worker.
|
|
224
|
+
* The substrate wires `--gate-save` / `--gate-compare` once (ADR-0036), so the
|
|
225
|
+
* osv-scanner adapter inherits it. This proves: capture a baseline → an unchanged
|
|
226
|
+
* re-scan is clean (exit 0) → a NET-NEW vulnerability surfaces and fails (exit ≠ 0).
|
|
227
|
+
*
|
|
228
|
+
* Runs in its OWN throwaway project so the baseline + sessions are isolated from the
|
|
229
|
+
* scan suites above. The fake binary copies `FAKE_OSV_GOLDEN` to `--output`;
|
|
230
|
+
* pointing it at an AUGMENTED golden (the two originals + one new vuln in a new
|
|
231
|
+
* package) is how the "regression" run injects a net-new finding.
|
|
232
|
+
*/
|
|
233
|
+
describe('osv-scanner worker E2E — full gate ratchet (§4.12)', () => {
|
|
234
|
+
let gateProject;
|
|
235
|
+
let augmentedGolden;
|
|
236
|
+
let save;
|
|
237
|
+
let compareClean;
|
|
238
|
+
let compareRegressed;
|
|
239
|
+
beforeAll(() => {
|
|
240
|
+
gateProject = makeOsvProject();
|
|
241
|
+
// The augmented golden = the committed two findings + one NET-NEW vuln in a new
|
|
242
|
+
// package (a distinct ruleId/message ⇒ a distinct message-hash fingerprint ⇒ the
|
|
243
|
+
// ratchet sees it as net-new, not unchanged).
|
|
244
|
+
const original = JSON.parse(readFileSync(GOLDEN_PATH, 'utf8'));
|
|
245
|
+
original.results[0].packages.push({
|
|
246
|
+
package: { name: 'axios', version: '0.21.0', ecosystem: 'npm' },
|
|
247
|
+
vulnerabilities: [
|
|
248
|
+
{
|
|
249
|
+
id: 'GHSA-NEWVULN-FAKE-0001',
|
|
250
|
+
summary: 'Server-Side Request Forgery in axios',
|
|
251
|
+
aliases: ['CVE-2024-99999'],
|
|
252
|
+
database_specific: { severity: 'HIGH' },
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
groups: [{ ids: ['GHSA-NEWVULN-FAKE-0001'], max_severity: '8.6' }],
|
|
256
|
+
});
|
|
257
|
+
augmentedGolden = join(gateProject, 'augmented-golden.json');
|
|
258
|
+
writeFileSync(augmentedGolden, JSON.stringify(original), 'utf8');
|
|
259
|
+
// 1) Capture the baseline (two findings). The findings gate (ADR-0020) makes
|
|
260
|
+
// gate-save itself exit 1 — it records the baseline AND honours the verdict.
|
|
261
|
+
save = runCli(['osv', '--gate-save'], {}, gateProject);
|
|
262
|
+
// 2) Re-scan the SAME golden and compare → no net-new ⇒ clean (exit 0).
|
|
263
|
+
compareClean = runCli(['osv', '--gate-compare'], {}, gateProject);
|
|
264
|
+
// 3) Compare against the augmented golden → one net-new finding ⇒ degraded.
|
|
265
|
+
compareRegressed = runCli(['osv', '--gate-compare'], { FAKE_OSV_GOLDEN: augmentedGolden }, gateProject);
|
|
266
|
+
});
|
|
267
|
+
afterAll(() => {
|
|
268
|
+
if (gateProject !== undefined)
|
|
269
|
+
rmSync(gateProject, { recursive: true, force: true });
|
|
270
|
+
});
|
|
271
|
+
it('--gate-save records the baseline and persists a session', () => {
|
|
272
|
+
// The findings gate makes gate-save exit 1 (a high-severity vuln present), but
|
|
273
|
+
// the baseline IS written — proven by the clean compare below.
|
|
274
|
+
expect(save.status).toBe(1);
|
|
275
|
+
const list = runCli(['sessions', 'list', '--json'], {}, gateProject);
|
|
276
|
+
const data = outcomeJson(list).data;
|
|
277
|
+
const osvRows = (data.sessions ?? []).filter((s) => s.tool === 'osv-scanner');
|
|
278
|
+
expect(osvRows.length).toBeGreaterThanOrEqual(1);
|
|
279
|
+
});
|
|
280
|
+
it('--gate-compare on the SAME scan is a clean no-op (exit 0, no regression)', () => {
|
|
281
|
+
// Pre-existing findings recorded in the baseline are NOT a regression — only
|
|
282
|
+
// net-new findings fail the ratchet. The clean exit also proves gate-save wrote
|
|
283
|
+
// the baseline (the missing-baseline → exit 2 contract is asserted directly in
|
|
284
|
+
// the "typed exit-class survives the worker boundary" suite below).
|
|
285
|
+
expect(compareRegressed).toBeDefined();
|
|
286
|
+
expect(compareClean.status).toBe(0);
|
|
287
|
+
expect(`${compareClean.stdout}${compareClean.stderr}`).toMatch(/STABLE|no change/i);
|
|
288
|
+
});
|
|
289
|
+
it('--gate-compare surfaces a NET-NEW vulnerability and exits non-zero (degraded)', () => {
|
|
290
|
+
expect(compareRegressed.status).not.toBe(0);
|
|
291
|
+
const out = `${compareRegressed.stdout}${compareRegressed.stderr}`;
|
|
292
|
+
// The net-new advisory is named in the diff; the verdict footer says DEGRADED.
|
|
293
|
+
expect(out).toContain('GHSA-NEWVULN-FAKE-0001');
|
|
294
|
+
expect(out).toMatch(/DEGRADED|Added/i);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
/**
|
|
298
|
+
* A5/A6 — the typed exit-class must survive the worker boundary on the host-RPC
|
|
299
|
+
* REJECT path too. `--gate-compare` with NO saved baseline makes the host
|
|
300
|
+
* `compareBaseline` seam reject with a ConfigurationError (BASELINE_MISSING). That
|
|
301
|
+
* rejection crosses the worker IPC as a structured reply; before the fix the worker
|
|
302
|
+
* shim rebuilt a PLAIN Error → SystemError → exit 1, silently losing the frozen
|
|
303
|
+
* exit-2 config contract. This asserts the contract end-to-end over a REAL fork.
|
|
304
|
+
*/
|
|
305
|
+
describe('osv-scanner worker E2E — gate-compare with no baseline exits 2 (A5/A6)', () => {
|
|
306
|
+
it('`opensip osv --gate-compare` before any --gate-save exits 2 (not 1)', () => {
|
|
307
|
+
// A fresh project with NO baseline captured: the compareBaseline host seam
|
|
308
|
+
// rejects ConfigurationError(BASELINE_MISSING) over the host-RPC channel.
|
|
309
|
+
const freshProject = makeOsvProject();
|
|
310
|
+
try {
|
|
311
|
+
const run = runCli(['osv', '--gate-compare'], {}, freshProject);
|
|
312
|
+
expect(run.status).toBe(2);
|
|
313
|
+
expect(`${run.stdout}${run.stderr}`).toMatch(/baseline|gate-save/i);
|
|
314
|
+
}
|
|
315
|
+
finally {
|
|
316
|
+
rmSync(freshProject, { recursive: true, force: true });
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
//# sourceMappingURL=worker-e2e.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-e2e.test.js","sourceRoot":"","sources":["../../src/__tests__/worker-e2e.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@opensip-cli/tool-osv-scanner` public barrel.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the `tool` descriptor the host loads by name through the installed
|
|
5
|
+
* external-tool worker-dispatch path (`mod.tool`), plus a `default` alias and the
|
|
6
|
+
* pure `parseOsvJson` normalizer (consumed by the acceptance tests). The adapter
|
|
7
|
+
* internals are otherwise not public API.
|
|
8
|
+
*/
|
|
9
|
+
export { tool, tool as default, OSV_SCANNER_IDENTITY, OSV_SCANNER_STABLE_ID } from './tool.js';
|
|
10
|
+
export { parseOsvJson } from './parse-osv-json.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@opensip-cli/tool-osv-scanner` public barrel.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the `tool` descriptor the host loads by name through the installed
|
|
5
|
+
* external-tool worker-dispatch path (`mod.tool`), plus a `default` alias and the
|
|
6
|
+
* pure `parseOsvJson` normalizer (consumed by the acceptance tests). The adapter
|
|
7
|
+
* internals are otherwise not public API.
|
|
8
|
+
*/
|
|
9
|
+
export { tool, tool as default, OSV_SCANNER_IDENTITY, OSV_SCANNER_STABLE_ID } from './tool.js';
|
|
10
|
+
export { parseOsvJson } from './parse-osv-json.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
|