securewithtrace 0.16.0 → 0.17.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.
- package/dist/index.js +179 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23943,7 +23943,9 @@ var VulnerabilityAggregatedCountsRequestSchema = external_exports.object({
|
|
|
23943
23943
|
excludeStatuses: external_exports.array(VulnerabilityStatus).optional(),
|
|
23944
23944
|
defaultBranchOnly: external_exports.boolean().default(true).optional(),
|
|
23945
23945
|
/** Lower bound for time-series data. Only vulnerabilities created on or after this date are included in the timeSeries field. Does not affect byRepoAndSeverity or byStatusAndSeverity. */
|
|
23946
|
-
timeSeriesSince: external_exports.coerce.date().optional()
|
|
23946
|
+
timeSeriesSince: external_exports.coerce.date().optional(),
|
|
23947
|
+
/** When provided, only include vulnerabilities belonging to this repository. */
|
|
23948
|
+
repositoryId: external_exports.uuid().optional()
|
|
23947
23949
|
});
|
|
23948
23950
|
var VulnerabilityAggregatedCountsResponseSchema = external_exports.object({
|
|
23949
23951
|
byRepoAndSeverity: external_exports.array(RepoSeverityCountSchema),
|
|
@@ -24957,8 +24959,24 @@ async function authenticatedRequestSafe(request) {
|
|
|
24957
24959
|
return null;
|
|
24958
24960
|
}
|
|
24959
24961
|
}
|
|
24962
|
+
function extractOrganizationIdFromToken(token) {
|
|
24963
|
+
if (!token || token.trim().length === 0) {
|
|
24964
|
+
return null;
|
|
24965
|
+
}
|
|
24966
|
+
const parts = token.split(".");
|
|
24967
|
+
const payload = parts[1];
|
|
24968
|
+
if (!payload) {
|
|
24969
|
+
return null;
|
|
24970
|
+
}
|
|
24971
|
+
try {
|
|
24972
|
+
const decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf-8"));
|
|
24973
|
+
return typeof decoded.org_id === "string" && decoded.org_id.trim().length > 0 ? decoded.org_id : null;
|
|
24974
|
+
} catch {
|
|
24975
|
+
return null;
|
|
24976
|
+
}
|
|
24977
|
+
}
|
|
24960
24978
|
var SAFE_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
24961
|
-
function determineActiveOrganization(organizations, selectedOrganizationId) {
|
|
24979
|
+
function determineActiveOrganization(organizations, selectedOrganizationId, tokenOrganizationId) {
|
|
24962
24980
|
if (organizations.length === 0) {
|
|
24963
24981
|
return null;
|
|
24964
24982
|
}
|
|
@@ -24974,6 +24992,18 @@ function determineActiveOrganization(organizations, selectedOrganizationId) {
|
|
|
24974
24992
|
};
|
|
24975
24993
|
}
|
|
24976
24994
|
}
|
|
24995
|
+
if (tokenOrganizationId && SAFE_ID_PATTERN.test(tokenOrganizationId)) {
|
|
24996
|
+
const tokenOrganization = organizations.find(
|
|
24997
|
+
(organization) => organization.organizationId === tokenOrganizationId
|
|
24998
|
+
);
|
|
24999
|
+
if (tokenOrganization) {
|
|
25000
|
+
return {
|
|
25001
|
+
organization: tokenOrganization,
|
|
25002
|
+
source: "default",
|
|
25003
|
+
staleSelectionDetected: selectedOrganizationId != null
|
|
25004
|
+
};
|
|
25005
|
+
}
|
|
25006
|
+
}
|
|
24977
25007
|
const [fallbackOrganization] = organizations;
|
|
24978
25008
|
if (!fallbackOrganization) {
|
|
24979
25009
|
return null;
|
|
@@ -24994,7 +25024,12 @@ async function resolveOrganizationId(client) {
|
|
|
24994
25024
|
}
|
|
24995
25025
|
const organizations = result.body;
|
|
24996
25026
|
const selectedOrganizationId = readSelectedOrganizationId();
|
|
24997
|
-
const
|
|
25027
|
+
const tokenOrganizationId = extractOrganizationIdFromToken(readToken());
|
|
25028
|
+
const activeOrganization = determineActiveOrganization(
|
|
25029
|
+
organizations,
|
|
25030
|
+
selectedOrganizationId,
|
|
25031
|
+
tokenOrganizationId
|
|
25032
|
+
);
|
|
24998
25033
|
if (!activeOrganization) {
|
|
24999
25034
|
console.error("No organization found for your account.");
|
|
25000
25035
|
process.exit(1);
|
|
@@ -25030,7 +25065,12 @@ async function resolveOrganizationIdSafe(client) {
|
|
|
25030
25065
|
}
|
|
25031
25066
|
const organizations = result.body;
|
|
25032
25067
|
const selectedOrganizationId = readSelectedOrganizationId();
|
|
25033
|
-
const
|
|
25068
|
+
const tokenOrganizationId = extractOrganizationIdFromToken(readToken());
|
|
25069
|
+
const activeOrganization = determineActiveOrganization(
|
|
25070
|
+
organizations,
|
|
25071
|
+
selectedOrganizationId,
|
|
25072
|
+
tokenOrganizationId
|
|
25073
|
+
);
|
|
25034
25074
|
if (!activeOrganization) {
|
|
25035
25075
|
return null;
|
|
25036
25076
|
}
|
|
@@ -25050,6 +25090,21 @@ async function resolveOrganizationIdSafe(client) {
|
|
|
25050
25090
|
}
|
|
25051
25091
|
}
|
|
25052
25092
|
|
|
25093
|
+
// src/format.ts
|
|
25094
|
+
var SEVERITY_ORDER = {
|
|
25095
|
+
CRITICAL: 0,
|
|
25096
|
+
HIGH: 1,
|
|
25097
|
+
MEDIUM: 2,
|
|
25098
|
+
LOW: 3,
|
|
25099
|
+
INFORMATIONAL: 4
|
|
25100
|
+
};
|
|
25101
|
+
function formatStatus(status) {
|
|
25102
|
+
return status.toLowerCase().replace("_", " ");
|
|
25103
|
+
}
|
|
25104
|
+
function tsvSafe(value) {
|
|
25105
|
+
return (value ?? "").replace(/[\t\r\n]/g, " ");
|
|
25106
|
+
}
|
|
25107
|
+
|
|
25053
25108
|
// src/auth/commands.ts
|
|
25054
25109
|
function getClientId() {
|
|
25055
25110
|
const clientId = "client_01KEZ01W5Q3107GTBY51WQ67HT";
|
|
@@ -25312,7 +25367,14 @@ function createStatusCommand() {
|
|
|
25312
25367
|
});
|
|
25313
25368
|
}
|
|
25314
25369
|
function createOrgListCommand() {
|
|
25315
|
-
return new Command("list").description("List organizations available to your account").option("--
|
|
25370
|
+
return new Command("list").description("List organizations available to your account").option("-o, --output <format>", "Output format: table (default), json, tsv").addHelpText(
|
|
25371
|
+
"after",
|
|
25372
|
+
`
|
|
25373
|
+
Examples:
|
|
25374
|
+
tracecli org list
|
|
25375
|
+
tracecli org list --output json
|
|
25376
|
+
tracecli org list --output tsv | cut -f1`
|
|
25377
|
+
).action(async (options) => {
|
|
25316
25378
|
const organizationContext = await fetchOrganizationContext();
|
|
25317
25379
|
const items = organizationContext.organizations.map(
|
|
25318
25380
|
(organization) => ({
|
|
@@ -25321,10 +25383,23 @@ function createOrgListCommand() {
|
|
|
25321
25383
|
selected: organization.organizationId === organizationContext.selectedOrganizationId
|
|
25322
25384
|
})
|
|
25323
25385
|
);
|
|
25324
|
-
if (options.json) {
|
|
25386
|
+
if (options.output === "json") {
|
|
25325
25387
|
console.log(JSON.stringify(items, null, 2));
|
|
25326
25388
|
return;
|
|
25327
25389
|
}
|
|
25390
|
+
if (options.output === "tsv") {
|
|
25391
|
+
for (const item of items) {
|
|
25392
|
+
console.log(
|
|
25393
|
+
[
|
|
25394
|
+
tsvSafe(item.name),
|
|
25395
|
+
tsvSafe(item.slug),
|
|
25396
|
+
tsvSafe(item.organizationId),
|
|
25397
|
+
item.active ? "true" : "false"
|
|
25398
|
+
].join(" ")
|
|
25399
|
+
);
|
|
25400
|
+
}
|
|
25401
|
+
return;
|
|
25402
|
+
}
|
|
25328
25403
|
for (const item of items) {
|
|
25329
25404
|
const marker = item.active ? "*" : " ";
|
|
25330
25405
|
const labels = [item.active ? "active" : null, item.selected ? "selected" : null].filter(
|
|
@@ -25341,11 +25416,18 @@ function createOrgListCommand() {
|
|
|
25341
25416
|
});
|
|
25342
25417
|
}
|
|
25343
25418
|
function createOrgCurrentCommand() {
|
|
25344
|
-
return new Command("current").description("Show the active organization used by CLI commands").option("--
|
|
25419
|
+
return new Command("current").description("Show the active organization used by CLI commands").option("-o, --output <format>", "Output format: table (default), json, tsv").addHelpText(
|
|
25420
|
+
"after",
|
|
25421
|
+
`
|
|
25422
|
+
Examples:
|
|
25423
|
+
tracecli org current
|
|
25424
|
+
tracecli org current --output json
|
|
25425
|
+
tracecli org current --output tsv`
|
|
25426
|
+
).action(async (options) => {
|
|
25345
25427
|
const organizationContext = await fetchOrganizationContext();
|
|
25346
25428
|
const active = organizationContext.activeOrganization;
|
|
25347
25429
|
const source = organizationContext.selectedOrganizationId === active.organizationId ? "selected" : "default";
|
|
25348
|
-
if (options.json) {
|
|
25430
|
+
if (options.output === "json") {
|
|
25349
25431
|
console.log(
|
|
25350
25432
|
JSON.stringify(
|
|
25351
25433
|
{
|
|
@@ -25358,6 +25440,17 @@ function createOrgCurrentCommand() {
|
|
|
25358
25440
|
);
|
|
25359
25441
|
return;
|
|
25360
25442
|
}
|
|
25443
|
+
if (options.output === "tsv") {
|
|
25444
|
+
console.log(
|
|
25445
|
+
[
|
|
25446
|
+
tsvSafe(active.name),
|
|
25447
|
+
tsvSafe(active.slug),
|
|
25448
|
+
tsvSafe(active.organizationId),
|
|
25449
|
+
tsvSafe(source)
|
|
25450
|
+
].join(" ")
|
|
25451
|
+
);
|
|
25452
|
+
return;
|
|
25453
|
+
}
|
|
25361
25454
|
console.log(
|
|
25362
25455
|
`Active organization: ${sanitizeForOutput(active.name)} (${sanitizeForOutput(active.slug)})`
|
|
25363
25456
|
);
|
|
@@ -25792,22 +25885,10 @@ function createCompletionCommand(program3) {
|
|
|
25792
25885
|
});
|
|
25793
25886
|
}
|
|
25794
25887
|
|
|
25795
|
-
// src/format.ts
|
|
25796
|
-
var SEVERITY_ORDER = {
|
|
25797
|
-
CRITICAL: 0,
|
|
25798
|
-
HIGH: 1,
|
|
25799
|
-
MEDIUM: 2,
|
|
25800
|
-
LOW: 3,
|
|
25801
|
-
INFORMATIONAL: 4
|
|
25802
|
-
};
|
|
25803
|
-
function formatStatus(status) {
|
|
25804
|
-
return status.toLowerCase().replace("_", " ");
|
|
25805
|
-
}
|
|
25806
|
-
|
|
25807
25888
|
// src/pentest/commands.ts
|
|
25808
25889
|
var DEFAULT_LIMIT = 30;
|
|
25809
25890
|
var MAX_LIMIT = 100;
|
|
25810
|
-
function
|
|
25891
|
+
function tsvSafe2(value) {
|
|
25811
25892
|
return value.replace(/[\t\n\r]/g, " ");
|
|
25812
25893
|
}
|
|
25813
25894
|
function formatDate(date5) {
|
|
@@ -25926,7 +26007,7 @@ Examples:
|
|
|
25926
26007
|
for (const pt of pentests) {
|
|
25927
26008
|
const cols = [
|
|
25928
26009
|
`PT-${pt.displayId}`,
|
|
25929
|
-
|
|
26010
|
+
tsvSafe2(pt.title),
|
|
25930
26011
|
pt.status,
|
|
25931
26012
|
pt.startedAt ? String(pt.startedAt) : "",
|
|
25932
26013
|
pt.endedAt ? String(pt.endedAt) : "",
|
|
@@ -26009,8 +26090,8 @@ Examples:
|
|
|
26009
26090
|
const cols = [
|
|
26010
26091
|
finding.severity,
|
|
26011
26092
|
finding.status,
|
|
26012
|
-
|
|
26013
|
-
|
|
26093
|
+
tsvSafe2(finding.category),
|
|
26094
|
+
tsvSafe2(finding.title),
|
|
26014
26095
|
finding.cweIds.join(";"),
|
|
26015
26096
|
finding.cvssScore != null ? String(finding.cvssScore) : ""
|
|
26016
26097
|
];
|
|
@@ -26098,6 +26179,8 @@ function extractRepoName(input) {
|
|
|
26098
26179
|
}
|
|
26099
26180
|
var BRANCH_NAME_PATTERN = /^[a-zA-Z0-9._/+-]+$/;
|
|
26100
26181
|
var TRACE_GIT_ASKPASS_TOKEN_ENV = "TRACE_GIT_ASKPASS_TOKEN";
|
|
26182
|
+
var DEFAULT_LIMIT2 = 30;
|
|
26183
|
+
var MAX_LIMIT2 = 100;
|
|
26101
26184
|
var REPOSITORY_PLATFORMS = ["GITHUB", "GITLAB", "BITBUCKET"];
|
|
26102
26185
|
var REPOSITORY_STATUSES = ["CONNECTED", "DISCONNECTED"];
|
|
26103
26186
|
function validateBranchName(branch) {
|
|
@@ -26304,6 +26387,29 @@ function filterRepositories(repositories, options) {
|
|
|
26304
26387
|
return true;
|
|
26305
26388
|
});
|
|
26306
26389
|
}
|
|
26390
|
+
function parseListLimit(value) {
|
|
26391
|
+
const n = Number(value);
|
|
26392
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
26393
|
+
throw new Error("--limit must be a positive integer");
|
|
26394
|
+
}
|
|
26395
|
+
if (n > MAX_LIMIT2) {
|
|
26396
|
+
throw new Error(`--limit cannot exceed ${MAX_LIMIT2}`);
|
|
26397
|
+
}
|
|
26398
|
+
return n;
|
|
26399
|
+
}
|
|
26400
|
+
function printRepositoriesTsv(repositories) {
|
|
26401
|
+
for (const repo of repositories) {
|
|
26402
|
+
console.log(
|
|
26403
|
+
[
|
|
26404
|
+
tsvSafe(repo.repositoryUrl),
|
|
26405
|
+
tsvSafe(repo.platform),
|
|
26406
|
+
tsvSafe(repo.status),
|
|
26407
|
+
tsvSafe(repo.defaultBranch),
|
|
26408
|
+
tsvSafe(repo.primaryLanguage)
|
|
26409
|
+
].join(" ")
|
|
26410
|
+
);
|
|
26411
|
+
}
|
|
26412
|
+
}
|
|
26307
26413
|
function collectFilterExpression(value, previous) {
|
|
26308
26414
|
previous.push(value);
|
|
26309
26415
|
return previous;
|
|
@@ -26328,11 +26434,16 @@ function addRepositoryFilterOptions(command) {
|
|
|
26328
26434
|
"Filter by status (CONNECTED, DISCONNECTED)",
|
|
26329
26435
|
(value) => value.toUpperCase()
|
|
26330
26436
|
).option("--query <query>", "Case-insensitive search across URL, repo, branch, and language").option("--default-branch <branch>", "Filter by default branch (case-insensitive contains)").option("--language <language>", "Filter by primary language (case-insensitive contains)").option(
|
|
26331
|
-
"--filter <expression>",
|
|
26332
|
-
"Advanced filter expression. Repeatable. Examples: platform=GITHUB, repo:trace, status!=DISCONNECTED
|
|
26437
|
+
"-f, --filter <expression>",
|
|
26438
|
+
"Advanced filter expression. Repeatable. Examples: platform=GITHUB, repo:trace, status!=DISCONNECTED",
|
|
26333
26439
|
collectFilterExpression,
|
|
26334
26440
|
[]
|
|
26335
|
-
).option("--
|
|
26441
|
+
).option("-o, --output <format>", "Output format: table (default), json, tsv").option(
|
|
26442
|
+
"-L, --limit <n>",
|
|
26443
|
+
`Maximum repositories to display (default ${DEFAULT_LIMIT2}, max ${MAX_LIMIT2})`,
|
|
26444
|
+
parseListLimit,
|
|
26445
|
+
DEFAULT_LIMIT2
|
|
26446
|
+
).option(
|
|
26336
26447
|
"--dependency <pkg>",
|
|
26337
26448
|
"Filter repositories that use a dependency (e.g. lodash, lodash@4.17.21, @types/node@20)"
|
|
26338
26449
|
);
|
|
@@ -26371,11 +26482,17 @@ async function runRepositoryListCommand(options) {
|
|
|
26371
26482
|
console.log("No repositories found.");
|
|
26372
26483
|
return;
|
|
26373
26484
|
}
|
|
26374
|
-
|
|
26375
|
-
|
|
26485
|
+
const limit = options.limit ?? DEFAULT_LIMIT2;
|
|
26486
|
+
const displayedRepositories = filteredRepositories.slice(0, limit);
|
|
26487
|
+
if (options.output === "json") {
|
|
26488
|
+
console.log(JSON.stringify(displayedRepositories, null, 2));
|
|
26376
26489
|
return;
|
|
26377
26490
|
}
|
|
26378
|
-
|
|
26491
|
+
if (options.output === "tsv") {
|
|
26492
|
+
printRepositoriesTsv(displayedRepositories);
|
|
26493
|
+
return;
|
|
26494
|
+
}
|
|
26495
|
+
for (const repo of displayedRepositories) {
|
|
26379
26496
|
const status = repo.status === "CONNECTED" ? "connected" : "disconnected";
|
|
26380
26497
|
const url2 = stripAnsi(String(repo.repositoryUrl));
|
|
26381
26498
|
const platform = stripAnsi(String(repo.platform)).toLowerCase();
|
|
@@ -26430,11 +26547,19 @@ async function runDependencyFilter(organizationId, options) {
|
|
|
26430
26547
|
console.log(`No repositories found using dependency '${label}'.`);
|
|
26431
26548
|
return;
|
|
26432
26549
|
}
|
|
26433
|
-
|
|
26434
|
-
|
|
26550
|
+
const limit = options.limit ?? DEFAULT_LIMIT2;
|
|
26551
|
+
const displayedRepos = repos.slice(0, limit);
|
|
26552
|
+
if (options.output === "json") {
|
|
26553
|
+
console.log(JSON.stringify(displayedRepos, null, 2));
|
|
26435
26554
|
return;
|
|
26436
26555
|
}
|
|
26437
|
-
|
|
26556
|
+
if (options.output === "tsv") {
|
|
26557
|
+
for (const repo of displayedRepos) {
|
|
26558
|
+
console.log(`${tsvSafe(repo.fullName)} ${tsvSafe(repo.versions.join(","))}`);
|
|
26559
|
+
}
|
|
26560
|
+
return;
|
|
26561
|
+
}
|
|
26562
|
+
for (const repo of displayedRepos) {
|
|
26438
26563
|
const versions = repo.versions.join(", ");
|
|
26439
26564
|
console.log(`${repo.fullName} (${versions})`);
|
|
26440
26565
|
}
|
|
@@ -26442,6 +26567,16 @@ async function runDependencyFilter(organizationId, options) {
|
|
|
26442
26567
|
function createListCommand2() {
|
|
26443
26568
|
return addRepositoryFilterOptions(
|
|
26444
26569
|
new Command("list").description("List repositories in your organization")
|
|
26570
|
+
).addHelpText(
|
|
26571
|
+
"after",
|
|
26572
|
+
`
|
|
26573
|
+
Examples:
|
|
26574
|
+
tracecli repo list
|
|
26575
|
+
tracecli repo list --platform GITHUB --status CONNECTED
|
|
26576
|
+
tracecli repo list --output json | jq '.[].repositoryUrl'
|
|
26577
|
+
tracecli repo list --output tsv | cut -f1
|
|
26578
|
+
tracecli repo list --filter "language:typescript" --limit 10
|
|
26579
|
+
tracecli repo list --dependency lodash@4.17.21`
|
|
26445
26580
|
).action(async (options) => {
|
|
26446
26581
|
await runRepositoryListCommand(options);
|
|
26447
26582
|
});
|
|
@@ -26449,6 +26584,12 @@ function createListCommand2() {
|
|
|
26449
26584
|
function createFilterCommand() {
|
|
26450
26585
|
return addRepositoryFilterOptions(
|
|
26451
26586
|
new Command("filter").description("Filter repositories in your organization")
|
|
26587
|
+
).addHelpText(
|
|
26588
|
+
"after",
|
|
26589
|
+
`
|
|
26590
|
+
Examples:
|
|
26591
|
+
tracecli repo filter --filter "platform=GITHUB" --filter "status=CONNECTED"
|
|
26592
|
+
tracecli repo filter --language typescript --output json`
|
|
26452
26593
|
).action(async (options) => {
|
|
26453
26594
|
await runRepositoryListCommand(options);
|
|
26454
26595
|
});
|
|
@@ -26570,8 +26711,8 @@ function createRepoCommand() {
|
|
|
26570
26711
|
}
|
|
26571
26712
|
|
|
26572
26713
|
// src/vulnerabilities/commands.ts
|
|
26573
|
-
var
|
|
26574
|
-
var
|
|
26714
|
+
var DEFAULT_LIMIT3 = 30;
|
|
26715
|
+
var MAX_LIMIT3 = 100;
|
|
26575
26716
|
async function resolveRepositoryIdAuthenticated(organizationId, repoIdentifier) {
|
|
26576
26717
|
const result = await authenticatedRequest(
|
|
26577
26718
|
(client) => client.repository.listRepositories({
|
|
@@ -26680,13 +26821,13 @@ function createListCommand3() {
|
|
|
26680
26821
|
(value) => value.toUpperCase()
|
|
26681
26822
|
).option(
|
|
26682
26823
|
"-L, --limit <n>",
|
|
26683
|
-
`Max results to return (default: ${
|
|
26824
|
+
`Max results to return (default: ${DEFAULT_LIMIT3}, max: ${MAX_LIMIT3})`,
|
|
26684
26825
|
(v) => {
|
|
26685
26826
|
const n = Number.parseInt(v, 10);
|
|
26686
26827
|
if (Number.isNaN(n) || n < 1) {
|
|
26687
26828
|
throw new Error("--limit must be a positive integer");
|
|
26688
26829
|
}
|
|
26689
|
-
return Math.min(n,
|
|
26830
|
+
return Math.min(n, MAX_LIMIT3);
|
|
26690
26831
|
}
|
|
26691
26832
|
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
26692
26833
|
"after",
|
|
@@ -26717,7 +26858,7 @@ Examples:
|
|
|
26717
26858
|
sortBy: "severity",
|
|
26718
26859
|
sortOrder: "desc"
|
|
26719
26860
|
};
|
|
26720
|
-
const limit = options.limit ??
|
|
26861
|
+
const limit = options.limit ?? DEFAULT_LIMIT3;
|
|
26721
26862
|
const isJson = options.output === "json";
|
|
26722
26863
|
const isTsv = options.output === "tsv";
|
|
26723
26864
|
const collected = [];
|