securewithtrace 0.20.0 → 0.20.2
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.js +279 -101
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24235,6 +24235,14 @@ var ScanTriggerTypeValues = [
|
|
|
24235
24235
|
var ScanTriggerType = external_exports.enum(ScanTriggerTypeValues);
|
|
24236
24236
|
|
|
24237
24237
|
// ../../packages/api-contracts/src/schemas/api/v1/scan.api.ts
|
|
24238
|
+
var ScanProviderValues = ["bedrock"];
|
|
24239
|
+
var ScanConfigurationSchema = external_exports.object({
|
|
24240
|
+
/**
|
|
24241
|
+
* Override the LLM provider used for this scan.
|
|
24242
|
+
* Staff-only — must be enforced server-side.
|
|
24243
|
+
*/
|
|
24244
|
+
provider: external_exports.enum(ScanProviderValues).optional()
|
|
24245
|
+
}).strict();
|
|
24238
24246
|
var ScanIdParamsSchema = OrgIdParamsSchema.extend({
|
|
24239
24247
|
scanId: external_exports.uuid()
|
|
24240
24248
|
});
|
|
@@ -24244,7 +24252,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24244
24252
|
webApplicationId: external_exports.uuid(),
|
|
24245
24253
|
targetUrl: external_exports.url(),
|
|
24246
24254
|
userProvidedContext: external_exports.string().optional(),
|
|
24247
|
-
scanConfiguration:
|
|
24255
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24248
24256
|
}),
|
|
24249
24257
|
external_exports.object({
|
|
24250
24258
|
scanMode: external_exports.literal("SAST"),
|
|
@@ -24252,7 +24260,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24252
24260
|
branch: external_exports.string().optional(),
|
|
24253
24261
|
scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
|
|
24254
24262
|
userProvidedContext: external_exports.string().optional(),
|
|
24255
|
-
scanConfiguration:
|
|
24263
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24256
24264
|
}),
|
|
24257
24265
|
external_exports.object({
|
|
24258
24266
|
scanMode: external_exports.literal("SCA"),
|
|
@@ -24260,7 +24268,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24260
24268
|
branch: external_exports.string().optional(),
|
|
24261
24269
|
scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
|
|
24262
24270
|
userProvidedContext: external_exports.string().optional(),
|
|
24263
|
-
scanConfiguration:
|
|
24271
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24264
24272
|
}),
|
|
24265
24273
|
external_exports.object({
|
|
24266
24274
|
scanMode: external_exports.literal("SECRETS"),
|
|
@@ -24268,7 +24276,7 @@ var CreateScanRequestSchema = external_exports.discriminatedUnion("scanMode", [
|
|
|
24268
24276
|
branch: external_exports.string().optional(),
|
|
24269
24277
|
scanType: external_exports.enum(["FULL", "INCREMENTAL"]).optional(),
|
|
24270
24278
|
userProvidedContext: external_exports.string().optional(),
|
|
24271
|
-
scanConfiguration:
|
|
24279
|
+
scanConfiguration: ScanConfigurationSchema.optional()
|
|
24272
24280
|
})
|
|
24273
24281
|
]);
|
|
24274
24282
|
var ScanResponseSchema = external_exports.object({
|
|
@@ -26165,6 +26173,7 @@ function colorAccentUnderline(text, colorizer = source_default) {
|
|
|
26165
26173
|
var readTokenSafe = readToken;
|
|
26166
26174
|
var PRODUCTION_API_URL = "https://api.securewithtrace.com";
|
|
26167
26175
|
var UNAUTHORIZED_STATUS = 401;
|
|
26176
|
+
var REFRESH_AUTH_FAILURE_STATUS_CODES = /* @__PURE__ */ new Set([400, 401]);
|
|
26168
26177
|
function getApiBaseUrl() {
|
|
26169
26178
|
const raw = process.env["TRACE_API_URL"];
|
|
26170
26179
|
if (!raw) {
|
|
@@ -26209,9 +26218,24 @@ function getWorkosClientId() {
|
|
|
26209
26218
|
}
|
|
26210
26219
|
return clientId;
|
|
26211
26220
|
}
|
|
26221
|
+
function parseRefreshFailureStatus(error48) {
|
|
26222
|
+
if (!(error48 instanceof Error)) {
|
|
26223
|
+
return null;
|
|
26224
|
+
}
|
|
26225
|
+
const statusMatch = error48.message.match(/\b([1-5]\d{2})\b/);
|
|
26226
|
+
if (!statusMatch?.[1]) {
|
|
26227
|
+
return null;
|
|
26228
|
+
}
|
|
26229
|
+
return Number.parseInt(statusMatch[1], 10);
|
|
26230
|
+
}
|
|
26231
|
+
function isRefreshAuthFailure(error48) {
|
|
26232
|
+
const status = parseRefreshFailureStatus(error48);
|
|
26233
|
+
return status !== null && REFRESH_AUTH_FAILURE_STATUS_CODES.has(status);
|
|
26234
|
+
}
|
|
26212
26235
|
async function refreshStoredAccessToken() {
|
|
26213
26236
|
const clientId = getWorkosClientId();
|
|
26214
26237
|
const refreshToken = readRefreshToken();
|
|
26238
|
+
const tokenOrganizationId = extractOrganizationIdFromToken(readToken());
|
|
26215
26239
|
if (!clientId || !refreshToken) {
|
|
26216
26240
|
return null;
|
|
26217
26241
|
}
|
|
@@ -26221,7 +26245,20 @@ async function refreshStoredAccessToken() {
|
|
|
26221
26245
|
writeTokens(tokenResponse.access_token, nextRefreshToken);
|
|
26222
26246
|
return tokenResponse.access_token;
|
|
26223
26247
|
} catch (error48) {
|
|
26224
|
-
if (
|
|
26248
|
+
if (tokenOrganizationId && isRefreshAuthFailure(error48)) {
|
|
26249
|
+
try {
|
|
26250
|
+
const tokenResponse = await refreshAccessToken(clientId, refreshToken, tokenOrganizationId);
|
|
26251
|
+
const nextRefreshToken = tokenResponse.refresh_token ?? refreshToken;
|
|
26252
|
+
writeTokens(tokenResponse.access_token, nextRefreshToken);
|
|
26253
|
+
return tokenResponse.access_token;
|
|
26254
|
+
} catch (orgRefreshError) {
|
|
26255
|
+
if (isRefreshAuthFailure(orgRefreshError)) {
|
|
26256
|
+
removeToken();
|
|
26257
|
+
}
|
|
26258
|
+
return null;
|
|
26259
|
+
}
|
|
26260
|
+
}
|
|
26261
|
+
if (isRefreshAuthFailure(error48)) {
|
|
26225
26262
|
removeToken();
|
|
26226
26263
|
}
|
|
26227
26264
|
return null;
|
|
@@ -26239,7 +26276,7 @@ async function refreshStoredAccessTokenForOrganization(workosOrganizationId) {
|
|
|
26239
26276
|
writeTokens(tokenResponse.access_token, nextRefreshToken);
|
|
26240
26277
|
return true;
|
|
26241
26278
|
} catch (error48) {
|
|
26242
|
-
if (
|
|
26279
|
+
if (isRefreshAuthFailure(error48)) {
|
|
26243
26280
|
removeToken();
|
|
26244
26281
|
}
|
|
26245
26282
|
return false;
|
|
@@ -26673,7 +26710,7 @@ Examples:
|
|
|
26673
26710
|
const existingToken = readToken();
|
|
26674
26711
|
if (existingToken) {
|
|
26675
26712
|
console.log(
|
|
26676
|
-
`${colorWarning("You are already logged in.")} Run \`
|
|
26713
|
+
`${colorWarning("You are already logged in.")} Run \`tracecli auth logout\` first to re-authenticate.`
|
|
26677
26714
|
);
|
|
26678
26715
|
return;
|
|
26679
26716
|
}
|
|
@@ -26771,6 +26808,7 @@ Examples:
|
|
|
26771
26808
|
return;
|
|
26772
26809
|
}
|
|
26773
26810
|
if (options.output === "tsv") {
|
|
26811
|
+
console.log("loggedIn expired hasRefreshToken userId orgId activeOrg");
|
|
26774
26812
|
console.log(
|
|
26775
26813
|
[
|
|
26776
26814
|
String(info.loggedIn),
|
|
@@ -26840,6 +26878,7 @@ Examples:
|
|
|
26840
26878
|
return;
|
|
26841
26879
|
}
|
|
26842
26880
|
if (options.output === "tsv") {
|
|
26881
|
+
console.log("name slug organizationId active");
|
|
26843
26882
|
for (const item of items) {
|
|
26844
26883
|
console.log(
|
|
26845
26884
|
[
|
|
@@ -26893,6 +26932,7 @@ Examples:
|
|
|
26893
26932
|
return;
|
|
26894
26933
|
}
|
|
26895
26934
|
if (options.output === "tsv") {
|
|
26935
|
+
console.log("name slug organizationId source");
|
|
26896
26936
|
console.log(
|
|
26897
26937
|
[
|
|
26898
26938
|
tsvSafe(active.name),
|
|
@@ -27353,7 +27393,15 @@ function resolveShell(shellOption) {
|
|
|
27353
27393
|
return shell;
|
|
27354
27394
|
}
|
|
27355
27395
|
function createCompletionCommand(program3) {
|
|
27356
|
-
return new Command("completion").description("Generate shell completion script").option("--shell <shell>", `Shell type (${SUPPORTED_SHELLS.join(", ")})`).
|
|
27396
|
+
return new Command("completion").description("Generate shell completion script").option("--shell <shell>", `Shell type (${SUPPORTED_SHELLS.join(", ")})`).addHelpText(
|
|
27397
|
+
"after",
|
|
27398
|
+
`
|
|
27399
|
+
Examples:
|
|
27400
|
+
tracecli completion --shell bash
|
|
27401
|
+
tracecli completion --shell zsh
|
|
27402
|
+
tracecli completion --shell fish
|
|
27403
|
+
tracecli completion # auto-detects shell from $SHELL`
|
|
27404
|
+
).action((options) => {
|
|
27357
27405
|
const shell = resolveShell(options.shell);
|
|
27358
27406
|
const script = generateCompletion(program3, shell);
|
|
27359
27407
|
const writtenPath = writeCompletionFile(shell, script);
|
|
@@ -27457,6 +27505,10 @@ Run \`tracecli pentest list\` to see available pentests.`
|
|
|
27457
27505
|
}
|
|
27458
27506
|
function createListCommand() {
|
|
27459
27507
|
return new Command("list").description("List pentests for your organization").option(
|
|
27508
|
+
"--status <status>",
|
|
27509
|
+
"Filter by status (SCOPING, IN_PROGRESS, REMEDIATION, CLOSED)",
|
|
27510
|
+
(value) => value.toUpperCase()
|
|
27511
|
+
).option(
|
|
27460
27512
|
"-L, --limit <n>",
|
|
27461
27513
|
`Max results to return (default: ${DEFAULT_LIMIT}, max: ${MAX_LIMIT})`,
|
|
27462
27514
|
(v) => {
|
|
@@ -27471,6 +27523,7 @@ function createListCommand() {
|
|
|
27471
27523
|
`
|
|
27472
27524
|
Examples:
|
|
27473
27525
|
tracecli pentest list
|
|
27526
|
+
tracecli pentest list --status IN_PROGRESS
|
|
27474
27527
|
tracecli pentest list --limit 10
|
|
27475
27528
|
tracecli pentest list --output json | jq '.[].title'
|
|
27476
27529
|
tracecli pentest list --output tsv | cut -f1,2`
|
|
@@ -27489,8 +27542,12 @@ Examples:
|
|
|
27489
27542
|
console.error(`Failed to list pentests (status ${result.status}).`);
|
|
27490
27543
|
process.exit(1);
|
|
27491
27544
|
}
|
|
27545
|
+
let filteredPentests = result.body;
|
|
27546
|
+
if (options.status) {
|
|
27547
|
+
filteredPentests = filteredPentests.filter((p2) => p2.status === options.status);
|
|
27548
|
+
}
|
|
27492
27549
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
27493
|
-
const pentests =
|
|
27550
|
+
const pentests = filteredPentests.slice(0, limit);
|
|
27494
27551
|
const isJson = options.output === "json";
|
|
27495
27552
|
const isTsv = options.output === "tsv";
|
|
27496
27553
|
if (pentests.length === 0) {
|
|
@@ -27540,89 +27597,119 @@ Examples:
|
|
|
27540
27597
|
});
|
|
27541
27598
|
}
|
|
27542
27599
|
function createFindingsListCommand() {
|
|
27543
|
-
return new Command("list").description("List findings for a pentest").requiredOption("--pentest <id>", "Pentest display ID (e.g. PT-3) or UUID").option(
|
|
27600
|
+
return new Command("list").description("List findings for a pentest").requiredOption("--pentest <id>", "Pentest display ID (e.g. PT-3) or UUID").option(
|
|
27601
|
+
"--severity <severity>",
|
|
27602
|
+
"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW, INFORMATIONAL)",
|
|
27603
|
+
(value) => value.toUpperCase()
|
|
27604
|
+
).option(
|
|
27605
|
+
"--status <status>",
|
|
27606
|
+
"Filter by status (OPEN, IN_PROGRESS, CONTESTED, REMEDIATED, VERIFIED_FIXED, VERIFIED_OPEN, DISMISSED)",
|
|
27607
|
+
(value) => value.toUpperCase()
|
|
27608
|
+
).option(
|
|
27609
|
+
"-L, --limit <n>",
|
|
27610
|
+
`Max results to return (default: ${DEFAULT_LIMIT}, max: ${MAX_LIMIT})`,
|
|
27611
|
+
(v) => {
|
|
27612
|
+
const n = Number.parseInt(v, 10);
|
|
27613
|
+
if (Number.isNaN(n) || n < 1) {
|
|
27614
|
+
throw new Error("--limit must be a positive integer");
|
|
27615
|
+
}
|
|
27616
|
+
return Math.min(n, MAX_LIMIT);
|
|
27617
|
+
}
|
|
27618
|
+
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
27544
27619
|
"after",
|
|
27545
27620
|
`
|
|
27546
27621
|
Examples:
|
|
27547
27622
|
tracecli pentest findings list --pentest PT-3
|
|
27623
|
+
tracecli pentest findings list --pentest PT-3 --severity CRITICAL
|
|
27624
|
+
tracecli pentest findings list --pentest PT-3 --status OPEN --limit 20
|
|
27548
27625
|
tracecli pentest findings list --pentest PT-3 --output json
|
|
27549
27626
|
tracecli pentest findings list --pentest PT-3 --output tsv | cut -f1,4`
|
|
27550
|
-
).action(
|
|
27551
|
-
|
|
27552
|
-
|
|
27553
|
-
|
|
27554
|
-
|
|
27555
|
-
|
|
27556
|
-
|
|
27557
|
-
|
|
27558
|
-
if (result.status === 401) {
|
|
27559
|
-
console.error("Authentication failed. Run `tracecli auth login` to re-authenticate.");
|
|
27560
|
-
process.exit(1);
|
|
27561
|
-
}
|
|
27562
|
-
if (result.status === 404) {
|
|
27563
|
-
console.error(
|
|
27564
|
-
`Pentest '${options.pentest}' not found. Verify the ID with \`tracecli pentest list\`.`
|
|
27627
|
+
).action(
|
|
27628
|
+
async (options) => {
|
|
27629
|
+
const organizationId = await resolveOrganizationId();
|
|
27630
|
+
const pentestId = await resolvePentestId(organizationId, options.pentest);
|
|
27631
|
+
const result = await authenticatedRequest(
|
|
27632
|
+
(client) => client.pentestFinding.listFindings({
|
|
27633
|
+
params: { organizationId, pentestId }
|
|
27634
|
+
})
|
|
27565
27635
|
);
|
|
27566
|
-
|
|
27567
|
-
|
|
27568
|
-
|
|
27569
|
-
|
|
27570
|
-
|
|
27571
|
-
|
|
27572
|
-
|
|
27573
|
-
|
|
27574
|
-
|
|
27575
|
-
|
|
27636
|
+
if (result.status === 401) {
|
|
27637
|
+
console.error("Authentication failed. Run `tracecli auth login` to re-authenticate.");
|
|
27638
|
+
process.exit(1);
|
|
27639
|
+
}
|
|
27640
|
+
if (result.status === 404) {
|
|
27641
|
+
console.error(
|
|
27642
|
+
`Pentest '${options.pentest}' not found. Verify the ID with \`tracecli pentest list\`.`
|
|
27643
|
+
);
|
|
27644
|
+
process.exit(1);
|
|
27645
|
+
}
|
|
27646
|
+
if (result.status !== 200) {
|
|
27647
|
+
console.error(`Failed to list findings (status ${result.status}).`);
|
|
27648
|
+
process.exit(1);
|
|
27649
|
+
}
|
|
27650
|
+
let filteredFindings = result.body;
|
|
27651
|
+
if (options.severity) {
|
|
27652
|
+
filteredFindings = filteredFindings.filter((f) => f.severity === options.severity);
|
|
27653
|
+
}
|
|
27654
|
+
if (options.status) {
|
|
27655
|
+
filteredFindings = filteredFindings.filter((f) => f.status === options.status);
|
|
27656
|
+
}
|
|
27657
|
+
filteredFindings.sort(
|
|
27658
|
+
(a, b) => (SEVERITY_ORDER[a.severity] ?? 99) - (SEVERITY_ORDER[b.severity] ?? 99)
|
|
27659
|
+
);
|
|
27660
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
27661
|
+
const findings = filteredFindings.slice(0, limit);
|
|
27662
|
+
const isJson = options.output === "json";
|
|
27663
|
+
const isTsv = options.output === "tsv";
|
|
27664
|
+
if (findings.length === 0) {
|
|
27665
|
+
if (isJson) {
|
|
27666
|
+
console.log("[]");
|
|
27667
|
+
} else if (isTsv) {
|
|
27668
|
+
console.log("severity status category title cweIds cvssScore");
|
|
27669
|
+
} else {
|
|
27670
|
+
console.log("No findings found for this pentest.");
|
|
27671
|
+
}
|
|
27672
|
+
return;
|
|
27673
|
+
}
|
|
27576
27674
|
if (isJson) {
|
|
27577
|
-
console.log(
|
|
27578
|
-
|
|
27579
|
-
console.log("severity status category title cweIds cvssScore");
|
|
27580
|
-
} else {
|
|
27581
|
-
console.log("No findings found for this pentest.");
|
|
27675
|
+
console.log(JSON.stringify(findings, null, 2));
|
|
27676
|
+
return;
|
|
27582
27677
|
}
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27593
|
-
|
|
27594
|
-
|
|
27595
|
-
|
|
27596
|
-
|
|
27597
|
-
finding.status,
|
|
27598
|
-
tsvSafe2(finding.category),
|
|
27599
|
-
tsvSafe2(finding.title),
|
|
27600
|
-
finding.cweIds.join(";"),
|
|
27601
|
-
finding.cvssScore != null ? String(finding.cvssScore) : ""
|
|
27602
|
-
];
|
|
27603
|
-
console.log(cols.join(" "));
|
|
27678
|
+
if (isTsv) {
|
|
27679
|
+
console.log("severity status category title cweIds cvssScore");
|
|
27680
|
+
for (const finding of findings) {
|
|
27681
|
+
const cols = [
|
|
27682
|
+
finding.severity,
|
|
27683
|
+
finding.status,
|
|
27684
|
+
tsvSafe2(finding.category),
|
|
27685
|
+
tsvSafe2(finding.title),
|
|
27686
|
+
finding.cweIds.join(";"),
|
|
27687
|
+
finding.cvssScore != null ? String(finding.cvssScore) : ""
|
|
27688
|
+
];
|
|
27689
|
+
console.log(cols.join(" "));
|
|
27690
|
+
}
|
|
27691
|
+
return;
|
|
27604
27692
|
}
|
|
27605
|
-
|
|
27606
|
-
}
|
|
27607
|
-
console.log(`Found ${findings.length} finding${findings.length === 1 ? "" : "s"}:
|
|
27693
|
+
console.log(`Found ${findings.length} finding${findings.length === 1 ? "" : "s"}:
|
|
27608
27694
|
`);
|
|
27609
|
-
|
|
27610
|
-
|
|
27611
|
-
|
|
27612
|
-
|
|
27613
|
-
|
|
27614
|
-
|
|
27615
|
-
|
|
27616
|
-
|
|
27617
|
-
|
|
27618
|
-
|
|
27619
|
-
|
|
27620
|
-
|
|
27695
|
+
for (const finding of findings) {
|
|
27696
|
+
const sev = formatFindingSeverity(finding.severity);
|
|
27697
|
+
const severityLabel = colorSeverity(finding.severity, sev);
|
|
27698
|
+
const status = formatStatus(finding.status);
|
|
27699
|
+
const cwes = finding.cweIds.length > 0 ? ` | ${finding.cweIds.join(", ")}` : "";
|
|
27700
|
+
const score = finding.cvssScore != null ? ` | CVSS ${finding.cvssScore.toFixed(1)}` : "";
|
|
27701
|
+
console.log(` [${severityLabel}] ${finding.title}`);
|
|
27702
|
+
console.log(` ${finding.category} \xB7 ${status}${cwes}${score}`);
|
|
27703
|
+
if (finding.repositories.length > 0) {
|
|
27704
|
+
for (const repo of finding.repositories) {
|
|
27705
|
+
const location = repo.filePath ? `${repo.repositoryName} \xB7 ${repo.filePath}${repo.startLine != null ? `:${repo.startLine}` : ""}` : repo.repositoryName;
|
|
27706
|
+
console.log(` ${location}`);
|
|
27707
|
+
}
|
|
27621
27708
|
}
|
|
27709
|
+
console.log("");
|
|
27622
27710
|
}
|
|
27623
|
-
console.log("");
|
|
27624
27711
|
}
|
|
27625
|
-
|
|
27712
|
+
);
|
|
27626
27713
|
}
|
|
27627
27714
|
function createFindingsCommand() {
|
|
27628
27715
|
const findings = new Command("findings").description("Manage pentest findings");
|
|
@@ -27917,6 +28004,24 @@ function printRepositoriesTsv(repositories) {
|
|
|
27917
28004
|
);
|
|
27918
28005
|
}
|
|
27919
28006
|
}
|
|
28007
|
+
function printRepositoriesTable(repositories) {
|
|
28008
|
+
const headers = ["Repository URL", "Platform", "Status"];
|
|
28009
|
+
const rows = repositories.map(
|
|
28010
|
+
(repo) => [
|
|
28011
|
+
stripAnsi(String(repo.repositoryUrl)),
|
|
28012
|
+
stripAnsi(String(repo.platform)).toUpperCase(),
|
|
28013
|
+
repo.status === "CONNECTED" ? "connected" : "disconnected"
|
|
28014
|
+
]
|
|
28015
|
+
);
|
|
28016
|
+
const colWidths = headers.map(
|
|
28017
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length))
|
|
28018
|
+
);
|
|
28019
|
+
const pad = (s, w3) => s.padEnd(w3);
|
|
28020
|
+
console.log(headers.map((h, i) => pad(h, colWidths[i] ?? h.length)).join(" "));
|
|
28021
|
+
for (const row of rows) {
|
|
28022
|
+
console.log(row.map((cell, i) => pad(cell, colWidths[i] ?? 0)).join(" "));
|
|
28023
|
+
}
|
|
28024
|
+
}
|
|
27920
28025
|
function collectFilterExpression(value, previous) {
|
|
27921
28026
|
previous.push(value);
|
|
27922
28027
|
return previous;
|
|
@@ -28040,7 +28145,7 @@ function addRepositoryFilterOptions(command) {
|
|
|
28040
28145
|
"Advanced filter expression. Repeatable. Examples: platform=GITHUB, repo:trace, status!=DISCONNECTED",
|
|
28041
28146
|
collectFilterExpression,
|
|
28042
28147
|
[]
|
|
28043
|
-
).option("-o, --output <format>", "Output format: table
|
|
28148
|
+
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option(
|
|
28044
28149
|
"-L, --limit <n>",
|
|
28045
28150
|
`Maximum repositories to display (default ${DEFAULT_LIMIT2}, max ${MAX_LIMIT2})`,
|
|
28046
28151
|
parseListLimit,
|
|
@@ -28098,12 +28203,7 @@ async function runRepositoryListCommand(options) {
|
|
|
28098
28203
|
printRepositoriesTsv(displayedRepositories);
|
|
28099
28204
|
return;
|
|
28100
28205
|
}
|
|
28101
|
-
|
|
28102
|
-
const status = repo.status === "CONNECTED" ? "connected" : "disconnected";
|
|
28103
|
-
const url2 = stripAnsi(String(repo.repositoryUrl));
|
|
28104
|
-
const platform = stripAnsi(String(repo.platform)).toLowerCase();
|
|
28105
|
-
console.log(`${url2} (${platform}, ${status})`);
|
|
28106
|
-
}
|
|
28206
|
+
printRepositoriesTable(displayedRepositories);
|
|
28107
28207
|
}
|
|
28108
28208
|
async function runDependencyFilter(organizationId, options) {
|
|
28109
28209
|
const dependency = options.dependency;
|
|
@@ -28164,6 +28264,7 @@ async function runDependencyFilter(organizationId, options) {
|
|
|
28164
28264
|
return;
|
|
28165
28265
|
}
|
|
28166
28266
|
if (options.output === "tsv") {
|
|
28267
|
+
console.log("repository versions");
|
|
28167
28268
|
for (const repo of displayedRepos) {
|
|
28168
28269
|
console.log(`${tsvSafe(repo.fullName)} ${tsvSafe(repo.versions.join(","))}`);
|
|
28169
28270
|
}
|
|
@@ -28517,16 +28618,87 @@ function resolveRegistryUrl() {
|
|
|
28517
28618
|
if (typeof override === "string" && override.trim().length > 0) {
|
|
28518
28619
|
return override;
|
|
28519
28620
|
}
|
|
28520
|
-
return `https://registry.npmjs.org/${encodeURIComponent(CLI_PACKAGE_NAME)}
|
|
28621
|
+
return `https://registry.npmjs.org/${encodeURIComponent(CLI_PACKAGE_NAME)}`;
|
|
28622
|
+
}
|
|
28623
|
+
function isRecord(value) {
|
|
28624
|
+
return typeof value === "object" && value !== null;
|
|
28625
|
+
}
|
|
28626
|
+
function selectNewestVersion(versions) {
|
|
28627
|
+
let newestVersion = null;
|
|
28628
|
+
for (const version2 of versions) {
|
|
28629
|
+
if (newestVersion === null) {
|
|
28630
|
+
newestVersion = version2;
|
|
28631
|
+
continue;
|
|
28632
|
+
}
|
|
28633
|
+
const comparison = compareSemver(version2, newestVersion);
|
|
28634
|
+
if (comparison !== null && comparison > 0) {
|
|
28635
|
+
newestVersion = version2;
|
|
28636
|
+
}
|
|
28637
|
+
}
|
|
28638
|
+
return newestVersion;
|
|
28639
|
+
}
|
|
28640
|
+
function isStableSemver(version2) {
|
|
28641
|
+
const parsed = parseSemver(version2);
|
|
28642
|
+
return parsed !== null && parsed.prerelease.length === 0;
|
|
28643
|
+
}
|
|
28644
|
+
function extractPublishedVersions(payload) {
|
|
28645
|
+
const versionsField = payload["versions"];
|
|
28646
|
+
if (!isRecord(versionsField)) {
|
|
28647
|
+
return [];
|
|
28648
|
+
}
|
|
28649
|
+
const publishedVersions = [];
|
|
28650
|
+
for (const version2 of Object.keys(versionsField)) {
|
|
28651
|
+
if (parseSemver(version2) !== null) {
|
|
28652
|
+
publishedVersions.push(version2);
|
|
28653
|
+
}
|
|
28654
|
+
}
|
|
28655
|
+
return publishedVersions;
|
|
28656
|
+
}
|
|
28657
|
+
function extractDistTagLatestVersion(payload) {
|
|
28658
|
+
const distTags = payload["dist-tags"];
|
|
28659
|
+
if (!isRecord(distTags)) {
|
|
28660
|
+
return null;
|
|
28661
|
+
}
|
|
28662
|
+
if (typeof distTags["latest"] !== "string") {
|
|
28663
|
+
return null;
|
|
28664
|
+
}
|
|
28665
|
+
const candidate = distTags["latest"].trim();
|
|
28666
|
+
if (candidate.length === 0 || parseSemver(candidate) === null) {
|
|
28667
|
+
return null;
|
|
28668
|
+
}
|
|
28669
|
+
return candidate;
|
|
28670
|
+
}
|
|
28671
|
+
function extractLatestEndpointVersion(payload) {
|
|
28672
|
+
if (typeof payload["version"] !== "string") {
|
|
28673
|
+
return null;
|
|
28674
|
+
}
|
|
28675
|
+
const candidate = payload["version"].trim();
|
|
28676
|
+
if (candidate.length === 0 || parseSemver(candidate) === null) {
|
|
28677
|
+
return null;
|
|
28678
|
+
}
|
|
28679
|
+
return candidate;
|
|
28521
28680
|
}
|
|
28522
28681
|
function extractLatestVersionFromRegistryPayload(payload) {
|
|
28523
|
-
if (
|
|
28682
|
+
if (!isRecord(payload)) {
|
|
28524
28683
|
return null;
|
|
28525
28684
|
}
|
|
28526
|
-
|
|
28527
|
-
|
|
28685
|
+
const publishedVersions = extractPublishedVersions(payload);
|
|
28686
|
+
const hasPublishedVersions = publishedVersions.length > 0;
|
|
28687
|
+
const publishedVersionSet = new Set(publishedVersions);
|
|
28688
|
+
const distTagLatestVersion = extractDistTagLatestVersion(payload);
|
|
28689
|
+
if (distTagLatestVersion && (!hasPublishedVersions || publishedVersionSet.has(distTagLatestVersion))) {
|
|
28690
|
+
return distTagLatestVersion;
|
|
28528
28691
|
}
|
|
28529
|
-
|
|
28692
|
+
const latestEndpointVersion = extractLatestEndpointVersion(payload);
|
|
28693
|
+
if (latestEndpointVersion && (!hasPublishedVersions || publishedVersionSet.has(latestEndpointVersion))) {
|
|
28694
|
+
return latestEndpointVersion;
|
|
28695
|
+
}
|
|
28696
|
+
const stablePublishedVersions = publishedVersions.filter((version2) => isStableSemver(version2));
|
|
28697
|
+
const newestStableVersion = selectNewestVersion(stablePublishedVersions);
|
|
28698
|
+
if (newestStableVersion) {
|
|
28699
|
+
return newestStableVersion;
|
|
28700
|
+
}
|
|
28701
|
+
return selectNewestVersion(publishedVersions);
|
|
28530
28702
|
}
|
|
28531
28703
|
async function fetchLatestVersionFromRegistry() {
|
|
28532
28704
|
try {
|
|
@@ -28593,15 +28765,21 @@ async function maybeNotifyUpdateAvailable(commandName) {
|
|
|
28593
28765
|
return;
|
|
28594
28766
|
}
|
|
28595
28767
|
noticePrinted = true;
|
|
28596
|
-
|
|
28597
|
-
|
|
28598
|
-
`
|
|
28599
|
-
|
|
28600
|
-
|
|
28601
|
-
|
|
28602
|
-
}
|
|
28603
|
-
|
|
28604
|
-
const
|
|
28768
|
+
const lines = [
|
|
28769
|
+
`A new tracecli version is available: ${availability.currentVersion} -> ${availability.latestVersion}`,
|
|
28770
|
+
"Run `tracecli upgrade` to install the latest version."
|
|
28771
|
+
];
|
|
28772
|
+
const maxLen = Math.max(...lines.map((l) => l.length));
|
|
28773
|
+
const pad = (s) => s + " ".repeat(maxLen - s.length);
|
|
28774
|
+
const top = `\u256D${"\u2500".repeat(maxLen + 2)}\u256E`;
|
|
28775
|
+
const bottom = `\u2570${"\u2500".repeat(maxLen + 2)}\u256F`;
|
|
28776
|
+
const boxed = [top, ...lines.map((l) => `\u2502 ${pad(l)} \u2502`), bottom].join("\n");
|
|
28777
|
+
console.log("");
|
|
28778
|
+
console.log(colorMuted(boxed));
|
|
28779
|
+
console.log("");
|
|
28780
|
+
}
|
|
28781
|
+
function resolveUpgradePlan(targetVersion) {
|
|
28782
|
+
const packageSpec = targetVersion ? `${CLI_PACKAGE_NAME}@${targetVersion}` : `${CLI_PACKAGE_NAME}@latest`;
|
|
28605
28783
|
if (Bun.which("npm")) {
|
|
28606
28784
|
return { command: "npm", args: ["install", "-g", packageSpec] };
|
|
28607
28785
|
}
|
|
@@ -28665,7 +28843,7 @@ Examples:
|
|
|
28665
28843
|
console.log("Upgrade cancelled.");
|
|
28666
28844
|
return;
|
|
28667
28845
|
}
|
|
28668
|
-
const plan = resolveUpgradePlan();
|
|
28846
|
+
const plan = resolveUpgradePlan(availability.latestVersion);
|
|
28669
28847
|
if (!plan) {
|
|
28670
28848
|
console.error(
|
|
28671
28849
|
`No supported package manager found (npm, bun, pnpm). Install the latest version manually from https://www.npmjs.com/package/${CLI_PACKAGE_NAME}`
|
|
@@ -28899,7 +29077,7 @@ function createVulnerabilitiesCommand() {
|
|
|
28899
29077
|
// src/index.ts
|
|
28900
29078
|
var program2 = new Command();
|
|
28901
29079
|
program2.name("tracecli").description("Trace CLI").version(CLI_VERSION);
|
|
28902
|
-
program2.hook("
|
|
29080
|
+
program2.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
28903
29081
|
await maybeNotifyUpdateAvailable(actionCommand.name());
|
|
28904
29082
|
});
|
|
28905
29083
|
program2.action(() => {
|