@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/dist/tool.d.ts ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * `@opensip-cli/tool-gitleaks` Tool descriptor (ADR-0090 / ADR-0091 / ADR-0092).
3
+ *
4
+ * The FIRST External Tool Adapter: it wraps the user-installed `gitleaks` secret
5
+ * scanner as an ordinary opensip-cli `Tool` via {@link defineExternalToolAdapter}.
6
+ * The substrate owns binary resolution, the run loop (resolve → execFile → ingest
7
+ * → normalize → persist via the host artifact seam), secret redaction, provenance,
8
+ * and the auto-added `doctor`/`version` commands; this module declares only the
9
+ * gitleaks identity, the wrapped binary, and the `scan` command (args + JSON
10
+ * parser).
11
+ *
12
+ * Layer 4: imports the substrate + `@opensip-cli/core` ONLY — never the CLI,
13
+ * output, or any other adapter (dependency-cruiser enforced).
14
+ *
15
+ * This is an OPT-IN, installed tool (NOT in `bundled-tools.manifest.json`): the
16
+ * host never imports this runtime; an `opensip gitleaks` invocation forks a worker
17
+ * that re-discovers + imports it and runs the handler. Installed tools are
18
+ * deny-by-default — a run needs `OPENSIP_CLI_ALLOW_INSTALLED_TOOLS` to include the
19
+ * gitleaks id.
20
+ */
21
+ import type { Tool, ToolIdentity } from '@opensip-cli/core';
22
+ import type { AdapterRunContext } from '@opensip-cli/external-tool-adapter';
23
+ /** Human/aliased identity (`opensip gitleaks` / `opensip secrets`). */
24
+ export declare const GITLEAKS_IDENTITY: ToolIdentity;
25
+ /** Stable UUID identity (ADR-0048); mirrors `opensipTools.stableId` in package.json. */
26
+ export declare const GITLEAKS_STABLE_ID = "cd08f737-ce8e-4813-9259-b4ffeb954268";
27
+ /**
28
+ * Normalize the `gitleaks version` stdout to a bare semver. Gitleaks prints
29
+ * either `8.18.4` or `v8.18.4` (and, on some builds, a multi-line banner); take
30
+ * the first semver-shaped token and strip a leading `v`.
31
+ *
32
+ * VERIFY-against-installed-binary: exact `gitleaks version` output format.
33
+ */
34
+ export declare function parseGitleaksVersion(stdout: string): string;
35
+ /**
36
+ * Build the gitleaks scan argv (no shell — args are passed to `execFile`). Scans
37
+ * the project working tree (`detect --no-git --source <root>`) and writes a JSON
38
+ * report to the host-owned artifact path the substrate composes for this run.
39
+ *
40
+ * VERIFY-against-installed-binary: `detect --no-git --source <root>` scans files
41
+ * on disk (incl. uncommitted) rather than git history; v8.19 renamed the verb to
42
+ * `gitleaks dir <root>`.
43
+ */
44
+ export declare function buildScanArgs(ctx: AdapterRunContext): readonly string[];
45
+ /**
46
+ * A3: build gitleaks's exclusion of opensip's own `.runtime` artifact store.
47
+ *
48
+ * gitleaks has NO CLI path-exclude, so we generate a `--config` allowlist that
49
+ * EXTENDS the default ruleset (secret detection still runs) and allowlists any
50
+ * file under `opensip-cli/.runtime`. Without this, a raw `Secret`/`Match` in a
51
+ * prior run's JSON report is re-detected with a new runId in its path → a net-new
52
+ * message-hash fingerprint every run → permanently degraded `--gate-compare`.
53
+ *
54
+ * The leading `# opensip-cli A3 exclude:` marker is load-bearing for the
55
+ * deterministic worker-E2E fake (it honors the SAME injected exclusion the real
56
+ * binary reads from the allowlist). VERIFY-against-installed-binary: gitleaks
57
+ * allowlist `paths` regex semantics (matched against the reported file path).
58
+ */
59
+ export declare function buildGitleaksExclude(input: {
60
+ readonly excludePath: string;
61
+ readonly configPath: (name: string) => string;
62
+ }): {
63
+ readonly args: readonly string[];
64
+ readonly configFile: {
65
+ path: string;
66
+ contents: string;
67
+ };
68
+ };
69
+ /**
70
+ * The gitleaks external-tool adapter `Tool`. The host loads it by name through
71
+ * the installed-tool worker-dispatch path (the barrel re-exports it as `tool`).
72
+ */
73
+ export declare const tool: Tool;
74
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,EAAE,YAG/B,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,kBAAkB,yCAAyC,CAAC;AAEzE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,SAAS,MAAM,EAAE,CAWvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/C,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAahG;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,EAAE,IA2CjB,CAAC"}
package/dist/tool.js ADDED
@@ -0,0 +1,140 @@
1
+ /**
2
+ * `@opensip-cli/tool-gitleaks` Tool descriptor (ADR-0090 / ADR-0091 / ADR-0092).
3
+ *
4
+ * The FIRST External Tool Adapter: it wraps the user-installed `gitleaks` secret
5
+ * scanner as an ordinary opensip-cli `Tool` via {@link defineExternalToolAdapter}.
6
+ * The substrate owns binary resolution, the run loop (resolve → execFile → ingest
7
+ * → normalize → persist via the host artifact seam), secret redaction, provenance,
8
+ * and the auto-added `doctor`/`version` commands; this module declares only the
9
+ * gitleaks identity, the wrapped binary, and the `scan` command (args + JSON
10
+ * parser).
11
+ *
12
+ * Layer 4: imports the substrate + `@opensip-cli/core` ONLY — never the CLI,
13
+ * output, or any other adapter (dependency-cruiser enforced).
14
+ *
15
+ * This is an OPT-IN, installed tool (NOT in `bundled-tools.manifest.json`): the
16
+ * host never imports this runtime; an `opensip gitleaks` invocation forks a worker
17
+ * that re-discovers + imports it and runs the handler. Installed tools are
18
+ * deny-by-default — a run needs `OPENSIP_CLI_ALLOW_INSTALLED_TOOLS` to include the
19
+ * gitleaks id.
20
+ */
21
+ import { readPackageVersion } from '@opensip-cli/core';
22
+ import { defineExternalToolAdapter } from '@opensip-cli/external-tool-adapter';
23
+ import { parseGitleaksJson } from './parse-gitleaks-json.js';
24
+ /** Human/aliased identity (`opensip gitleaks` / `opensip secrets`). */
25
+ export const GITLEAKS_IDENTITY = {
26
+ name: 'gitleaks',
27
+ aliases: ['secrets'],
28
+ };
29
+ /** Stable UUID identity (ADR-0048); mirrors `opensipTools.stableId` in package.json. */
30
+ export const GITLEAKS_STABLE_ID = 'cd08f737-ce8e-4813-9259-b4ffeb954268';
31
+ /**
32
+ * Normalize the `gitleaks version` stdout to a bare semver. Gitleaks prints
33
+ * either `8.18.4` or `v8.18.4` (and, on some builds, a multi-line banner); take
34
+ * the first semver-shaped token and strip a leading `v`.
35
+ *
36
+ * VERIFY-against-installed-binary: exact `gitleaks version` output format.
37
+ */
38
+ export function parseGitleaksVersion(stdout) {
39
+ // Fully bounded ({1,5} digit runs, {1,2} dotted segments) so the matcher is
40
+ // linear — major.minor[.patch], optional leading `v`.
41
+ const match = /v?(\d{1,5}(?:\.\d{1,5}){1,2})/.exec(stdout);
42
+ return match?.[1] ?? stdout.trim();
43
+ }
44
+ /**
45
+ * Build the gitleaks scan argv (no shell — args are passed to `execFile`). Scans
46
+ * the project working tree (`detect --no-git --source <root>`) and writes a JSON
47
+ * report to the host-owned artifact path the substrate composes for this run.
48
+ *
49
+ * VERIFY-against-installed-binary: `detect --no-git --source <root>` scans files
50
+ * on disk (incl. uncommitted) rather than git history; v8.19 renamed the verb to
51
+ * `gitleaks dir <root>`.
52
+ */
53
+ export function buildScanArgs(ctx) {
54
+ return [
55
+ 'detect',
56
+ '--no-git',
57
+ '--source',
58
+ ctx.projectRoot,
59
+ '--report-format',
60
+ 'json',
61
+ '--report-path',
62
+ ctx.artifactPath('gitleaks.json'),
63
+ ];
64
+ }
65
+ /**
66
+ * A3: build gitleaks's exclusion of opensip's own `.runtime` artifact store.
67
+ *
68
+ * gitleaks has NO CLI path-exclude, so we generate a `--config` allowlist that
69
+ * EXTENDS the default ruleset (secret detection still runs) and allowlists any
70
+ * file under `opensip-cli/.runtime`. Without this, a raw `Secret`/`Match` in a
71
+ * prior run's JSON report is re-detected with a new runId in its path → a net-new
72
+ * message-hash fingerprint every run → permanently degraded `--gate-compare`.
73
+ *
74
+ * The leading `# opensip-cli A3 exclude:` marker is load-bearing for the
75
+ * deterministic worker-E2E fake (it honors the SAME injected exclusion the real
76
+ * binary reads from the allowlist). VERIFY-against-installed-binary: gitleaks
77
+ * allowlist `paths` regex semantics (matched against the reported file path).
78
+ */
79
+ export function buildGitleaksExclude(input) {
80
+ const path = input.configPath('gitleaks-exclude.toml');
81
+ const contents = [
82
+ '# opensip-cli A3 exclude: opensip-cli/.runtime',
83
+ '[extend]',
84
+ 'useDefault = true',
85
+ '',
86
+ '[allowlist]',
87
+ 'description = "opensip-cli: skip the .runtime artifact store"',
88
+ "paths = ['''(^|/)opensip-cli/\\.runtime(/|$)''']",
89
+ '',
90
+ ].join('\n');
91
+ return { args: ['--config', path], configFile: { path, contents } };
92
+ }
93
+ /**
94
+ * The gitleaks external-tool adapter `Tool`. The host loads it by name through
95
+ * the installed-tool worker-dispatch path (the barrel re-exports it as `tool`).
96
+ */
97
+ export const tool = defineExternalToolAdapter({
98
+ identity: GITLEAKS_IDENTITY,
99
+ metadata: {
100
+ id: GITLEAKS_STABLE_ID,
101
+ version: readPackageVersion(import.meta.url),
102
+ description: 'Secret scanning via Gitleaks',
103
+ adapterPackage: '@opensip-cli/tool-gitleaks',
104
+ },
105
+ binary: {
106
+ command: 'gitleaks',
107
+ versionArgs: ['version'],
108
+ versionParse: parseGitleaksVersion,
109
+ // `detect --no-git --source` is the stable filesystem-scan invocation; the
110
+ // renamed `gitleaks dir` verb is v8.19+. VERIFY-against-installed-binary.
111
+ minVersion: '8.18.0',
112
+ // Operator pin (config `binaries.gitleaks.path` / `OPENSIP_GITLEAKS_BIN`)
113
+ // beats PATH; resolution never fetches a binary.
114
+ resolution: ['config', 'path'],
115
+ installHint: 'Install gitleaks: https://github.com/gitleaks/gitleaks#installing (brew install gitleaks)',
116
+ },
117
+ // Gitleaks scans local files via execFile — no network, no credentials.
118
+ network: 'local-only',
119
+ commands: [
120
+ {
121
+ name: 'scan',
122
+ description: 'Scan the project working tree for committed secrets (Gitleaks)',
123
+ args: buildScanArgs,
124
+ output: { kind: 'json', path: 'gitleaks.json' },
125
+ // ADR-0091 Phase-0 decision 4: `0` clean, `1` findings, `>=2` fault. Gitleaks
126
+ // ALSO exits 1 on an internal fatal — the substrate disambiguates by artifact
127
+ // presence + JSON-parseability (exit 1 + valid report ⇒ findings; exit 1 +
128
+ // missing/garbage ⇒ fault).
129
+ exitCodes: { ok: [0], findings: [1], errorFrom: 2 },
130
+ parse: parseGitleaksJson,
131
+ // A3: never re-detect secrets in opensip's OWN persisted reports under
132
+ // `.runtime/` (see {@link buildGitleaksExclude}).
133
+ excludeScan: buildGitleaksExclude,
134
+ },
135
+ ],
136
+ // Scanner output is line-volatile → the line-shift-tolerant message hash, not
137
+ // the host `ruleId|file|line|col` default. Stamped worker-side in the run loop.
138
+ fingerprintStrategy: 'message-hash',
139
+ });
140
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,142 @@
1
+ {
2
+ "name": "@opensip-cli/tool-gitleaks",
3
+ "version": "0.1.15",
4
+ "license": "Apache-2.0",
5
+ "description": "External Tool Adapter for Gitleaks — wraps the gitleaks secret scanner as an opensip-cli tool (opensip gitleaks / opensip secrets)",
6
+ "keywords": [
7
+ "opensip-cli",
8
+ "static-analysis",
9
+ "code-quality",
10
+ "security",
11
+ "gitleaks",
12
+ "secrets",
13
+ "scanner"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/opensip-ai/opensip-cli.git",
18
+ "directory": "packages/tool-gitleaks"
19
+ },
20
+ "homepage": "https://github.com/opensip-ai/opensip-cli",
21
+ "bugs": {
22
+ "url": "https://github.com/opensip-ai/opensip-cli/issues"
23
+ },
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": "./dist/index.js"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "LICENSE",
33
+ "NOTICE"
34
+ ],
35
+ "opensipTools": {
36
+ "kind": "tool",
37
+ "id": "gitleaks",
38
+ "identity": {
39
+ "name": "gitleaks",
40
+ "aliases": [
41
+ "secrets"
42
+ ]
43
+ },
44
+ "stableId": "cd08f737-ce8e-4813-9259-b4ffeb954268",
45
+ "apiVersion": 1,
46
+ "requires": [
47
+ {
48
+ "resource": "subprocess",
49
+ "reason": "Executes the user-installed gitleaks binary via execFile (no shell)"
50
+ },
51
+ {
52
+ "resource": "filesystem",
53
+ "reason": "Reads the project working tree and writes the raw scan artifact under .runtime/artifacts"
54
+ }
55
+ ],
56
+ "commands": [
57
+ {
58
+ "name": "gitleaks",
59
+ "description": "Scan the project working tree for committed secrets (Gitleaks)",
60
+ "aliases": [
61
+ "secrets"
62
+ ],
63
+ "commonFlags": [
64
+ "json",
65
+ "cwd",
66
+ "quiet",
67
+ "verbose",
68
+ "debug",
69
+ "reportTo",
70
+ "apiKey",
71
+ "open"
72
+ ],
73
+ "options": [
74
+ {
75
+ "flag": "--gate-save",
76
+ "description": "Architecture-gate: save current findings as baseline in the project SQLite store (mutually exclusive with --gate-compare)",
77
+ "default": false
78
+ },
79
+ {
80
+ "flag": "--gate-compare",
81
+ "description": "Architecture-gate: compare current findings against the saved baseline; exit 1 on regression",
82
+ "default": false
83
+ }
84
+ ],
85
+ "scope": "project",
86
+ "output": "raw-stream",
87
+ "rawStreamReason": "runtime-render-dispatch"
88
+ },
89
+ {
90
+ "name": "doctor",
91
+ "description": "Check that the gitleaks binary is installed and ready",
92
+ "parent": "gitleaks",
93
+ "commonFlags": [
94
+ "json",
95
+ "cwd"
96
+ ],
97
+ "scope": "none",
98
+ "output": "raw-stream",
99
+ "rawStreamReason": "diagnostic-gate"
100
+ },
101
+ {
102
+ "name": "version",
103
+ "description": "Print the resolved gitleaks binary version",
104
+ "parent": "gitleaks",
105
+ "commonFlags": [
106
+ "json",
107
+ "cwd"
108
+ ],
109
+ "scope": "none",
110
+ "output": "raw-stream",
111
+ "rawStreamReason": "diagnostic-gate"
112
+ }
113
+ ],
114
+ "config": {
115
+ "namespace": "gitleaks",
116
+ "schema": {
117
+ "type": "object",
118
+ "properties": {
119
+ "binaries": {
120
+ "type": "object"
121
+ }
122
+ }
123
+ }
124
+ }
125
+ },
126
+ "dependencies": {
127
+ "typescript": "~6.0.3",
128
+ "@opensip-cli/contracts": "0.1.15",
129
+ "@opensip-cli/external-tool-adapter": "0.1.15",
130
+ "@opensip-cli/core": "0.1.15"
131
+ },
132
+ "devDependencies": {
133
+ "@types/node": "^24.13.2",
134
+ "vitest": "^4.1.8"
135
+ },
136
+ "scripts": {
137
+ "build": "tsc",
138
+ "test": "vitest run --passWithNoTests",
139
+ "typecheck": "tsc --noEmit",
140
+ "clean": "rm -rf dist"
141
+ }
142
+ }