@opensip-cli/tool-gitleaks 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-gitleaks-json.test.d.ts +7 -0
- package/dist/__tests__/parse-gitleaks-json.test.d.ts.map +1 -0
- package/dist/__tests__/parse-gitleaks-json.test.js +100 -0
- package/dist/__tests__/parse-gitleaks-json.test.js.map +1 -0
- package/dist/__tests__/suite-step-e2e.test.d.ts +48 -0
- package/dist/__tests__/suite-step-e2e.test.d.ts.map +1 -0
- package/dist/__tests__/suite-step-e2e.test.js +262 -0
- package/dist/__tests__/suite-step-e2e.test.js.map +1 -0
- package/dist/__tests__/tool.test.d.ts +11 -0
- package/dist/__tests__/tool.test.d.ts.map +1 -0
- package/dist/__tests__/tool.test.js +197 -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 +425 -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-gitleaks-json.d.ts +26 -0
- package/dist/parse-gitleaks-json.d.ts.map +1 -0
- package/dist/parse-gitleaks-json.js +88 -0
- package/dist/parse-gitleaks-json.js.map +1 -0
- package/dist/tool.d.ts +74 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +140 -0
- package/dist/tool.js.map +1 -0
- package/package.json +142 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 04↔05 integration E2E — an EXTERNAL tool adapter (plan 04) runs as a host-owned
|
|
3
|
+
* SUITE step (plan 05 / ADR-0093) over the REAL forked-worker boundary, end-to-end
|
|
4
|
+
* against the BUILT CLI.
|
|
5
|
+
*
|
|
6
|
+
* This locks in the seam between the two planes that otherwise only meet at run
|
|
7
|
+
* time: the gitleaks adapter is an installed, EXTERNAL-provenance tool, so when it
|
|
8
|
+
* appears as a `suites:` step the orchestrator's `maybeDispatchExternal` hook MUST
|
|
9
|
+
* fork the ADR-0054 worker (it never runs the untrusted runtime in-host), and the
|
|
10
|
+
* worker's verdict MUST flow back into the suite's worst-of exit aggregation.
|
|
11
|
+
*
|
|
12
|
+
* The harness mirrors `worker-e2e.test.ts` (least-effort path): the REAL gitleaks
|
|
13
|
+
* package is presented as an installed npm tool (symlinked into the throwaway
|
|
14
|
+
* project's `node_modules` so the worker resolves its `@opensip-cli/*` workspace
|
|
15
|
+
* deps via realpath), a FAKE `gitleaks` on PATH makes the scan deterministic (copy
|
|
16
|
+
* the committed golden to `--report-path`, exit 1 like real gitleaks on findings),
|
|
17
|
+
* and `OPENSIP_CLI_ALLOW_INSTALLED_TOOLS` trusts it (installed tools are
|
|
18
|
+
* deny-by-default). The fake's golden path rides the documented
|
|
19
|
+
* `OPENSIP_CLI_TOOL_ENV_PASSTHROUGH` into the worker fork's curated env.
|
|
20
|
+
*
|
|
21
|
+
* What it proves:
|
|
22
|
+
* - `suite add security --tool gitleaks --command gitleaks` resolves the tool
|
|
23
|
+
* NAME to its canonical `ToolMetadata.id` UUID in `opensip-cli.config.yml`.
|
|
24
|
+
* - `suite run security` dispatches the step through the forked worker: the raw
|
|
25
|
+
* artifact lands at `.runtime/artifacts/gitleaks/<runId>/gitleaks.json`
|
|
26
|
+
* (mode 0600 in a 0700 dir) — the worker boundary actually ran the scan.
|
|
27
|
+
* - the gitleaks findings verdict propagates into the suite worst-of exit
|
|
28
|
+
* (the 2 fixture secrets trip the findings gate ⇒ the suite exits non-zero,
|
|
29
|
+
* the step summary records exit 1).
|
|
30
|
+
* - the run persists under the suite grouping (`suiteRunId` / `suiteName`) with
|
|
31
|
+
* the gitleaks verdict + finding count.
|
|
32
|
+
* - the secret-egress guarantee STILL holds inside a suite (no raw `Secret`/
|
|
33
|
+
* `Match` reaches the emitted output; only the masked preview survives).
|
|
34
|
+
* - deny-by-default STILL applies in suite context: WITHOUT the trust env the
|
|
35
|
+
* step is denied (non-zero exit, no artifact, no session) — it never silently
|
|
36
|
+
* succeeds.
|
|
37
|
+
*
|
|
38
|
+
* Requires `pnpm build` first (the CLI dist + the gitleaks dist). Missing builds
|
|
39
|
+
* FAIL loudly (no silent skip).
|
|
40
|
+
*
|
|
41
|
+
* NOTE on the step command name: the adapter declares its scan command as `scan`,
|
|
42
|
+
* but `defineExternalToolAdapter` makes the first command the PRIMARY, which
|
|
43
|
+
* `defineTool` names from `identity.name` — so the resolvable `commandSpecs` name
|
|
44
|
+
* (and the suite step `command`) is `gitleaks`, not `scan`. `suite add --command
|
|
45
|
+
* scan` is rejected (`CONFIG.SUITE_ADD.UNKNOWN_COMMAND`, exit 2).
|
|
46
|
+
*/
|
|
47
|
+
import { execFileSync } from 'node:child_process';
|
|
48
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, symlinkSync, writeFileSync, } from 'node:fs';
|
|
49
|
+
import { tmpdir } from 'node:os';
|
|
50
|
+
import { dirname, join } from 'node:path';
|
|
51
|
+
import { fileURLToPath } from 'node:url';
|
|
52
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
53
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
54
|
+
// .../packages/tool-gitleaks/src/__tests__ → repo root is four levels up.
|
|
55
|
+
const REPO_ROOT = join(HERE, '..', '..', '..', '..');
|
|
56
|
+
const CLI_DIST = join(REPO_ROOT, 'packages', 'cli', 'dist', 'index.js');
|
|
57
|
+
const GITLEAKS_PKG_DIR = join(REPO_ROOT, 'packages', 'tool-gitleaks');
|
|
58
|
+
const FIXTURES = join(GITLEAKS_PKG_DIR, '__fixtures__');
|
|
59
|
+
const GOLDEN_PATH = join(FIXTURES, 'gitleaks-golden.json');
|
|
60
|
+
// The gitleaks adapter's stable `ToolMetadata.id` (ADR-0048). Suite steps address
|
|
61
|
+
// tools by this UUID; `suite add --tool gitleaks` must resolve the name to it.
|
|
62
|
+
const GITLEAKS_STABLE_ID = 'cd08f737-ce8e-4813-9259-b4ffeb954268';
|
|
63
|
+
// Raw matched-credential strings that must NEVER reach the emitted payload.
|
|
64
|
+
const RAW_SECRETS = ['AKIAIOSFODNN7EXAMPLE', 'glpat-XXXXXXXXXXXXXXXXXXXX', 'aws_key ='];
|
|
65
|
+
let binDir;
|
|
66
|
+
let baseEnv;
|
|
67
|
+
/** Run the built CLI as a child process, capturing stdout/stderr + exit code. */
|
|
68
|
+
function runCli(args, extraEnv, cwd) {
|
|
69
|
+
try {
|
|
70
|
+
const stdout = execFileSync('node', [CLI_DIST, ...args], {
|
|
71
|
+
cwd,
|
|
72
|
+
env: { ...process.env, ...baseEnv, ...extraEnv },
|
|
73
|
+
encoding: 'utf8',
|
|
74
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
75
|
+
});
|
|
76
|
+
return { stdout, stderr: '', status: 0 };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const e = error;
|
|
80
|
+
return { stdout: e.stdout ?? '', stderr: e.stderr ?? '', status: e.status ?? 1 };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** Scaffold a throwaway opensip-cli project that resolves the installed gitleaks tool. */
|
|
84
|
+
function makeSuiteProject() {
|
|
85
|
+
const dir = mkdtempSync(join(tmpdir(), 'opensip-gitleaks-suite-'));
|
|
86
|
+
writeFileSync(join(dir, 'opensip-cli.config.yml'), 'schemaVersion: 1\ntargets: {}\n', 'utf8');
|
|
87
|
+
// SYMLINK (not a copy) so the worker resolves the adapter's `@opensip-cli/*`
|
|
88
|
+
// workspace deps from the monorepo via realpath — a copy would orphan them.
|
|
89
|
+
const scopeDir = join(dir, 'node_modules', '@opensip-cli');
|
|
90
|
+
mkdirSync(scopeDir, { recursive: true });
|
|
91
|
+
symlinkSync(GITLEAKS_PKG_DIR, join(scopeDir, 'tool-gitleaks'), 'dir');
|
|
92
|
+
return dir;
|
|
93
|
+
}
|
|
94
|
+
/** Split the CLI's concatenated top-level `--json` outcome documents. */
|
|
95
|
+
function parseOutcomes(stdout) {
|
|
96
|
+
// The CLI pretty-prints each top-level outcome object starting at column 0; a
|
|
97
|
+
// `suite run --json` emits the step's gitleaks envelope outcome AND the suite-run
|
|
98
|
+
// outcome back-to-back. Split before each line-leading `{`, then JSON.parse each.
|
|
99
|
+
return stdout
|
|
100
|
+
.split(/\n(?=\{)/)
|
|
101
|
+
.map((chunk) => chunk.trim())
|
|
102
|
+
.filter((chunk) => chunk.startsWith('{'))
|
|
103
|
+
.map((chunk) => JSON.parse(chunk));
|
|
104
|
+
}
|
|
105
|
+
beforeAll(() => {
|
|
106
|
+
if (!existsSync(CLI_DIST)) {
|
|
107
|
+
throw new Error(`built CLI not found at ${CLI_DIST} — run \`pnpm build\` first`);
|
|
108
|
+
}
|
|
109
|
+
if (!existsSync(join(GITLEAKS_PKG_DIR, 'dist', 'index.js'))) {
|
|
110
|
+
throw new Error('built tool-gitleaks dist not found — run `pnpm build` first');
|
|
111
|
+
}
|
|
112
|
+
// A FAKE gitleaks on PATH for determinism (copies the golden to --report-path,
|
|
113
|
+
// exits 1). PATH is auto-forwarded into the worker fork's curated env.
|
|
114
|
+
binDir = mkdtempSync(join(tmpdir(), 'opensip-gitleaks-suite-bin-'));
|
|
115
|
+
cpSync(join(FIXTURES, 'fake-gitleaks'), join(binDir, 'gitleaks'));
|
|
116
|
+
execFileSync('chmod', ['+x', join(binDir, 'gitleaks')]);
|
|
117
|
+
baseEnv = {
|
|
118
|
+
PATH: `${binDir}:${process.env.PATH ?? ''}`,
|
|
119
|
+
FAKE_GITLEAKS_GOLDEN: GOLDEN_PATH,
|
|
120
|
+
OPENSIP_CLI_TOOL_ENV_PASSTHROUGH: 'FAKE_GITLEAKS_GOLDEN',
|
|
121
|
+
// Installed tools are deny-by-default — trust the gitleaks id (admission keys
|
|
122
|
+
// on `opensipTools.id`; the UUID is included per the ADR-0048 stable-id rule).
|
|
123
|
+
OPENSIP_CLI_ALLOW_INSTALLED_TOOLS: `${GITLEAKS_STABLE_ID} gitleaks`,
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
afterAll(() => {
|
|
127
|
+
if (binDir !== undefined)
|
|
128
|
+
rmSync(binDir, { recursive: true, force: true });
|
|
129
|
+
});
|
|
130
|
+
describe('gitleaks as a suite step (04↔05) — external adapter over the worker boundary', () => {
|
|
131
|
+
let project;
|
|
132
|
+
let configText;
|
|
133
|
+
let addRun;
|
|
134
|
+
let suiteRun;
|
|
135
|
+
let suiteOutcome;
|
|
136
|
+
beforeAll(() => {
|
|
137
|
+
project = makeSuiteProject();
|
|
138
|
+
// 1) Author the suite via `suite add` — proving it resolves the tool NAME to
|
|
139
|
+
// the canonical UUID (needs the trust env to admit the installed tool into
|
|
140
|
+
// the registry it resolves against). `--command gitleaks` is the primary
|
|
141
|
+
// command's resolvable name (see the file header NOTE).
|
|
142
|
+
addRun = runCli(['suite', 'add', 'security', '--tool', 'gitleaks', '--command', 'gitleaks'], {}, project);
|
|
143
|
+
configText = readFileSync(join(project, 'opensip-cli.config.yml'), 'utf8');
|
|
144
|
+
// 2) Run the suite over the real forked worker (single `--json` run drives all
|
|
145
|
+
// the structured assertions + the on-disk side effects).
|
|
146
|
+
suiteRun = runCli(['suite', 'run', 'security', '--json'], {}, project);
|
|
147
|
+
const outcomes = parseOutcomes(suiteRun.stdout);
|
|
148
|
+
const found = outcomes.find((o) => o.kind === 'suite-run');
|
|
149
|
+
if (found === undefined) {
|
|
150
|
+
throw new Error(`no suite-run outcome in stdout:\n${suiteRun.stdout}`);
|
|
151
|
+
}
|
|
152
|
+
suiteOutcome = found.data;
|
|
153
|
+
});
|
|
154
|
+
afterAll(() => {
|
|
155
|
+
if (project !== undefined)
|
|
156
|
+
rmSync(project, { recursive: true, force: true });
|
|
157
|
+
});
|
|
158
|
+
it('`suite add` resolves the tool name to its canonical UUID in config', () => {
|
|
159
|
+
expect(addRun.status).toBe(0);
|
|
160
|
+
expect(configText).toContain(`tool: ${GITLEAKS_STABLE_ID}`);
|
|
161
|
+
expect(configText).toContain('command: gitleaks');
|
|
162
|
+
});
|
|
163
|
+
it('dispatches the step through the forked worker — raw artifact lands 0600 in a 0700 dir', () => {
|
|
164
|
+
const runDir = join(project, 'opensip-cli', '.runtime', 'artifacts', 'gitleaks');
|
|
165
|
+
expect(existsSync(runDir)).toBe(true);
|
|
166
|
+
const runs = readdirSync(runDir).filter((name) => name.startsWith('RUN_'));
|
|
167
|
+
expect(runs.length).toBeGreaterThan(0);
|
|
168
|
+
const perRunDir = join(runDir, runs[0]);
|
|
169
|
+
const artifact = join(perRunDir, 'gitleaks.json');
|
|
170
|
+
// The fake binary does NOT `mkdir -p` its --report-path dir — the artifact
|
|
171
|
+
// exists ONLY because the host `ensureArtifactDir` seam created the per-run dir
|
|
172
|
+
// (over the worker boundary) before the scan. Its presence proves the worker
|
|
173
|
+
// actually ran the gitleaks scan inside the suite step.
|
|
174
|
+
expect(existsSync(artifact)).toBe(true);
|
|
175
|
+
expect(statSync(perRunDir).mode & 0o777).toBe(0o700);
|
|
176
|
+
expect(statSync(artifact).mode & 0o777).toBe(0o600);
|
|
177
|
+
// The persisted artifact is the byte-preserved golden (two findings).
|
|
178
|
+
expect(JSON.parse(readFileSync(artifact, 'utf8'))).toHaveLength(2);
|
|
179
|
+
});
|
|
180
|
+
it('propagates the gitleaks findings verdict into the suite worst-of exit', () => {
|
|
181
|
+
// The 2 fixture secrets trip the findings gate ⇒ the worker verdict FAILS, and
|
|
182
|
+
// that must aggregate worst-of into the suite exit (process + structured both 1).
|
|
183
|
+
expect(suiteRun.status).toBe(1);
|
|
184
|
+
expect(suiteOutcome.exitCode).toBe(1);
|
|
185
|
+
expect(suiteOutcome.suiteRunId).toMatch(/^SUITE_/);
|
|
186
|
+
expect(suiteOutcome.steps).toHaveLength(1);
|
|
187
|
+
const [step] = suiteOutcome.steps;
|
|
188
|
+
expect(step?.tool).toBe('gitleaks');
|
|
189
|
+
expect(step?.stableId).toBe(GITLEAKS_STABLE_ID);
|
|
190
|
+
expect(step?.command).toBe('gitleaks');
|
|
191
|
+
expect(step?.exitCode).toBe(1);
|
|
192
|
+
});
|
|
193
|
+
it('persists the run under the suite grouping with the gitleaks verdict', () => {
|
|
194
|
+
const list = runCli(['sessions', 'list', '--json'], {}, project);
|
|
195
|
+
expect(list.status).toBe(0);
|
|
196
|
+
const data = parseOutcomes(list.stdout).find((o) => o.kind === 'history')?.data;
|
|
197
|
+
const gitleaksRow = (data?.sessions ?? []).find((s) => s.tool === 'gitleaks');
|
|
198
|
+
expect(gitleaksRow).toBeDefined();
|
|
199
|
+
expect(gitleaksRow?.suiteName).toBe('security');
|
|
200
|
+
expect(gitleaksRow?.suiteRunId ?? '').toMatch(/^SUITE_/);
|
|
201
|
+
// The grouped suiteRunId matches the suite-run outcome's id (same run).
|
|
202
|
+
expect(gitleaksRow?.suiteRunId).toBe(suiteOutcome.suiteRunId);
|
|
203
|
+
expect(gitleaksRow?.passed).toBe(false);
|
|
204
|
+
expect(gitleaksRow?.payload?.findings).toBe(2);
|
|
205
|
+
});
|
|
206
|
+
it('upholds the secret-egress guarantee inside the suite (masked preview only)', () => {
|
|
207
|
+
for (const raw of RAW_SECRETS) {
|
|
208
|
+
expect(suiteRun.stdout).not.toContain(raw);
|
|
209
|
+
}
|
|
210
|
+
expect(suiteRun.stdout).not.toContain('"Match"');
|
|
211
|
+
expect(suiteRun.stdout).not.toContain('"Secret"');
|
|
212
|
+
// The masked preview IS present (the finding stays identifiable in the suite).
|
|
213
|
+
expect(suiteRun.stdout).toContain('AKIA…');
|
|
214
|
+
expect(suiteRun.stdout).toContain('glpa…');
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
describe('gitleaks as a suite step — deny-by-default still applies in suite context', () => {
|
|
218
|
+
let project;
|
|
219
|
+
let denied;
|
|
220
|
+
beforeAll(() => {
|
|
221
|
+
project = makeSuiteProject();
|
|
222
|
+
// Author the suite config DIRECTLY (the installed gitleaks IS present in
|
|
223
|
+
// node_modules, so the deny is purely the trust gate, not absence of the tool).
|
|
224
|
+
writeFileSync(join(project, 'opensip-cli.config.yml'), [
|
|
225
|
+
'schemaVersion: 1',
|
|
226
|
+
'targets: {}',
|
|
227
|
+
'suites:',
|
|
228
|
+
' security:',
|
|
229
|
+
' steps:',
|
|
230
|
+
` - tool: ${GITLEAKS_STABLE_ID}`,
|
|
231
|
+
' name: gitleaks',
|
|
232
|
+
' command: gitleaks',
|
|
233
|
+
'',
|
|
234
|
+
].join('\n'), 'utf8');
|
|
235
|
+
// Run WITHOUT the trust allowlist (override baseEnv's trust to empty).
|
|
236
|
+
denied = runCli(['suite', 'run', 'security'], { OPENSIP_CLI_ALLOW_INSTALLED_TOOLS: '' }, project);
|
|
237
|
+
});
|
|
238
|
+
afterAll(() => {
|
|
239
|
+
if (project !== undefined)
|
|
240
|
+
rmSync(project, { recursive: true, force: true });
|
|
241
|
+
});
|
|
242
|
+
it('denies the untrusted external step (non-zero exit — never a silent success)', () => {
|
|
243
|
+
// The installed gitleaks is not admitted, so the suite's UUID-addressed step
|
|
244
|
+
// resolves to no tool and the run fails (configuration error) rather than
|
|
245
|
+
// silently passing.
|
|
246
|
+
expect(denied.status).not.toBe(0);
|
|
247
|
+
});
|
|
248
|
+
it('runs no scan: no artifact and no gitleaks session were produced', () => {
|
|
249
|
+
const runDir = join(project, 'opensip-cli', '.runtime', 'artifacts', 'gitleaks');
|
|
250
|
+
const artifactCount = existsSync(runDir)
|
|
251
|
+
? readdirSync(runDir)
|
|
252
|
+
.filter((name) => name.startsWith('RUN_'))
|
|
253
|
+
.filter((name) => existsSync(join(runDir, name, 'gitleaks.json'))).length
|
|
254
|
+
: 0;
|
|
255
|
+
expect(artifactCount).toBe(0);
|
|
256
|
+
const list = runCli(['sessions', 'list', '--json'], { OPENSIP_CLI_ALLOW_INSTALLED_TOOLS: '' }, project);
|
|
257
|
+
const data = parseOutcomes(list.stdout).find((o) => o.kind === 'history')?.data;
|
|
258
|
+
const gitleaksRows = (data?.sessions ?? []).filter((s) => s.tool === 'gitleaks');
|
|
259
|
+
expect(gitleaksRows).toHaveLength(0);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
//# sourceMappingURL=suite-step-e2e.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suite-step-e2e.test.js","sourceRoot":"","sources":["../../src/__tests__/suite-step-e2e.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-1 (in-process) tests for the gitleaks adapter `Tool` (ADR-0090 D6 Tier 1).
|
|
3
|
+
*
|
|
4
|
+
* Asserts the declarative surface (commandSpecs / identity / metadata), the binary
|
|
5
|
+
* helpers (version parse + scan args), the FROZEN exit model (Phase-0 decision 4),
|
|
6
|
+
* the manifest↔runtime host-shape guards (`assertManifestMatchesTool` +
|
|
7
|
+
* `deriveAdapterManifestCommands` parity), and the full normalize→envelope path
|
|
8
|
+
* via the acceptance harness — including a redaction check across the envelope.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=tool.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tool.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-1 (in-process) tests for the gitleaks adapter `Tool` (ADR-0090 D6 Tier 1).
|
|
3
|
+
*
|
|
4
|
+
* Asserts the declarative surface (commandSpecs / identity / metadata), the binary
|
|
5
|
+
* helpers (version parse + scan args), the FROZEN exit model (Phase-0 decision 4),
|
|
6
|
+
* the manifest↔runtime host-shape guards (`assertManifestMatchesTool` +
|
|
7
|
+
* `deriveAdapterManifestCommands` parity), and the full normalize→envelope path
|
|
8
|
+
* via the acceptance harness — including a redaction check across the envelope.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
import { assertManifestMatchesTool } from '@opensip-cli/core';
|
|
13
|
+
import { DEFAULT_EXIT_MODEL, deriveAdapterConfigManifest, deriveAdapterManifestCommands, deriveAdapterManifestRequires, interpretExit, normalizedSignalShape, runAcceptanceCase, } from '@opensip-cli/external-tool-adapter';
|
|
14
|
+
import { describe, expect, it } from 'vitest';
|
|
15
|
+
import { parseGitleaksJson } from '../parse-gitleaks-json.js';
|
|
16
|
+
import { buildGitleaksExclude, buildScanArgs, GITLEAKS_STABLE_ID, parseGitleaksVersion, tool, } from '../tool.js';
|
|
17
|
+
const PKG = JSON.parse(readFileSync(fileURLToPath(new URL('../../package.json', import.meta.url)), 'utf8'));
|
|
18
|
+
const GOLDEN_RAW = readFileSync(fileURLToPath(new URL('../../__fixtures__/gitleaks-golden.json', import.meta.url)), 'utf8');
|
|
19
|
+
const EXPECTED = JSON.parse(readFileSync(fileURLToPath(new URL('../../__fixtures__/expected-signals.json', import.meta.url)), 'utf8'));
|
|
20
|
+
/** Reconstruct the admitted `ToolPluginManifest` the host builds from package.json. */
|
|
21
|
+
function manifestFromPackage() {
|
|
22
|
+
return {
|
|
23
|
+
...PKG.opensipTools,
|
|
24
|
+
name: PKG.name,
|
|
25
|
+
version: PKG.version,
|
|
26
|
+
apiVersion: PKG.opensipTools.apiVersion,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
describe('gitleaks tool — identity + metadata', () => {
|
|
30
|
+
it('declares the gitleaks identity with the `secrets` alias', () => {
|
|
31
|
+
expect(tool.identity).toEqual({ name: 'gitleaks', aliases: ['secrets'] });
|
|
32
|
+
});
|
|
33
|
+
it('carries the stable UUID and a description', () => {
|
|
34
|
+
expect(tool.metadata.id).toBe(GITLEAKS_STABLE_ID);
|
|
35
|
+
expect(tool.metadata.name).toBe('gitleaks');
|
|
36
|
+
expect(tool.metadata.description).toBe('Secret scanning via Gitleaks');
|
|
37
|
+
});
|
|
38
|
+
it('defaults to the line-shift-tolerant message-hash fingerprint strategy', () => {
|
|
39
|
+
expect(tool.extensionPoints?.fingerprintStrategy?.id).toBe('external-tool-adapter.sha256-file-rule-message');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
const byName = (name) => tool.commandSpecs?.find((c) => c.name === name);
|
|
43
|
+
describe('gitleaks tool — commandSpecs', () => {
|
|
44
|
+
it('mounts the primary scan, plus nested doctor + version', () => {
|
|
45
|
+
const names = (tool.commandSpecs ?? []).map((c) => c.name);
|
|
46
|
+
expect(names).toEqual(['gitleaks', 'doctor', 'version']);
|
|
47
|
+
});
|
|
48
|
+
it('the primary command is `gitleaks` (aliased `secrets`), project-scoped, raw-stream dispatch', () => {
|
|
49
|
+
const primary = byName('gitleaks');
|
|
50
|
+
expect(primary?.parent).toBeUndefined();
|
|
51
|
+
expect(primary?.aliases).toEqual(['secrets']);
|
|
52
|
+
expect(primary?.scope).toBe('project');
|
|
53
|
+
expect(primary?.output).toBe('raw-stream');
|
|
54
|
+
expect(primary?.rawStreamReason).toBe('runtime-render-dispatch');
|
|
55
|
+
});
|
|
56
|
+
it('doctor + version are nested under gitleaks, scope:none, diagnostic-gate', () => {
|
|
57
|
+
for (const name of ['doctor', 'version']) {
|
|
58
|
+
const spec = byName(name);
|
|
59
|
+
expect(spec?.parent).toBe('gitleaks');
|
|
60
|
+
expect(spec?.scope).toBe('none');
|
|
61
|
+
expect(spec?.output).toBe('raw-stream');
|
|
62
|
+
expect(spec?.rawStreamReason).toBe('diagnostic-gate');
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('gitleaks tool — binary helpers', () => {
|
|
67
|
+
it('parses the gitleaks version stdout (with or without a leading v)', () => {
|
|
68
|
+
expect(parseGitleaksVersion('8.18.4')).toBe('8.18.4');
|
|
69
|
+
expect(parseGitleaksVersion('v8.18.4\n')).toBe('8.18.4');
|
|
70
|
+
expect(parseGitleaksVersion('gitleaks version 8.19.0')).toBe('8.19.0');
|
|
71
|
+
});
|
|
72
|
+
it('falls back to the trimmed stdout when no semver is present', () => {
|
|
73
|
+
expect(parseGitleaksVersion(' unknown ')).toBe('unknown');
|
|
74
|
+
});
|
|
75
|
+
it('builds the filesystem-scan argv writing JSON to the run artifact path', () => {
|
|
76
|
+
const ctx = {
|
|
77
|
+
projectRoot: '/proj',
|
|
78
|
+
artifactPath: (name) => `/proj/.runtime/artifacts/gitleaks/run1/${name}`,
|
|
79
|
+
};
|
|
80
|
+
expect(buildScanArgs(ctx)).toEqual([
|
|
81
|
+
'detect',
|
|
82
|
+
'--no-git',
|
|
83
|
+
'--source',
|
|
84
|
+
'/proj',
|
|
85
|
+
'--report-format',
|
|
86
|
+
'json',
|
|
87
|
+
'--report-path',
|
|
88
|
+
'/proj/.runtime/artifacts/gitleaks/run1/gitleaks.json',
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('gitleaks tool — A3 .runtime exclusion (buildGitleaksExclude)', () => {
|
|
93
|
+
const ex = buildGitleaksExclude({
|
|
94
|
+
excludePath: '/proj/opensip-cli/.runtime',
|
|
95
|
+
configPath: (name) => `/proj/opensip-cli/.runtime/artifacts/gitleaks/run1/${name}`,
|
|
96
|
+
});
|
|
97
|
+
it('references a generated --config allowlist written to the per-run dir', () => {
|
|
98
|
+
const cfg = '/proj/opensip-cli/.runtime/artifacts/gitleaks/run1/gitleaks-exclude.toml';
|
|
99
|
+
expect(ex.args).toEqual(['--config', cfg]);
|
|
100
|
+
expect(ex.configFile.path).toBe(cfg);
|
|
101
|
+
});
|
|
102
|
+
it('extends the default ruleset and allowlists the .runtime store (with the E2E marker)', () => {
|
|
103
|
+
expect(ex.configFile.contents).toContain('useDefault = true');
|
|
104
|
+
// The allowlist path regex matches any file under opensip-cli/.runtime.
|
|
105
|
+
expect(ex.configFile.contents).toContain('opensip-cli/\\.runtime');
|
|
106
|
+
// The marker the deterministic worker-E2E fake reads to honor the exclusion.
|
|
107
|
+
expect(ex.configFile.contents).toContain('# opensip-cli A3 exclude: opensip-cli/.runtime');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('gitleaks tool — exit model (Phase-0 decision 4)', () => {
|
|
111
|
+
const model = { ok: [0], findings: [1], errorFrom: 2 };
|
|
112
|
+
it('exit 0 ⇒ clean (no findings)', () => {
|
|
113
|
+
expect(interpretExit(0, model)).toBe('ok');
|
|
114
|
+
});
|
|
115
|
+
it('exit 1 + a valid artifact ⇒ findings', () => {
|
|
116
|
+
expect(interpretExit(1, model, { artifactValid: true })).toBe('findings');
|
|
117
|
+
});
|
|
118
|
+
it('exit 1 + a missing/garbage artifact ⇒ fault (the gitleaks disambiguation)', () => {
|
|
119
|
+
expect(interpretExit(1, model, { artifactValid: false })).toBe('fault');
|
|
120
|
+
});
|
|
121
|
+
it('exit >= 2 ⇒ fault', () => {
|
|
122
|
+
expect(interpretExit(2, model)).toBe('fault');
|
|
123
|
+
expect(interpretExit(7, model)).toBe('fault');
|
|
124
|
+
});
|
|
125
|
+
it('matches the substrate default model', () => {
|
|
126
|
+
expect(model).toEqual(DEFAULT_EXIT_MODEL);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('gitleaks tool — manifest ↔ runtime host-shape guards', () => {
|
|
130
|
+
it('the package.json manifest matches the runtime tool (no drift)', () => {
|
|
131
|
+
expect(() => {
|
|
132
|
+
assertManifestMatchesTool(manifestFromPackage(), tool);
|
|
133
|
+
}).not.toThrow();
|
|
134
|
+
});
|
|
135
|
+
it('the generated manifest commands equal the derived runtime command shells', () => {
|
|
136
|
+
// The package.json `commands` are written by the shared manifest generator
|
|
137
|
+
// (which OMITS an empty `aliases`), while the substrate's
|
|
138
|
+
// `deriveAdapterManifestCommands` always emits `aliases: []`. Canonicalize
|
|
139
|
+
// that one representational difference (`aliases ?? []`) before comparing the
|
|
140
|
+
// substantive shells.
|
|
141
|
+
const canon = (c) => ({
|
|
142
|
+
...c,
|
|
143
|
+
aliases: c.aliases ?? [],
|
|
144
|
+
});
|
|
145
|
+
const generated = PKG.opensipTools.commands.map(canon);
|
|
146
|
+
const derived = deriveAdapterManifestCommands(tool).map((c) => canon(c));
|
|
147
|
+
expect(generated).toEqual(derived);
|
|
148
|
+
});
|
|
149
|
+
it('the generated manifest requires equal the posture-derived requires (no drift)', () => {
|
|
150
|
+
// A13: `requires` is DERIVED from the network posture, not hand-typed. The
|
|
151
|
+
// generated manifest must match the substrate derivation byte-for-byte, so a
|
|
152
|
+
// posture flip surfaces as a `--check` drift.
|
|
153
|
+
expect(PKG.opensipTools.requires).toEqual(deriveAdapterManifestRequires(tool));
|
|
154
|
+
});
|
|
155
|
+
it('derives subprocess + filesystem only (local-only posture, no network)', () => {
|
|
156
|
+
expect(PKG.opensipTools.requires.map((r) => r.resource)).toEqual([
|
|
157
|
+
'subprocess',
|
|
158
|
+
'filesystem',
|
|
159
|
+
]);
|
|
160
|
+
});
|
|
161
|
+
it('the generated manifest config descriptor equals the derived namespace claim (A4)', () => {
|
|
162
|
+
// A4: the installed-path namespace claim (so the host pre-fork pass recognizes a
|
|
163
|
+
// `gitleaks:` block and never bricks). Generator parity guards against drift.
|
|
164
|
+
const derived = deriveAdapterConfigManifest(tool);
|
|
165
|
+
expect(derived?.namespace).toBe('gitleaks');
|
|
166
|
+
expect(PKG.opensipTools.config).toEqual(derived);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe('gitleaks tool — acceptance harness (normalize → envelope)', () => {
|
|
170
|
+
const result = runAcceptanceCase({
|
|
171
|
+
tool: 'gitleaks',
|
|
172
|
+
kind: 'json',
|
|
173
|
+
raw: GOLDEN_RAW,
|
|
174
|
+
parse: parseGitleaksJson,
|
|
175
|
+
fingerprintStrategy: 'message-hash',
|
|
176
|
+
});
|
|
177
|
+
it('produces the golden normalized signals', () => {
|
|
178
|
+
expect(result.signals.map(normalizedSignalShape)).toEqual(EXPECTED);
|
|
179
|
+
});
|
|
180
|
+
it('builds an envelope whose verdict FAILS (high-severity secrets are error-rung)', () => {
|
|
181
|
+
expect(result.envelope.tool).toBe('gitleaks');
|
|
182
|
+
expect(result.envelope.verdict.passed).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
it('stamps a message-hash fingerprint on every envelope signal worker-side', () => {
|
|
185
|
+
expect(result.envelope.signals).toHaveLength(2);
|
|
186
|
+
for (const s of result.envelope.signals) {
|
|
187
|
+
expect(s.fingerprint).toMatch(/^[0-9a-f]{64}$/);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
it('NEVER lets a raw secret into the built envelope (secret-egress guard)', () => {
|
|
191
|
+
const serialized = JSON.stringify(result.envelope);
|
|
192
|
+
for (const raw of ['AKIAIOSFODNN7EXAMPLE', 'glpat-XXXXXXXXXXXXXXXXXXXX', 'aws_key =']) {
|
|
193
|
+
expect(serialized).not.toContain(raw);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
//# 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
|
+
* gitleaks 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 gitleaks 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 `gitleaks` binary on PATH makes the run deterministic (it copies the
|
|
12
|
+
* committed golden to `--report-path` and exits 1, like real gitleaks 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 gitleaks` forks a worker that re-discovers + imports the real runtime
|
|
17
|
+
* and runs the scan loop; this suite asserts the worker→host result + the
|
|
18
|
+
* host-side effects: normalized signals match the golden, the raw artifact lands
|
|
19
|
+
* at `.runtime/artifacts/gitleaks/<runId>/gitleaks.json` with mode 0600, the
|
|
20
|
+
* `--json` envelope is well-formed, the session row persists with provenance, and
|
|
21
|
+
* — the load-bearing negative — NO raw `Secret`/`Match` substring ever reaches the
|
|
22
|
+
* emitted worker→host payload.
|
|
23
|
+
*
|
|
24
|
+
* Requires `pnpm build` first (the CLI dist + the gitleaks 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"}
|