@westbayberry/dg 1.0.33 → 1.0.34
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/index.mjs +158 -52
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -53,7 +53,7 @@ __export(auth_exports, {
|
|
|
53
53
|
import { readFileSync, writeFileSync, chmodSync, unlinkSync, existsSync } from "node:fs";
|
|
54
54
|
import { join } from "node:path";
|
|
55
55
|
import { homedir } from "node:os";
|
|
56
|
-
import {
|
|
56
|
+
import { spawn } from "node:child_process";
|
|
57
57
|
import { randomUUID } from "node:crypto";
|
|
58
58
|
async function createAuthSession() {
|
|
59
59
|
let res;
|
|
@@ -154,24 +154,35 @@ function getOrCreateDeviceId() {
|
|
|
154
154
|
return deviceId;
|
|
155
155
|
}
|
|
156
156
|
function openBrowser(url) {
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
try {
|
|
158
|
+
const parsed = new URL(url);
|
|
159
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return;
|
|
160
|
+
} catch {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
159
163
|
let cmd;
|
|
164
|
+
let args;
|
|
160
165
|
switch (process.platform) {
|
|
161
166
|
case "darwin":
|
|
162
|
-
cmd =
|
|
167
|
+
cmd = "open";
|
|
168
|
+
args = [url];
|
|
163
169
|
break;
|
|
164
170
|
case "linux":
|
|
165
|
-
cmd =
|
|
171
|
+
cmd = "xdg-open";
|
|
172
|
+
args = [url];
|
|
166
173
|
break;
|
|
167
174
|
case "win32":
|
|
168
|
-
cmd =
|
|
175
|
+
cmd = "cmd.exe";
|
|
176
|
+
args = ["/c", "start", "", url];
|
|
169
177
|
break;
|
|
170
178
|
default:
|
|
171
179
|
return;
|
|
172
180
|
}
|
|
173
|
-
|
|
174
|
-
|
|
181
|
+
try {
|
|
182
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
183
|
+
child.unref();
|
|
184
|
+
} catch {
|
|
185
|
+
}
|
|
175
186
|
}
|
|
176
187
|
var WEB_BASE, CONFIG_FILE;
|
|
177
188
|
var init_auth = __esm({
|
|
@@ -211,6 +222,22 @@ function loadDgrc() {
|
|
|
211
222
|
}
|
|
212
223
|
return {};
|
|
213
224
|
}
|
|
225
|
+
function validateApiUrl(url) {
|
|
226
|
+
try {
|
|
227
|
+
const parsed = new URL(url);
|
|
228
|
+
const isLocal = parsed.hostname === "localhost" || parsed.hostname.startsWith("127.");
|
|
229
|
+
if (parsed.protocol !== "https:" && !isLocal) {
|
|
230
|
+
process.stderr.write(`Error: API URL must use HTTPS (got ${parsed.protocol}). Use localhost for local testing.
|
|
231
|
+
`);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
return url;
|
|
235
|
+
} catch {
|
|
236
|
+
process.stderr.write(`Error: Invalid API URL: ${url}
|
|
237
|
+
`);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
214
241
|
function getVersion() {
|
|
215
242
|
try {
|
|
216
243
|
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -286,12 +313,14 @@ function parseConfig(argv) {
|
|
|
286
313
|
return {
|
|
287
314
|
apiKey,
|
|
288
315
|
deviceId,
|
|
289
|
-
apiUrl:
|
|
316
|
+
apiUrl: validateApiUrl(
|
|
317
|
+
values["api-url"] ?? process.env.DG_API_URL ?? dgrc.apiUrl ?? "https://api.westbayberry.com"
|
|
318
|
+
),
|
|
290
319
|
mode: modeRaw,
|
|
291
320
|
blockThreshold,
|
|
292
321
|
warnThreshold,
|
|
293
322
|
maxPackages,
|
|
294
|
-
allowlist: allowlistRaw ? allowlistRaw.split(",").map((s) => s.trim()).filter(Boolean) : dgrc.allowlist ?? [],
|
|
323
|
+
allowlist: (allowlistRaw ? allowlistRaw.split(",").map((s) => s.trim()).filter(Boolean) : dgrc.allowlist ?? []).map((s) => s.toLowerCase()),
|
|
295
324
|
json: values.json,
|
|
296
325
|
scanAll: values["scan-all"],
|
|
297
326
|
baseLockfile: values["base-lockfile"] ?? null,
|
|
@@ -370,7 +399,7 @@ var init_config = __esm({
|
|
|
370
399
|
});
|
|
371
400
|
|
|
372
401
|
// src/npm-wrapper.ts
|
|
373
|
-
import { spawn } from "node:child_process";
|
|
402
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
374
403
|
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
|
|
375
404
|
import { join as join3 } from "node:path";
|
|
376
405
|
function parseNpmArgs(args) {
|
|
@@ -451,7 +480,7 @@ function parsePackageSpec(spec) {
|
|
|
451
480
|
}
|
|
452
481
|
async function resolveVersion(spec) {
|
|
453
482
|
return new Promise((resolve) => {
|
|
454
|
-
const child =
|
|
483
|
+
const child = spawn2("npm", ["view", spec, "version"], {
|
|
455
484
|
stdio: ["pipe", "pipe", "pipe"]
|
|
456
485
|
});
|
|
457
486
|
let stdout = "";
|
|
@@ -509,7 +538,7 @@ async function resolvePackages(specs) {
|
|
|
509
538
|
}
|
|
510
539
|
function runNpm(args) {
|
|
511
540
|
return new Promise((resolve) => {
|
|
512
|
-
const child =
|
|
541
|
+
const child = spawn2("npm", args, {
|
|
513
542
|
stdio: "inherit",
|
|
514
543
|
shell: false
|
|
515
544
|
});
|
|
@@ -27588,9 +27617,9 @@ var init_ansi_styles = __esm({
|
|
|
27588
27617
|
|
|
27589
27618
|
// node_modules/wrap-ansi/index.js
|
|
27590
27619
|
function wrapAnsi(string, columns, options) {
|
|
27591
|
-
return String(string).normalize().replaceAll("\r\n", "\n").split("\n").map((line) =>
|
|
27620
|
+
return String(string).normalize().replaceAll("\r\n", "\n").split("\n").map((line) => exec(line, columns, options)).join("\n");
|
|
27592
27621
|
}
|
|
27593
|
-
var ESCAPES, END_CODE, ANSI_ESCAPE_BELL, ANSI_CSI, ANSI_OSC, ANSI_SGR_TERMINATOR, ANSI_ESCAPE_LINK, wrapAnsiCode, wrapAnsiHyperlink, wordLengths, wrapWord, stringVisibleTrimSpacesRight,
|
|
27622
|
+
var ESCAPES, END_CODE, ANSI_ESCAPE_BELL, ANSI_CSI, ANSI_OSC, ANSI_SGR_TERMINATOR, ANSI_ESCAPE_LINK, wrapAnsiCode, wrapAnsiHyperlink, wordLengths, wrapWord, stringVisibleTrimSpacesRight, exec;
|
|
27594
27623
|
var init_wrap_ansi = __esm({
|
|
27595
27624
|
"node_modules/wrap-ansi/index.js"() {
|
|
27596
27625
|
init_string_width();
|
|
@@ -27662,7 +27691,7 @@ var init_wrap_ansi = __esm({
|
|
|
27662
27691
|
}
|
|
27663
27692
|
return words.slice(0, last).join(" ") + words.slice(last).join("");
|
|
27664
27693
|
};
|
|
27665
|
-
|
|
27694
|
+
exec = (string, columns, options = {}) => {
|
|
27666
27695
|
if (options.trim !== false && string.trim() === "") {
|
|
27667
27696
|
return "";
|
|
27668
27697
|
}
|
|
@@ -30753,7 +30782,7 @@ var require_websocket = __commonJS({
|
|
|
30753
30782
|
var tls = __require("tls");
|
|
30754
30783
|
var { randomBytes, createHash } = __require("crypto");
|
|
30755
30784
|
var { Duplex, Readable } = __require("stream");
|
|
30756
|
-
var { URL } = __require("url");
|
|
30785
|
+
var { URL: URL2 } = __require("url");
|
|
30757
30786
|
var PerMessageDeflate = require_permessage_deflate();
|
|
30758
30787
|
var Receiver2 = require_receiver();
|
|
30759
30788
|
var Sender2 = require_sender();
|
|
@@ -31246,11 +31275,11 @@ var require_websocket = __commonJS({
|
|
|
31246
31275
|
);
|
|
31247
31276
|
}
|
|
31248
31277
|
let parsedUrl;
|
|
31249
|
-
if (address instanceof
|
|
31278
|
+
if (address instanceof URL2) {
|
|
31250
31279
|
parsedUrl = address;
|
|
31251
31280
|
} else {
|
|
31252
31281
|
try {
|
|
31253
|
-
parsedUrl = new
|
|
31282
|
+
parsedUrl = new URL2(address);
|
|
31254
31283
|
} catch (e) {
|
|
31255
31284
|
throw new SyntaxError(`Invalid URL: ${address}`);
|
|
31256
31285
|
}
|
|
@@ -31387,7 +31416,7 @@ var require_websocket = __commonJS({
|
|
|
31387
31416
|
req.abort();
|
|
31388
31417
|
let addr;
|
|
31389
31418
|
try {
|
|
31390
|
-
addr = new
|
|
31419
|
+
addr = new URL2(location, address);
|
|
31391
31420
|
} catch (e) {
|
|
31392
31421
|
const err = new SyntaxError(`Invalid URL: ${location}`);
|
|
31393
31422
|
emitErrorAndClose(websocket, err);
|
|
@@ -38919,6 +38948,38 @@ var init_LoginApp = __esm({
|
|
|
38919
38948
|
}
|
|
38920
38949
|
});
|
|
38921
38950
|
|
|
38951
|
+
// src/sanitize.ts
|
|
38952
|
+
import { stripVTControlCharacters } from "node:util";
|
|
38953
|
+
function sanitize(s) {
|
|
38954
|
+
return stripVTControlCharacters(s);
|
|
38955
|
+
}
|
|
38956
|
+
function sanitizeResponse(response) {
|
|
38957
|
+
return {
|
|
38958
|
+
...response,
|
|
38959
|
+
packages: response.packages.map((pkg) => ({
|
|
38960
|
+
...pkg,
|
|
38961
|
+
name: sanitize(pkg.name),
|
|
38962
|
+
version: sanitize(pkg.version),
|
|
38963
|
+
findings: pkg.findings.map((f) => ({
|
|
38964
|
+
...f,
|
|
38965
|
+
id: sanitize(f.id ?? ""),
|
|
38966
|
+
title: sanitize(f.title),
|
|
38967
|
+
evidence: f.evidence.map(sanitize)
|
|
38968
|
+
})),
|
|
38969
|
+
reasons: (pkg.reasons ?? []).map(sanitize),
|
|
38970
|
+
recommendation: pkg.recommendation ? sanitize(pkg.recommendation) : void 0
|
|
38971
|
+
})),
|
|
38972
|
+
safeVersions: Object.fromEntries(
|
|
38973
|
+
Object.entries(response.safeVersions).map(([k, v]) => [sanitize(k), sanitize(v)])
|
|
38974
|
+
)
|
|
38975
|
+
};
|
|
38976
|
+
}
|
|
38977
|
+
var init_sanitize = __esm({
|
|
38978
|
+
"src/sanitize.ts"() {
|
|
38979
|
+
"use strict";
|
|
38980
|
+
}
|
|
38981
|
+
});
|
|
38982
|
+
|
|
38922
38983
|
// src/api.ts
|
|
38923
38984
|
function buildHeaders(config) {
|
|
38924
38985
|
const headers = {
|
|
@@ -39065,7 +39126,11 @@ async function callAnalyzeBatch(packages, config) {
|
|
|
39065
39126
|
body
|
|
39066
39127
|
);
|
|
39067
39128
|
}
|
|
39068
|
-
|
|
39129
|
+
const raw = await response.json();
|
|
39130
|
+
if (!raw || typeof raw.score !== "number" || !Array.isArray(raw.packages)) {
|
|
39131
|
+
throw new APIError("Invalid API response format", 0, "");
|
|
39132
|
+
}
|
|
39133
|
+
return sanitizeResponse(raw);
|
|
39069
39134
|
}
|
|
39070
39135
|
async function callPyPIAnalyzeAPI(packages, config, onProgress) {
|
|
39071
39136
|
const batchSize = config.apiKey ? BATCH_SIZE : ANON_BATCH_SIZE;
|
|
@@ -39139,12 +39204,17 @@ async function callPyPIBatch(packages, config) {
|
|
|
39139
39204
|
const body = await response.text();
|
|
39140
39205
|
throw new APIError(`API returned ${response.status}: ${body}`, response.status, body);
|
|
39141
39206
|
}
|
|
39142
|
-
|
|
39207
|
+
const raw = await response.json();
|
|
39208
|
+
if (!raw || typeof raw.score !== "number" || !Array.isArray(raw.packages)) {
|
|
39209
|
+
throw new APIError("Invalid API response format", 0, "");
|
|
39210
|
+
}
|
|
39211
|
+
return sanitizeResponse(raw);
|
|
39143
39212
|
}
|
|
39144
39213
|
var APIError, TrialExhaustedError, BATCH_SIZE, ANON_BATCH_SIZE, MAX_RETRIES, RETRY_DELAY_MS;
|
|
39145
39214
|
var init_api = __esm({
|
|
39146
39215
|
"src/api.ts"() {
|
|
39147
39216
|
"use strict";
|
|
39217
|
+
init_sanitize();
|
|
39148
39218
|
APIError = class extends Error {
|
|
39149
39219
|
constructor(message, statusCode, body) {
|
|
39150
39220
|
super(message);
|
|
@@ -39183,7 +39253,9 @@ function parseLockfile(content) {
|
|
|
39183
39253
|
version: e.version ?? "",
|
|
39184
39254
|
resolved: e.resolved,
|
|
39185
39255
|
integrity: e.integrity,
|
|
39186
|
-
dev: e.dev
|
|
39256
|
+
dev: e.dev,
|
|
39257
|
+
optional: e.optional,
|
|
39258
|
+
hasPlatformRestriction: !!(e.os || e.cpu)
|
|
39187
39259
|
});
|
|
39188
39260
|
}
|
|
39189
39261
|
}
|
|
@@ -39405,9 +39477,16 @@ var init_parse_package_json = __esm({
|
|
|
39405
39477
|
});
|
|
39406
39478
|
|
|
39407
39479
|
// src/lockfile.ts
|
|
39408
|
-
import { execFileSync } from "node:child_process";
|
|
39409
|
-
import { readFileSync as readFileSync6, existsSync as existsSync5 } from "node:fs";
|
|
39480
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
39481
|
+
import { readFileSync as readFileSync6, existsSync as existsSync5, statSync } from "node:fs";
|
|
39410
39482
|
import { join as join5 } from "node:path";
|
|
39483
|
+
function readFileSafe(path) {
|
|
39484
|
+
const size = statSync(path).size;
|
|
39485
|
+
if (size > MAX_LOCKFILE_BYTES) {
|
|
39486
|
+
throw new Error(`Lockfile too large (${(size / 1024 / 1024).toFixed(0)} MB, max 50 MB): ${path}`);
|
|
39487
|
+
}
|
|
39488
|
+
return readFileSync6(path, "utf-8");
|
|
39489
|
+
}
|
|
39411
39490
|
function discoverChanges(cwd2, config) {
|
|
39412
39491
|
if (config.workspace) {
|
|
39413
39492
|
cwd2 = join5(cwd2, config.workspace);
|
|
@@ -39418,13 +39497,14 @@ function discoverChanges(cwd2, config) {
|
|
|
39418
39497
|
"No lockfile found (package-lock.json, yarn.lock, or pnpm-lock.yaml). Run from your project root or use --base-lockfile."
|
|
39419
39498
|
);
|
|
39420
39499
|
}
|
|
39421
|
-
const headContent =
|
|
39500
|
+
const headContent = readFileSafe(lockfileInfo.path);
|
|
39422
39501
|
const headParsed = parseLockfileByType(headContent, lockfileInfo.type);
|
|
39423
39502
|
const directDeps = getDirectDeps(cwd2);
|
|
39424
39503
|
if (config.scanAll) {
|
|
39425
39504
|
const packages2 = [];
|
|
39426
39505
|
for (const [name, entry] of headParsed.packages) {
|
|
39427
39506
|
if (packages2.length >= config.maxPackages) break;
|
|
39507
|
+
if (entry.optional && entry.hasPlatformRestriction) continue;
|
|
39428
39508
|
packages2.push({
|
|
39429
39509
|
name,
|
|
39430
39510
|
version: entry.version,
|
|
@@ -39438,7 +39518,7 @@ function discoverChanges(cwd2, config) {
|
|
|
39438
39518
|
if (!existsSync5(config.baseLockfile)) {
|
|
39439
39519
|
throw new Error(`Base lockfile not found: ${config.baseLockfile}`);
|
|
39440
39520
|
}
|
|
39441
|
-
const baseContent2 =
|
|
39521
|
+
const baseContent2 = readFileSafe(config.baseLockfile);
|
|
39442
39522
|
const baseParsed = parseLockfile(baseContent2);
|
|
39443
39523
|
const diff2 = diffLockfiles(baseParsed, headParsed, config.maxPackages, directDeps);
|
|
39444
39524
|
return {
|
|
@@ -39459,7 +39539,7 @@ function discoverChanges(cwd2, config) {
|
|
|
39459
39539
|
}
|
|
39460
39540
|
const pkgJsonPath = join5(cwd2, "package.json");
|
|
39461
39541
|
if (existsSync5(pkgJsonPath)) {
|
|
39462
|
-
const headPkgJson =
|
|
39542
|
+
const headPkgJson = readFileSafe(pkgJsonPath);
|
|
39463
39543
|
const basePkgJson = getGitBaseFile(cwd2, "package.json");
|
|
39464
39544
|
if (basePkgJson !== null) {
|
|
39465
39545
|
const diff2 = diffPackageJsons(basePkgJson, headPkgJson, config.maxPackages);
|
|
@@ -39480,6 +39560,7 @@ function discoverChanges(cwd2, config) {
|
|
|
39480
39560
|
const packages = [];
|
|
39481
39561
|
for (const [name, entry] of headParsed.packages) {
|
|
39482
39562
|
if (packages.length >= config.maxPackages) break;
|
|
39563
|
+
if (entry.optional && entry.hasPlatformRestriction) continue;
|
|
39483
39564
|
packages.push({
|
|
39484
39565
|
name,
|
|
39485
39566
|
version: entry.version,
|
|
@@ -39514,7 +39595,7 @@ function parseLockfileByType(content, type) {
|
|
|
39514
39595
|
}
|
|
39515
39596
|
function getDirectDeps(cwd2) {
|
|
39516
39597
|
try {
|
|
39517
|
-
const content =
|
|
39598
|
+
const content = readFileSafe(join5(cwd2, "package.json"));
|
|
39518
39599
|
const pkg = JSON.parse(content);
|
|
39519
39600
|
return /* @__PURE__ */ new Set([
|
|
39520
39601
|
...Object.keys(pkg.dependencies ?? {}),
|
|
@@ -39526,7 +39607,7 @@ function getDirectDeps(cwd2) {
|
|
|
39526
39607
|
}
|
|
39527
39608
|
function getGitBaseLockfile(cwd2) {
|
|
39528
39609
|
try {
|
|
39529
|
-
const mergeBase =
|
|
39610
|
+
const mergeBase = execFileSync2("git", ["merge-base", "HEAD", "main"], {
|
|
39530
39611
|
cwd: cwd2,
|
|
39531
39612
|
encoding: "utf-8",
|
|
39532
39613
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -39534,7 +39615,7 @@ function getGitBaseLockfile(cwd2) {
|
|
|
39534
39615
|
if (!mergeBase) return null;
|
|
39535
39616
|
for (const name of ["package-lock.json", "yarn.lock", "pnpm-lock.yaml"]) {
|
|
39536
39617
|
try {
|
|
39537
|
-
return
|
|
39618
|
+
return execFileSync2("git", ["show", `${mergeBase}:${name}`], {
|
|
39538
39619
|
cwd: cwd2,
|
|
39539
39620
|
encoding: "utf-8",
|
|
39540
39621
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -39550,13 +39631,13 @@ function getGitBaseLockfile(cwd2) {
|
|
|
39550
39631
|
}
|
|
39551
39632
|
function getGitBaseFile(cwd2, filename) {
|
|
39552
39633
|
try {
|
|
39553
|
-
const mergeBase =
|
|
39634
|
+
const mergeBase = execFileSync2("git", ["merge-base", "HEAD", "main"], {
|
|
39554
39635
|
cwd: cwd2,
|
|
39555
39636
|
encoding: "utf-8",
|
|
39556
39637
|
stdio: ["pipe", "pipe", "pipe"]
|
|
39557
39638
|
}).trim();
|
|
39558
39639
|
if (!mergeBase) return null;
|
|
39559
|
-
return
|
|
39640
|
+
return execFileSync2("git", ["show", `${mergeBase}:${filename}`], {
|
|
39560
39641
|
cwd: cwd2,
|
|
39561
39642
|
encoding: "utf-8",
|
|
39562
39643
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -39574,7 +39655,7 @@ function toPackageInput(change) {
|
|
|
39574
39655
|
};
|
|
39575
39656
|
}
|
|
39576
39657
|
function parsePythonDepFile(projectDir, depFile) {
|
|
39577
|
-
const content =
|
|
39658
|
+
const content = readFileSafe(join5(projectDir, depFile));
|
|
39578
39659
|
if (depFile === "Pipfile.lock") {
|
|
39579
39660
|
try {
|
|
39580
39661
|
const parsed = JSON.parse(content);
|
|
@@ -39622,6 +39703,7 @@ function parsePythonDepFile(projectDir, depFile) {
|
|
|
39622
39703
|
}
|
|
39623
39704
|
return packages;
|
|
39624
39705
|
}
|
|
39706
|
+
var MAX_LOCKFILE_BYTES;
|
|
39625
39707
|
var init_lockfile = __esm({
|
|
39626
39708
|
"src/lockfile.ts"() {
|
|
39627
39709
|
"use strict";
|
|
@@ -39630,6 +39712,7 @@ var init_lockfile = __esm({
|
|
|
39630
39712
|
init_parse_pnpm_lock();
|
|
39631
39713
|
init_diff2();
|
|
39632
39714
|
init_parse_package_json();
|
|
39715
|
+
MAX_LOCKFILE_BYTES = 50 * 1024 * 1024;
|
|
39633
39716
|
}
|
|
39634
39717
|
});
|
|
39635
39718
|
|
|
@@ -39638,7 +39721,7 @@ var discover_exports = {};
|
|
|
39638
39721
|
__export(discover_exports, {
|
|
39639
39722
|
discoverProjects: () => discoverProjects
|
|
39640
39723
|
});
|
|
39641
|
-
import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync,
|
|
39724
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync, lstatSync } from "node:fs";
|
|
39642
39725
|
import { join as join6, relative, basename } from "node:path";
|
|
39643
39726
|
function discoverProjects(root) {
|
|
39644
39727
|
const projects = [];
|
|
@@ -39689,7 +39772,8 @@ function walk(dir, root, depth, out) {
|
|
|
39689
39772
|
if (SKIP_DIRS.has(entry) || entry.startsWith(".")) continue;
|
|
39690
39773
|
const full = join6(dir, entry);
|
|
39691
39774
|
try {
|
|
39692
|
-
|
|
39775
|
+
const st = lstatSync(full);
|
|
39776
|
+
if (st.isDirectory() && !st.isSymbolicLink()) {
|
|
39693
39777
|
walk(full, root, depth + 1, out);
|
|
39694
39778
|
}
|
|
39695
39779
|
} catch {
|
|
@@ -39980,7 +40064,7 @@ async function runStatic(config) {
|
|
|
39980
40064
|
process.exit(0);
|
|
39981
40065
|
}
|
|
39982
40066
|
const packages = discovery.packages.filter(
|
|
39983
|
-
(p) => !config.allowlist.includes(p.name)
|
|
40067
|
+
(p) => !config.allowlist.includes(p.name.toLowerCase())
|
|
39984
40068
|
);
|
|
39985
40069
|
if (packages.length === 0) {
|
|
39986
40070
|
process.stderr.write(
|
|
@@ -40088,7 +40172,7 @@ async function runStaticNpm(npmArgs, config) {
|
|
|
40088
40172
|
return scanAndInstallStatic(resolved, parsed, config);
|
|
40089
40173
|
}
|
|
40090
40174
|
async function scanAndInstallStatic(resolved, parsed, config) {
|
|
40091
|
-
const toScan = resolved.filter((p) => !config.allowlist.includes(p.name));
|
|
40175
|
+
const toScan = resolved.filter((p) => !config.allowlist.includes(p.name.toLowerCase()));
|
|
40092
40176
|
if (toScan.length === 0) {
|
|
40093
40177
|
process.stderr.write(
|
|
40094
40178
|
import_chalk4.default.dim(" All packages are allowlisted. Passing through to npm.\n")
|
|
@@ -40271,7 +40355,7 @@ var hook_exports = {};
|
|
|
40271
40355
|
__export(hook_exports, {
|
|
40272
40356
|
handleHookCommand: () => handleHookCommand
|
|
40273
40357
|
});
|
|
40274
|
-
import { execFileSync as
|
|
40358
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
40275
40359
|
import {
|
|
40276
40360
|
existsSync as existsSync7,
|
|
40277
40361
|
readFileSync as readFileSync8,
|
|
@@ -40283,7 +40367,7 @@ import {
|
|
|
40283
40367
|
import { join as join7 } from "node:path";
|
|
40284
40368
|
function findGitDir() {
|
|
40285
40369
|
try {
|
|
40286
|
-
return
|
|
40370
|
+
return execFileSync3("git", ["rev-parse", "--git-dir"], {
|
|
40287
40371
|
encoding: "utf-8",
|
|
40288
40372
|
stdio: ["pipe", "pipe", "pipe"]
|
|
40289
40373
|
}).trim();
|
|
@@ -40518,7 +40602,7 @@ function useNpmWrapper(npmArgs, config) {
|
|
|
40518
40602
|
return;
|
|
40519
40603
|
}
|
|
40520
40604
|
const toScan = resolved.filter(
|
|
40521
|
-
(p) => !config.allowlist.includes(p.name)
|
|
40605
|
+
(p) => !config.allowlist.includes(p.name.toLowerCase())
|
|
40522
40606
|
);
|
|
40523
40607
|
if (toScan.length === 0) {
|
|
40524
40608
|
dispatch({ type: "INSTALLING" });
|
|
@@ -40728,6 +40812,7 @@ var init_ScoreHeader = __esm({
|
|
|
40728
40812
|
severityCounts
|
|
40729
40813
|
}) => {
|
|
40730
40814
|
const logo = renderLogo(action);
|
|
40815
|
+
const showLogo = (process.stdout.columns ?? 80) >= 60;
|
|
40731
40816
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
40732
40817
|
Box_default,
|
|
40733
40818
|
{
|
|
@@ -40767,7 +40852,7 @@ var init_ScoreHeader = __esm({
|
|
|
40767
40852
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: `\x1B]8;;https://westbayberry.com\x07westbayberry.com\x1B]8;;\x07` })
|
|
40768
40853
|
] })
|
|
40769
40854
|
] }),
|
|
40770
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexDirection: "column", marginLeft: 2, children: logo.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: line }, i)) })
|
|
40855
|
+
showLogo && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexDirection: "column", marginLeft: 2, children: logo.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: line }, i)) })
|
|
40771
40856
|
] })
|
|
40772
40857
|
}
|
|
40773
40858
|
);
|
|
@@ -41002,6 +41087,7 @@ var init_ErrorView = __esm({
|
|
|
41002
41087
|
"use strict";
|
|
41003
41088
|
await init_build2();
|
|
41004
41089
|
import_chalk8 = __toESM(require_source());
|
|
41090
|
+
init_sanitize();
|
|
41005
41091
|
import_jsx_runtime7 = __toESM(require_jsx_runtime());
|
|
41006
41092
|
ErrorView = ({ error }) => {
|
|
41007
41093
|
const hint = getHint(error);
|
|
@@ -41015,7 +41101,7 @@ var init_ErrorView = __esm({
|
|
|
41015
41101
|
paddingRight: 1,
|
|
41016
41102
|
children: [
|
|
41017
41103
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: import_chalk8.default.red.bold("\u2718 Error") }),
|
|
41018
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: error.message }),
|
|
41104
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: sanitize(error.message) }),
|
|
41019
41105
|
hint && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
|
|
41020
41106
|
import_chalk8.default.yellow("\u2192"),
|
|
41021
41107
|
" ",
|
|
@@ -41211,7 +41297,7 @@ function useScan(config) {
|
|
|
41211
41297
|
}
|
|
41212
41298
|
try {
|
|
41213
41299
|
const discovery = discoverChanges(process.cwd(), config);
|
|
41214
|
-
const packages = discovery.packages.filter((p) => !config.allowlist.includes(p.name));
|
|
41300
|
+
const packages = discovery.packages.filter((p) => !config.allowlist.includes(p.name.toLowerCase()));
|
|
41215
41301
|
if (packages.length === 0) {
|
|
41216
41302
|
const message = discovery.packages.length === 0 ? "No package changes detected." : "All changed packages are allowlisted.";
|
|
41217
41303
|
dispatch({ type: "DISCOVERY_EMPTY", message });
|
|
@@ -41273,7 +41359,7 @@ async function scanProjects(projects, config, dispatch) {
|
|
|
41273
41359
|
const discovery = discoverChanges(proj.path, fullScanConfig);
|
|
41274
41360
|
for (const pkg of discovery.packages) {
|
|
41275
41361
|
const key = `${pkg.name}@${pkg.version}`;
|
|
41276
|
-
if (!config.allowlist.includes(pkg.name) && !seenNpm.has(key)) {
|
|
41362
|
+
if (!config.allowlist.includes(pkg.name.toLowerCase()) && !seenNpm.has(key)) {
|
|
41277
41363
|
seenNpm.add(key);
|
|
41278
41364
|
npmPackages.push(pkg);
|
|
41279
41365
|
}
|
|
@@ -41286,7 +41372,7 @@ async function scanProjects(projects, config, dispatch) {
|
|
|
41286
41372
|
const packages = parsePythonDepFile(proj.path, proj.depFile);
|
|
41287
41373
|
for (const pkg of packages) {
|
|
41288
41374
|
const key = `${pkg.name}@${pkg.version}`;
|
|
41289
|
-
if (!config.allowlist.includes(pkg.name) && !seenPypi.has(key)) {
|
|
41375
|
+
if (!config.allowlist.includes(pkg.name.toLowerCase()) && !seenPypi.has(key)) {
|
|
41290
41376
|
seenPypi.add(key);
|
|
41291
41377
|
pypiPackages.push(pkg);
|
|
41292
41378
|
}
|
|
@@ -41858,6 +41944,15 @@ var init_InteractiveResultsView = __esm({
|
|
|
41858
41944
|
const newVp = adjustViewport(cursor, expandedIndex, expandLevel, clamped);
|
|
41859
41945
|
dispatchView({ type: "MOVE", cursor, viewport: newVp });
|
|
41860
41946
|
}, [availableRows]);
|
|
41947
|
+
(0, import_react31.useEffect)(() => {
|
|
41948
|
+
const dp = detailPaneRef.current;
|
|
41949
|
+
if (dp && detailLines.length > 0) {
|
|
41950
|
+
const maxScroll = Math.max(0, detailLines.length - detailContentRows);
|
|
41951
|
+
if (dp.scroll > maxScroll) {
|
|
41952
|
+
setDetailPane({ groupIndex: dp.groupIndex, scroll: maxScroll });
|
|
41953
|
+
}
|
|
41954
|
+
}
|
|
41955
|
+
}, [detailContentRows, detailLines.length]);
|
|
41861
41956
|
use_input_default((input, key) => {
|
|
41862
41957
|
if (groups.length === 0) {
|
|
41863
41958
|
if (input === "q" || key.return) onExit();
|
|
@@ -41906,6 +42001,11 @@ var init_InteractiveResultsView = __esm({
|
|
|
41906
42001
|
}
|
|
41907
42002
|
return;
|
|
41908
42003
|
}
|
|
42004
|
+
if (groups.length === 0) {
|
|
42005
|
+
if (input === "q") onExit();
|
|
42006
|
+
else if (input === "/") setSearchMode(true);
|
|
42007
|
+
return;
|
|
42008
|
+
}
|
|
41909
42009
|
const { cursor, expandLevel: expLvl, expandedIndex: expIdx, viewport: vpStart } = viewRef.current;
|
|
41910
42010
|
if (key.upArrow || input === "k") {
|
|
41911
42011
|
const next = Math.max(0, cursor - 1);
|
|
@@ -41956,6 +42056,7 @@ var init_InteractiveResultsView = __esm({
|
|
|
41956
42056
|
const aboveCount = view.viewport;
|
|
41957
42057
|
const belowCount = groups.length - visibleEnd;
|
|
41958
42058
|
const nameCol = Math.max(20, innerWidth - 22);
|
|
42059
|
+
const clampedCursor = groups.length > 0 ? Math.min(view.cursor, groups.length - 1) : 0;
|
|
41959
42060
|
if (showHelp) {
|
|
41960
42061
|
const isDetail = detailPane !== null;
|
|
41961
42062
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
@@ -42194,7 +42295,7 @@ var init_InteractiveResultsView = __esm({
|
|
|
42194
42295
|
children: [
|
|
42195
42296
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { justifyContent: "space-between", children: [
|
|
42196
42297
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { bold: true, children: "Flagged Packages" }),
|
|
42197
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: searchQuery ? `${groups.length} of ${allGroupCount}` : `${
|
|
42298
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: searchQuery ? `${groups.length} of ${allGroupCount}` : `${clampedCursor + 1}/${groups.length}` })
|
|
42198
42299
|
] }),
|
|
42199
42300
|
aboveCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
|
|
42200
42301
|
import_chalk10.default.cyan(" \u2191"),
|
|
@@ -42204,7 +42305,7 @@ var init_InteractiveResultsView = __esm({
|
|
|
42204
42305
|
] }),
|
|
42205
42306
|
visibleGroups.map((group, visIdx) => {
|
|
42206
42307
|
const globalIdx = view.viewport + visIdx;
|
|
42207
|
-
const isCursor = globalIdx ===
|
|
42308
|
+
const isCursor = globalIdx === clampedCursor;
|
|
42208
42309
|
const level = getLevel(globalIdx);
|
|
42209
42310
|
const rep = group.packages[0];
|
|
42210
42311
|
const { label, color } = actionBadge3(rep.score, config);
|
|
@@ -42406,6 +42507,7 @@ var init_ProjectSelector = __esm({
|
|
|
42406
42507
|
import_react32 = __toESM(require_react());
|
|
42407
42508
|
await init_build2();
|
|
42408
42509
|
import_chalk11 = __toESM(require_source());
|
|
42510
|
+
init_sanitize();
|
|
42409
42511
|
import_jsx_runtime11 = __toESM(require_jsx_runtime());
|
|
42410
42512
|
ProjectSelector = ({ projects, onConfirm, onCancel }) => {
|
|
42411
42513
|
const [cursor, setCursor] = (0, import_react32.useState)(0);
|
|
@@ -42458,7 +42560,7 @@ var init_ProjectSelector = __esm({
|
|
|
42458
42560
|
prefix,
|
|
42459
42561
|
check,
|
|
42460
42562
|
" ",
|
|
42461
|
-
proj.relativePath.padEnd(40),
|
|
42563
|
+
sanitize(proj.relativePath).padEnd(40),
|
|
42462
42564
|
" ",
|
|
42463
42565
|
ecosystemLabel(proj.ecosystem).padEnd(5),
|
|
42464
42566
|
" ",
|
|
@@ -42656,7 +42758,7 @@ init_npm_wrapper();
|
|
|
42656
42758
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
42657
42759
|
import { homedir as homedir3 } from "node:os";
|
|
42658
42760
|
import { join as join4 } from "node:path";
|
|
42659
|
-
import { spawn as
|
|
42761
|
+
import { spawn as spawn3, execFileSync } from "node:child_process";
|
|
42660
42762
|
var PKG_NAME = "@westbayberry/dg";
|
|
42661
42763
|
var CACHE_FILE = join4(homedir3(), ".dg-update-check.json");
|
|
42662
42764
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -42709,7 +42811,7 @@ function isNewer(latest, current) {
|
|
|
42709
42811
|
}
|
|
42710
42812
|
function spawnBackgroundUpdate(version) {
|
|
42711
42813
|
try {
|
|
42712
|
-
const child =
|
|
42814
|
+
const child = spawn3("npm", ["install", "-g", `${PKG_NAME}@${version}`], {
|
|
42713
42815
|
detached: true,
|
|
42714
42816
|
stdio: "ignore"
|
|
42715
42817
|
});
|
|
@@ -42755,7 +42857,7 @@ async function runUpdate(currentVersion) {
|
|
|
42755
42857
|
process.stderr.write(chalk10.dim(` Installing ${PKG_NAME}@${latest}...
|
|
42756
42858
|
`));
|
|
42757
42859
|
try {
|
|
42758
|
-
|
|
42860
|
+
execFileSync("npm", ["install", "-g", `${PKG_NAME}@${latest}`], { stdio: "inherit" });
|
|
42759
42861
|
writeCache({ latest, checkedAt: Date.now() });
|
|
42760
42862
|
process.stderr.write(
|
|
42761
42863
|
chalk10.green(`
|
|
@@ -42774,6 +42876,10 @@ async function runUpdate(currentVersion) {
|
|
|
42774
42876
|
|
|
42775
42877
|
// src/bin.ts
|
|
42776
42878
|
var CLI_VERSION = getVersion();
|
|
42879
|
+
process.on("SIGINT", () => {
|
|
42880
|
+
process.stderr.write("\n");
|
|
42881
|
+
process.exit(130);
|
|
42882
|
+
});
|
|
42777
42883
|
var isInteractive = process.stdout.isTTY === true && !process.env.CI && !process.env.NO_COLOR;
|
|
42778
42884
|
async function main() {
|
|
42779
42885
|
const rawCommand = process.argv[2];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@westbayberry/dg",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.34",
|
|
4
4
|
"description": "Supply chain security scanner for npm and Python dependencies — detects malicious packages, typosquatting, dependency confusion, and 26+ attack patterns",
|
|
5
5
|
"bin": {
|
|
6
6
|
"dependency-guardian": "dist/index.mjs",
|