@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.
@@ -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"}