@vyuhlabs/dxkit 2.7.1 → 2.9.0

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.
Files changed (133) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +20 -9
  3. package/dist/analyzers/cache.js +11 -0
  4. package/dist/analyzers/cache.js.map +1 -1
  5. package/dist/analyzers/security/aggregator.d.ts +20 -0
  6. package/dist/analyzers/security/aggregator.d.ts.map +1 -1
  7. package/dist/analyzers/security/aggregator.js +5 -0
  8. package/dist/analyzers/security/aggregator.js.map +1 -1
  9. package/dist/analyzers/security/gather.d.ts.map +1 -1
  10. package/dist/analyzers/security/gather.js +8 -0
  11. package/dist/analyzers/security/gather.js.map +1 -1
  12. package/dist/analyzers/tools/grep-secrets.d.ts +6 -1
  13. package/dist/analyzers/tools/grep-secrets.d.ts.map +1 -1
  14. package/dist/analyzers/tools/grep-secrets.js +80 -60
  15. package/dist/analyzers/tools/grep-secrets.js.map +1 -1
  16. package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
  17. package/dist/analyzers/tools/tool-registry.js +50 -0
  18. package/dist/analyzers/tools/tool-registry.js.map +1 -1
  19. package/dist/baseline/create.d.ts.map +1 -1
  20. package/dist/baseline/create.js +18 -6
  21. package/dist/baseline/create.js.map +1 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +58 -0
  24. package/dist/cli.js.map +1 -1
  25. package/dist/doctor.d.ts.map +1 -1
  26. package/dist/doctor.js +85 -7
  27. package/dist/doctor.js.map +1 -1
  28. package/dist/explore/cli/context.d.ts +1 -1
  29. package/dist/explore/cli/context.d.ts.map +1 -1
  30. package/dist/explore/cli/context.js +173 -4
  31. package/dist/explore/cli/context.js.map +1 -1
  32. package/dist/explore/queries.d.ts +71 -0
  33. package/dist/explore/queries.d.ts.map +1 -1
  34. package/dist/explore/queries.js +76 -0
  35. package/dist/explore/queries.js.map +1 -1
  36. package/dist/explore/source-slice.d.ts +51 -0
  37. package/dist/explore/source-slice.d.ts.map +1 -0
  38. package/dist/explore/source-slice.js +88 -0
  39. package/dist/explore/source-slice.js.map +1 -0
  40. package/dist/explore-cli.js +6 -4
  41. package/dist/explore-cli.js.map +1 -1
  42. package/dist/generator.d.ts.map +1 -1
  43. package/dist/generator.js +18 -0
  44. package/dist/generator.js.map +1 -1
  45. package/dist/hooks-cli.d.ts.map +1 -1
  46. package/dist/hooks-cli.js +43 -0
  47. package/dist/hooks-cli.js.map +1 -1
  48. package/dist/ingest/codeql.d.ts +36 -0
  49. package/dist/ingest/codeql.d.ts.map +1 -0
  50. package/dist/ingest/codeql.js +166 -0
  51. package/dist/ingest/codeql.js.map +1 -0
  52. package/dist/ingest/config.d.ts +10 -0
  53. package/dist/ingest/config.d.ts.map +1 -0
  54. package/dist/ingest/config.js +69 -0
  55. package/dist/ingest/config.js.map +1 -0
  56. package/dist/ingest/engine-resolver.d.ts +42 -0
  57. package/dist/ingest/engine-resolver.d.ts.map +1 -0
  58. package/dist/ingest/engine-resolver.js +89 -0
  59. package/dist/ingest/engine-resolver.js.map +1 -0
  60. package/dist/ingest/normalize.d.ts +23 -0
  61. package/dist/ingest/normalize.d.ts.map +1 -0
  62. package/dist/ingest/normalize.js +18 -0
  63. package/dist/ingest/normalize.js.map +1 -0
  64. package/dist/ingest/sarif.d.ts +29 -0
  65. package/dist/ingest/sarif.d.ts.map +1 -0
  66. package/dist/ingest/sarif.js +136 -0
  67. package/dist/ingest/sarif.js.map +1 -0
  68. package/dist/ingest/snapshot.d.ts +26 -0
  69. package/dist/ingest/snapshot.d.ts.map +1 -0
  70. package/dist/ingest/snapshot.js +114 -0
  71. package/dist/ingest/snapshot.js.map +1 -0
  72. package/dist/ingest/snyk-api.d.ts +82 -0
  73. package/dist/ingest/snyk-api.d.ts.map +1 -0
  74. package/dist/ingest/snyk-api.js +114 -0
  75. package/dist/ingest/snyk-api.js.map +1 -0
  76. package/dist/ingest/snyk-cli.d.ts +22 -0
  77. package/dist/ingest/snyk-cli.d.ts.map +1 -0
  78. package/dist/ingest/snyk-cli.js +135 -0
  79. package/dist/ingest/snyk-cli.js.map +1 -0
  80. package/dist/ingest/types.d.ts +68 -0
  81. package/dist/ingest/types.d.ts.map +1 -0
  82. package/dist/ingest/types.js +3 -0
  83. package/dist/ingest/types.js.map +1 -0
  84. package/dist/ingest-cli.d.ts +21 -0
  85. package/dist/ingest-cli.d.ts.map +1 -0
  86. package/dist/ingest-cli.js +232 -0
  87. package/dist/ingest-cli.js.map +1 -0
  88. package/dist/languages/csharp.d.ts +9 -0
  89. package/dist/languages/csharp.d.ts.map +1 -1
  90. package/dist/languages/csharp.js +87 -7
  91. package/dist/languages/csharp.js.map +1 -1
  92. package/dist/languages/go.d.ts.map +1 -1
  93. package/dist/languages/go.js +2 -0
  94. package/dist/languages/go.js.map +1 -1
  95. package/dist/languages/index.d.ts +21 -1
  96. package/dist/languages/index.d.ts.map +1 -1
  97. package/dist/languages/index.js +32 -0
  98. package/dist/languages/index.js.map +1 -1
  99. package/dist/languages/java.d.ts.map +1 -1
  100. package/dist/languages/java.js +2 -0
  101. package/dist/languages/java.js.map +1 -1
  102. package/dist/languages/kotlin.d.ts.map +1 -1
  103. package/dist/languages/kotlin.js +8 -0
  104. package/dist/languages/kotlin.js.map +1 -1
  105. package/dist/languages/python.d.ts.map +1 -1
  106. package/dist/languages/python.js +2 -0
  107. package/dist/languages/python.js.map +1 -1
  108. package/dist/languages/ruby.d.ts.map +1 -1
  109. package/dist/languages/ruby.js +2 -0
  110. package/dist/languages/ruby.js.map +1 -1
  111. package/dist/languages/rust.d.ts.map +1 -1
  112. package/dist/languages/rust.js +3 -0
  113. package/dist/languages/rust.js.map +1 -1
  114. package/dist/languages/types.d.ts +40 -0
  115. package/dist/languages/types.d.ts.map +1 -1
  116. package/dist/languages/typescript.d.ts.map +1 -1
  117. package/dist/languages/typescript.js +3 -0
  118. package/dist/languages/typescript.js.map +1 -1
  119. package/dist/ship-installers.d.ts +22 -0
  120. package/dist/ship-installers.d.ts.map +1 -1
  121. package/dist/ship-installers.js +83 -3
  122. package/dist/ship-installers.js.map +1 -1
  123. package/dist/update.d.ts.map +1 -1
  124. package/dist/update.js +8 -0
  125. package/dist/update.js.map +1 -1
  126. package/package.json +1 -1
  127. package/templates/.claude/skills/dxkit-action/SKILL.md +9 -0
  128. package/templates/.claude/skills/dxkit-config/SKILL.md +23 -0
  129. package/templates/.claude/skills/dxkit-docs/SKILL.md +148 -0
  130. package/templates/.claude/skills/dxkit-feature/SKILL.md +189 -0
  131. package/templates/.claude/skills/dxkit-ingest/SKILL.md +99 -0
  132. package/templates/.claude/skills/dxkit-update/SKILL.md +10 -0
  133. package/templates/.github/workflows/dxkit-deep-sast-refresh.yml +104 -0
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.snykIssueToFinding = snykIssueToFinding;
4
+ exports.fetchSnykCodeFindings = fetchSnykCodeFindings;
5
+ const DEFAULT_API_BASE = 'https://api.snyk.io';
6
+ const DEFAULT_VERSION = '2024-10-15';
7
+ /** Snyk's five-level severity → dxkit's four-tier. `info` folds to
8
+ * `low` (dxkit has no info tier). */
9
+ function mapSeverity(level) {
10
+ switch (level) {
11
+ case 'critical':
12
+ return 'critical';
13
+ case 'high':
14
+ return 'high';
15
+ case 'medium':
16
+ return 'medium';
17
+ case 'low':
18
+ case 'info':
19
+ return 'low';
20
+ default:
21
+ return 'medium';
22
+ }
23
+ }
24
+ /** Extract the first CWE id from an issue's `classes`. */
25
+ function cweFromClasses(classes) {
26
+ if (!classes)
27
+ return '';
28
+ for (const c of classes) {
29
+ if ((c.source || '').toUpperCase() === 'CWE' && c.id) {
30
+ const m = /(\d+)/.exec(c.id);
31
+ if (m)
32
+ return `CWE-${parseInt(m[1], 10)}`;
33
+ }
34
+ }
35
+ return '';
36
+ }
37
+ /** First resolvable source location (file + line) in an issue. */
38
+ function locationFrom(coords) {
39
+ for (const c of coords || []) {
40
+ for (const r of c.representations || []) {
41
+ const file = r.sourceLocation?.file;
42
+ const line = r.sourceLocation?.region?.start?.line;
43
+ if (file && line)
44
+ return { file, line };
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+ /** Map one Snyk issue → `ExternalFinding`, or null when it has no
50
+ * usable source location (can't be fingerprinted/fixed). */
51
+ function snykIssueToFinding(issue) {
52
+ const a = issue.attributes;
53
+ if (!a)
54
+ return null;
55
+ const loc = locationFrom(a.coordinates);
56
+ if (!loc)
57
+ return null;
58
+ return {
59
+ engine: 'snyk-code',
60
+ severity: mapSeverity(a.effective_severity_level),
61
+ category: 'code',
62
+ cwe: cweFromClasses(a.classes),
63
+ rule: issue.id || a.title || 'snyk-code',
64
+ title: a.title || 'Snyk Code finding',
65
+ file: loc.file,
66
+ line: loc.line,
67
+ };
68
+ }
69
+ /**
70
+ * Fetch all Snyk Code findings for a project, following pagination.
71
+ * Pure-ish: the only side effect is the network read. Throws on auth /
72
+ * network failure so the CLI can surface a clear message; a successful
73
+ * call with zero issues returns `[]`.
74
+ */
75
+ async function fetchSnykCodeFindings(opts) {
76
+ const base = opts.apiBase || DEFAULT_API_BASE;
77
+ const version = opts.version || DEFAULT_VERSION;
78
+ const params = new URLSearchParams({
79
+ version,
80
+ type: 'code',
81
+ 'scan_item.type': 'project',
82
+ 'scan_item.id': opts.projectId,
83
+ limit: '100',
84
+ });
85
+ let url = `${base}/rest/orgs/${opts.orgId}/issues?${params.toString()}`;
86
+ const out = [];
87
+ let guard = 0;
88
+ while (url && guard < 1000) {
89
+ guard++;
90
+ const res = await fetch(url, {
91
+ headers: {
92
+ // Snyk REST API convention. If a live token rejects this,
93
+ // switch to `Bearer ${opts.token}` (see VALIDATION NOTE).
94
+ Authorization: `token ${opts.token}`,
95
+ Accept: 'application/vnd.api+json',
96
+ },
97
+ });
98
+ if (!res.ok) {
99
+ const body = await res.text().catch(() => '');
100
+ throw new Error(`Snyk API ${res.status} ${res.statusText}: ${body.slice(0, 200)}`);
101
+ }
102
+ const json = (await res.json());
103
+ for (const issue of json.data || []) {
104
+ const f = snykIssueToFinding(issue);
105
+ if (f)
106
+ out.push(f);
107
+ }
108
+ const next = json.links?.next;
109
+ // `next` is a relative REST path; resolve against the base.
110
+ url = next ? (next.startsWith('http') ? next : `${base}${next}`) : null;
111
+ }
112
+ return out;
113
+ }
114
+ //# sourceMappingURL=snyk-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snyk-api.js","sourceRoot":"","sources":["../../src/ingest/snyk-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ExternalFinding } from './types';
2
+ /** Env flag that opts the guarded `snyk` registry entry in. */
3
+ export declare const SNYK_OPTIN_ENV = "DXKIT_SNYK_CLI";
4
+ /** `snyk code test` argv (no shell). Org scopes the entitlement; omit
5
+ * to use the token's default org. */
6
+ export declare function snykCodeTestArgs(org: string | undefined, sarifPath: string): string[];
7
+ export interface RunSnykCodeOptions {
8
+ cwd: string;
9
+ /** Snyk org id — scopes which org's Code entitlement/quota is used. */
10
+ org?: string;
11
+ /** Snyk Code tests can take a few minutes; default 10 min. */
12
+ timeoutMs?: number;
13
+ onLog?: (msg: string) => void;
14
+ }
15
+ /**
16
+ * Run `snyk code test` and return normalized findings. Installs the
17
+ * Snyk CLI on demand if missing. Throws when no SARIF is produced (a
18
+ * real failure); a non-zero exit with a written SARIF (findings present,
19
+ * or the cosmetic platform-report 403) is treated as success.
20
+ */
21
+ export declare function runSnykCodeTest(opts: RunSnykCodeOptions): Promise<ExternalFinding[]>;
22
+ //# sourceMappingURL=snyk-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snyk-cli.d.ts","sourceRoot":"","sources":["../../src/ingest/snyk-cli.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,+DAA+D;AAC/D,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;sCACsC;AACtC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAIrF;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAID;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAmD1F"}
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SNYK_OPTIN_ENV = void 0;
37
+ exports.snykCodeTestArgs = snykCodeTestArgs;
38
+ exports.runSnykCodeTest = runSnykCodeTest;
39
+ /**
40
+ * Snyk Code (SAST) via the Snyk CLI — the free-tier path.
41
+ *
42
+ * Reading findings over the Snyk REST API needs Snyk's API-access
43
+ * entitlement, which is an Enterprise-tier feature. On Free/Team plans
44
+ * that read returns `403 … not entitled for api access`. But running a
45
+ * Snyk Code TEST via the CLI uses the Snyk Code *product* entitlement
46
+ * (which Free includes, with a per-period test quota), and writes the
47
+ * full results to a local SARIF file — which we then ingest through the
48
+ * same `parseSarif` path as every other engine.
49
+ *
50
+ * So this is the path most customers actually use. It costs one Snyk
51
+ * Code test per run (vs the quota-free API read on Enterprise).
52
+ *
53
+ * Detection + install go through the canonical registry (Rule 1): the
54
+ * runner opts into the guarded `snyk` entry, and installs it on demand
55
+ * (it's a small npm package) if missing. The CLI emits a non-fatal
56
+ * platform-reporting error on plans without API access, but still writes
57
+ * the SARIF — so we read the file regardless of exit code.
58
+ */
59
+ const child_process_1 = require("child_process");
60
+ const fs = __importStar(require("fs"));
61
+ const os = __importStar(require("os"));
62
+ const path = __importStar(require("path"));
63
+ const tool_registry_1 = require("../analyzers/tools/tool-registry");
64
+ const runner_1 = require("../analyzers/tools/runner");
65
+ const sarif_1 = require("./sarif");
66
+ /** Env flag that opts the guarded `snyk` registry entry in. */
67
+ exports.SNYK_OPTIN_ENV = 'DXKIT_SNYK_CLI';
68
+ /** `snyk code test` argv (no shell). Org scopes the entitlement; omit
69
+ * to use the token's default org. */
70
+ function snykCodeTestArgs(org, sarifPath) {
71
+ const args = ['code', 'test', `--sarif-file-output=${sarifPath}`];
72
+ if (org)
73
+ args.push(`--org=${org}`);
74
+ return args;
75
+ }
76
+ const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
77
+ /**
78
+ * Run `snyk code test` and return normalized findings. Installs the
79
+ * Snyk CLI on demand if missing. Throws when no SARIF is produced (a
80
+ * real failure); a non-zero exit with a written SARIF (findings present,
81
+ * or the cosmetic platform-report 403) is treated as success.
82
+ */
83
+ async function runSnykCodeTest(opts) {
84
+ process.env[exports.SNYK_OPTIN_ENV] = '1';
85
+ const log = opts.onLog ?? (() => { });
86
+ let status = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.snyk, opts.cwd);
87
+ if (!status.available || !status.path) {
88
+ log('Snyk CLI not found — installing it on demand…');
89
+ try {
90
+ (0, child_process_1.execSync)((0, tool_registry_1.getInstallCommand)(tool_registry_1.TOOL_DEFS.snyk), { stdio: 'ignore' });
91
+ }
92
+ catch {
93
+ /* fall through to the availability check below */
94
+ }
95
+ status = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.snyk, opts.cwd);
96
+ }
97
+ if (!status.available || !status.path) {
98
+ throw new Error('Snyk CLI is not available. Install it with `vyuh-dxkit tools install snyk`.');
99
+ }
100
+ const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dxkit-snyk-'));
101
+ const sarifPath = path.join(workDir, 'snyk-code.sarif');
102
+ try {
103
+ log('Running `snyk code test` (uses one Snyk Code test from your quota)…');
104
+ const outcome = await (0, runner_1.runDetached)(status.path, snykCodeTestArgs(opts.org, sarifPath), {
105
+ cwd: opts.cwd,
106
+ timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
107
+ });
108
+ let raw = '';
109
+ try {
110
+ raw = fs.readFileSync(sarifPath, 'utf-8');
111
+ }
112
+ catch {
113
+ raw = '';
114
+ }
115
+ if (!raw) {
116
+ // No SARIF means the test genuinely failed (auth, network, no Code
117
+ // entitlement) — surface the CLI's first stderr line.
118
+ const firstErr = outcome.stderr
119
+ .split('\n')
120
+ .map((l) => l.trim())
121
+ .find((l) => l.length > 0);
122
+ throw new Error(`Snyk CLI produced no SARIF (exit ${outcome.code})${firstErr ? `: ${firstErr}` : ''}`);
123
+ }
124
+ return (0, sarif_1.parseSarif)(raw, 'snyk-code');
125
+ }
126
+ finally {
127
+ try {
128
+ fs.rmSync(workDir, { recursive: true, force: true });
129
+ }
130
+ catch {
131
+ /* best-effort cleanup */
132
+ }
133
+ }
134
+ }
135
+ //# sourceMappingURL=snyk-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snyk-cli.js","sourceRoot":"","sources":["../../src/ingest/snyk-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * External-findings ingestion types.
3
+ *
4
+ * dxkit's own scanners (semgrep, gitleaks, osv-scanner, npm-audit) are
5
+ * intraprocedural / dependency-level. Interprocedural taint SAST —
6
+ * the class of finding a proprietary engine like Snyk Code or an
7
+ * interprocedural engine like CodeQL produces — lives outside dxkit's
8
+ * bundled toolchain. Rather than try to out-detect those engines,
9
+ * dxkit *ingests* their output and makes it first-class: fingerprinted
10
+ * (Rule 9), aggregated (Rule 8), baselined (Rule 10), graph-linked
11
+ * (Rule 12), and fixable through the agent loop.
12
+ *
13
+ * Every supported engine funnels into the SAME normalized shape
14
+ * (`ExternalFinding`) so the rest of the pipeline is engine-agnostic.
15
+ * Adding an engine is a new *producer* (a function that returns
16
+ * `ExternalFinding[]`); the normalize → aggregate → graph → fix path
17
+ * never grows an engine-specific branch.
18
+ */
19
+ import type { Severity, FindingCategory } from '../analyzers/security/types';
20
+ /**
21
+ * The engines dxkit can ingest from. Each is a *producer* of
22
+ * `ExternalFinding[]`:
23
+ *
24
+ * - `snyk-code` — Snyk Code (SAST), read from the Snyk REST API
25
+ * (quota-free; reads stored results) or a SARIF
26
+ * export from `snyk code test --sarif`.
27
+ * - `codeql` — CodeQL, run on-demand where licensing permits
28
+ * (OSS / GitHub Advanced Security), emitting SARIF.
29
+ * - `semgrep-pro` — Semgrep Pro engine (interprocedural), if a
30
+ * customer has it; SARIF.
31
+ * - `sarif` — a generic SARIF file from any other tool. The
32
+ * producer-of-last-resort; keeps dxkit open.
33
+ *
34
+ * The string also becomes the finding's `tool` provenance so reports
35
+ * and the aggregator can attribute each finding to its origin.
36
+ */
37
+ export type SourceEngine = 'snyk-code' | 'codeql' | 'semgrep-pro' | 'sarif';
38
+ /**
39
+ * One normalized finding from an external engine. Deliberately a
40
+ * superset-mappable shape: it carries exactly the fields the security
41
+ * aggregator's `SecurityFinding` needs, plus the provenance the report
42
+ * surfaces. Identity (`fingerprint`) is NOT computed here — it is
43
+ * assigned by the normalize layer through the canonical helpers so
44
+ * there is one fingerprint scheme across native + ingested findings
45
+ * (Rule 9).
46
+ */
47
+ export interface ExternalFinding {
48
+ /** Engine that produced this finding; becomes the `tool` field. */
49
+ engine: SourceEngine;
50
+ /** Four-tier severity, already mapped from the engine's vocabulary. */
51
+ severity: Severity;
52
+ /** `code` for SAST taint findings; `secret`/`config` reserved for
53
+ * engines that also emit those kinds. Dependency advisories are NOT
54
+ * ingested here — dxkit's own dep-vuln gather is at parity. */
55
+ category: FindingCategory;
56
+ /** CWE identifier (e.g. `CWE-23`), or `''` when the engine gives none. */
57
+ cwe: string;
58
+ /** Engine-native rule id (e.g. `javascript/path-injection`,
59
+ * `SNYK-JS-...`). Combined with `engine` to form the canonical rule. */
60
+ rule: string;
61
+ /** Human-readable one-line title. */
62
+ title: string;
63
+ /** Repo-relative source path. */
64
+ file: string;
65
+ /** 1-based line number of the primary location. */
66
+ line: number;
67
+ }
68
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ingest/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE7E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,aAAa,GAAG,OAAO,CAAC;AAE5E;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,MAAM,EAAE,YAAY,CAAC;IACrB,uEAAuE;IACvE,QAAQ,EAAE,QAAQ,CAAC;IACnB;;oEAEgE;IAChE,QAAQ,EAAE,eAAe,CAAC;IAC1B,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC;IACZ;6EACyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ingest/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ export interface IngestOptions {
2
+ sarif?: string;
3
+ fromSnyk?: boolean;
4
+ codeql?: boolean;
5
+ /** Force the `snyk code test` CLI path, skipping the REST attempt. The
6
+ * REST API is an Enterprise-only entitlement; free/team plans must use
7
+ * the CLI (which costs one Snyk Code test from the quota). */
8
+ snykCli?: boolean;
9
+ /** Override engine label for `--sarif` (else inferred from the file). */
10
+ engine?: string;
11
+ /** Snyk identifiers (CLI flags override config / env). */
12
+ org?: string;
13
+ project?: string;
14
+ generatedAt: string;
15
+ commitSha?: string;
16
+ }
17
+ export declare function runIngest(cwd: string, opts: IngestOptions): Promise<void>;
18
+ /** A REST failure that means "this plan can't read the API" — Enterprise-
19
+ * only entitlement. We fall back to the CLI (Snyk Code product) path. */
20
+ export declare function isNotEntitled(message: string): boolean;
21
+ //# sourceMappingURL=ingest-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-cli.d.ts","sourceRoot":"","sources":["../src/ingest-cli.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;mEAE+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB/E;AAmDD;0EAC0E;AAC1E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD"}
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runIngest = runIngest;
37
+ exports.isNotEntitled = isNotEntitled;
38
+ /**
39
+ * `vyuh-dxkit ingest` — bring an external SAST engine's findings into
40
+ * dxkit's pipeline.
41
+ *
42
+ * Two sources today:
43
+ * --sarif <file> parse a SARIF 2.1.0 file from ANY engine (CodeQL,
44
+ * Snyk Code export, Semgrep Pro, Bearer, …)
45
+ * --from-snyk read a project's Code findings from the Snyk REST
46
+ * API (quota-free) using SNYK_TOKEN + org/project.
47
+ * On plans without REST API access (Enterprise-only)
48
+ * this auto-falls-back to `snyk code test`; pass
49
+ * --snyk-cli to force that path and skip the REST try.
50
+ *
51
+ * Either way the result is written to `.dxkit/external/<engine>.json`,
52
+ * a committed snapshot every later scan reads — so the token is needed
53
+ * only by whoever runs `ingest` (ideally one CI refresh job), not by
54
+ * every developer.
55
+ */
56
+ const fs = __importStar(require("fs"));
57
+ const logger = __importStar(require("./logger"));
58
+ const sarif_1 = require("./ingest/sarif");
59
+ const snyk_api_1 = require("./ingest/snyk-api");
60
+ const snyk_cli_1 = require("./ingest/snyk-cli");
61
+ const codeql_1 = require("./ingest/codeql");
62
+ const config_1 = require("./ingest/config");
63
+ const snapshot_1 = require("./ingest/snapshot");
64
+ const index_1 = require("./languages/index");
65
+ function isSourceEngine(s) {
66
+ return s === 'snyk-code' || s === 'codeql' || s === 'semgrep-pro' || s === 'sarif';
67
+ }
68
+ async function runIngest(cwd, opts) {
69
+ if (opts.fromSnyk) {
70
+ await ingestFromSnyk(cwd, opts);
71
+ return;
72
+ }
73
+ if (opts.codeql) {
74
+ await ingestFromCodeql(cwd, opts);
75
+ return;
76
+ }
77
+ if (opts.sarif) {
78
+ ingestFromSarif(cwd, opts);
79
+ return;
80
+ }
81
+ logger.warn('Nothing to ingest. Pass --sarif <file>, --from-snyk, or --codeql.');
82
+ logger.dim(' Examples:');
83
+ logger.dim(' vyuh-dxkit ingest --sarif results.sarif');
84
+ logger.dim(' SNYK_TOKEN=… vyuh-dxkit ingest --from-snyk --org <id> --project <id>');
85
+ logger.dim(' SNYK_TOKEN=… vyuh-dxkit ingest --from-snyk --snyk-cli # free/team plans');
86
+ logger.dim(' vyuh-dxkit ingest --codeql # OSS / GitHub Advanced Security only');
87
+ process.exitCode = 1;
88
+ }
89
+ async function ingestFromCodeql(cwd, opts) {
90
+ // CodeQL languages come from the active packs' recipe (Rule 6), so a
91
+ // new pack auto-extends what gets scanned. JS+TS collapse to one
92
+ // `javascript` DB.
93
+ const targets = [];
94
+ const seen = new Set();
95
+ for (const pack of (0, index_1.detectActiveLanguages)(cwd)) {
96
+ const lang = pack.deepSast?.codeqlLanguage;
97
+ if (lang && !seen.has(lang)) {
98
+ seen.add(lang);
99
+ targets.push({ language: lang, querySuite: pack.deepSast?.codeqlQuerySuite });
100
+ }
101
+ }
102
+ if (targets.length === 0) {
103
+ logger.warn('No active language pack has a CodeQL extractor for this repo.');
104
+ process.exitCode = 1;
105
+ return;
106
+ }
107
+ logger.info(`Running CodeQL for: ${targets.map((t) => t.language).join(', ')} (this can take many minutes)…`);
108
+ let findings;
109
+ try {
110
+ findings = await (0, codeql_1.runCodeql)({ cwd, targets, onLog: (m) => logger.dim(` ${m}`) });
111
+ }
112
+ catch (err) {
113
+ logger.warn(`CodeQL run failed: ${err.message}`);
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+ writeAndReport(cwd, 'codeql', findings, opts);
118
+ }
119
+ function ingestFromSarif(cwd, opts) {
120
+ let raw;
121
+ try {
122
+ raw = fs.readFileSync(opts.sarif, 'utf-8');
123
+ }
124
+ catch (err) {
125
+ logger.warn(`Cannot read SARIF file ${opts.sarif}: ${err.message}`);
126
+ process.exitCode = 1;
127
+ return;
128
+ }
129
+ const engineOverride = isSourceEngine(opts.engine) ? opts.engine : undefined;
130
+ const findings = (0, sarif_1.parseSarif)(raw, engineOverride);
131
+ // All findings from one SARIF share an engine; use the first (or the
132
+ // override / generic `sarif`) as the snapshot's engine label.
133
+ const engine = engineOverride ?? findings[0]?.engine ?? 'sarif';
134
+ writeAndReport(cwd, engine, findings, opts);
135
+ }
136
+ /** A REST failure that means "this plan can't read the API" — Enterprise-
137
+ * only entitlement. We fall back to the CLI (Snyk Code product) path. */
138
+ function isNotEntitled(message) {
139
+ return /\b403\b/.test(message) || /not entitled/i.test(message) || /api access/i.test(message);
140
+ }
141
+ async function ingestFromSnyk(cwd, opts) {
142
+ const token = process.env.SNYK_TOKEN;
143
+ if (!token) {
144
+ logger.warn('SNYK_TOKEN is not set.');
145
+ logger.dim(' dxkit reads SNYK_TOKEN from the environment — it does NOT auto-load a .env file.');
146
+ logger.dim(' Export it (`export SNYK_TOKEN=…`) or add it as a CI secret, then retry.');
147
+ process.exitCode = 1;
148
+ return;
149
+ }
150
+ // Org/project resolve flag → persisted config (`.vyuh-dxkit.json:
151
+ // deepSast.snyk`) → environment, so a sourced shell or configured repo
152
+ // can run `ingest --from-snyk` with no flags. (dxkit does not read .env;
153
+ // export the vars or set CI secrets.)
154
+ const cfg = (0, config_1.readDeepSastConfig)(cwd);
155
+ const orgId = opts.org ?? cfg.snyk?.orgId ?? process.env.SNYK_ORG_ID;
156
+ const projectId = opts.project ?? cfg.snyk?.projectId ?? process.env.SNYK_PROJECT_ID;
157
+ // Forced CLI path (free/team plans): skip the REST attempt entirely. The
158
+ // CLI tests the local checkout, so it needs only the org (to scope the
159
+ // entitlement), not a project id.
160
+ if (opts.snykCli) {
161
+ await ingestViaSnykCli(cwd, opts, orgId);
162
+ return;
163
+ }
164
+ if (!orgId || !projectId) {
165
+ logger.warn('Snyk org + project are required to read findings via the REST API.');
166
+ logger.dim(' Pass --org <id> --project <id>, set them once in .vyuh-dxkit.json:');
167
+ logger.dim(' { "deepSast": { "snyk": { "orgId": "…", "projectId": "…" } } }');
168
+ logger.dim(' or export SNYK_ORG_ID / SNYK_PROJECT_ID in your environment.');
169
+ logger.dim(' Find them in the Snyk UI (Settings → Org ID; the project page URL → project ID).');
170
+ logger.dim(' On free/team plans (no REST API access) use --snyk-cli to run a Snyk Code test.');
171
+ process.exitCode = 1;
172
+ return;
173
+ }
174
+ logger.info('Reading Snyk Code findings via the REST API (no test quota consumed)…');
175
+ let findings;
176
+ try {
177
+ findings = await (0, snyk_api_1.fetchSnykCodeFindings)({
178
+ token,
179
+ orgId,
180
+ projectId,
181
+ apiBase: process.env.SNYK_API,
182
+ });
183
+ }
184
+ catch (err) {
185
+ const message = err.message;
186
+ // REST API access is an Enterprise feature; on other plans the read
187
+ // 403s. Fall back to `snyk code test` (Snyk Code product entitlement,
188
+ // which free includes) so one command works on every plan.
189
+ if (isNotEntitled(message)) {
190
+ logger.warn('Snyk REST API access is not available on this plan (an Enterprise feature).');
191
+ logger.dim(' Falling back to `snyk code test` (Snyk Code product, uses one test quota)…');
192
+ await ingestViaSnykCli(cwd, opts, orgId);
193
+ return;
194
+ }
195
+ logger.warn(`Snyk read failed: ${message}`);
196
+ process.exitCode = 1;
197
+ return;
198
+ }
199
+ writeAndReport(cwd, 'snyk-code', findings, opts);
200
+ }
201
+ /** Run `snyk code test` on the local checkout and snapshot the findings.
202
+ * Used both as the explicit `--snyk-cli` path and as the REST fallback. */
203
+ async function ingestViaSnykCli(cwd, opts, orgId) {
204
+ let findings;
205
+ try {
206
+ findings = await (0, snyk_cli_1.runSnykCodeTest)({ cwd, org: orgId, onLog: (m) => logger.dim(` ${m}`) });
207
+ }
208
+ catch (err) {
209
+ logger.warn(`Snyk Code test failed: ${err.message}`);
210
+ process.exitCode = 1;
211
+ return;
212
+ }
213
+ writeAndReport(cwd, 'snyk-code', findings, opts);
214
+ }
215
+ function writeAndReport(cwd, engine, findings, opts) {
216
+ const file = (0, snapshot_1.writeSnapshot)(cwd, {
217
+ schemaVersion: 1,
218
+ engine,
219
+ generatedAt: opts.generatedAt,
220
+ ...(opts.commitSha ? { commitSha: opts.commitSha } : {}),
221
+ findings,
222
+ });
223
+ const bySev = findings.reduce((acc, f) => {
224
+ acc[f.severity] = (acc[f.severity] || 0) + 1;
225
+ return acc;
226
+ }, {});
227
+ logger.success(`Ingested ${findings.length} ${engine} finding(s) → ${file}`);
228
+ logger.dim(` critical:${bySev.critical || 0} high:${bySev.high || 0} medium:${bySev.medium || 0} low:${bySev.low || 0}`);
229
+ logger.dim(' Commit .dxkit/external/ so every scan + CI run sees these without a token.');
230
+ logger.dim(' Next: `vyuh-dxkit vulnerabilities --graph-context` to see them graph-linked.');
231
+ }
232
+ //# sourceMappingURL=ingest-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-cli.js","sourceRoot":"","sources":["../src/ingest-cli.ts"],"names":[],"mappings":"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"}