securewithtrace 0.20.2 → 0.21.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 +128 -37
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26412,6 +26412,32 @@ async function resolveOrganizationId(client) {
|
|
|
26412
26412
|
}
|
|
26413
26413
|
return id;
|
|
26414
26414
|
}
|
|
26415
|
+
async function resolveOrganizationSlug() {
|
|
26416
|
+
const result = await authenticatedRequest((client) => client.organization.listMyOrganizations());
|
|
26417
|
+
if (result.status === 401) {
|
|
26418
|
+
console.error(
|
|
26419
|
+
colorError("Authentication failed. Run `tracecli auth login` to re-authenticate.")
|
|
26420
|
+
);
|
|
26421
|
+
process.exit(1);
|
|
26422
|
+
}
|
|
26423
|
+
if (result.status !== 200) {
|
|
26424
|
+
console.error(colorError(`Failed to resolve organization (status ${result.status}).`));
|
|
26425
|
+
process.exit(1);
|
|
26426
|
+
}
|
|
26427
|
+
const organizations = result.body;
|
|
26428
|
+
const selectedOrganizationId = readSelectedOrganizationId();
|
|
26429
|
+
const tokenOrganizationId = extractOrganizationIdFromToken(readToken());
|
|
26430
|
+
const activeOrganization = determineActiveOrganization(
|
|
26431
|
+
organizations,
|
|
26432
|
+
selectedOrganizationId,
|
|
26433
|
+
tokenOrganizationId
|
|
26434
|
+
);
|
|
26435
|
+
if (!activeOrganization) {
|
|
26436
|
+
console.error(colorError("No organization found for your account."));
|
|
26437
|
+
process.exit(1);
|
|
26438
|
+
}
|
|
26439
|
+
return activeOrganization.organization.slug;
|
|
26440
|
+
}
|
|
26415
26441
|
async function resolveOrganizationIdSafe(client) {
|
|
26416
26442
|
try {
|
|
26417
26443
|
const result = client ? await client.organization.listMyOrganizations() : await authenticatedRequestSafe(
|
|
@@ -26450,6 +26476,39 @@ async function resolveOrganizationIdSafe(client) {
|
|
|
26450
26476
|
}
|
|
26451
26477
|
}
|
|
26452
26478
|
|
|
26479
|
+
// src/browser.ts
|
|
26480
|
+
var DEFAULT_APP_BASE_URL = "https://app.securewithtrace.com";
|
|
26481
|
+
function getAppBaseUrl() {
|
|
26482
|
+
const override = process.env["TRACE_APP_URL"];
|
|
26483
|
+
if (typeof override === "string" && override.trim().length > 0) {
|
|
26484
|
+
try {
|
|
26485
|
+
const parsed = new URL(override);
|
|
26486
|
+
if (parsed.protocol === "https:") {
|
|
26487
|
+
return override.replace(/\/+$/, "");
|
|
26488
|
+
}
|
|
26489
|
+
} catch {
|
|
26490
|
+
}
|
|
26491
|
+
}
|
|
26492
|
+
return DEFAULT_APP_BASE_URL;
|
|
26493
|
+
}
|
|
26494
|
+
async function openBrowser(url2) {
|
|
26495
|
+
try {
|
|
26496
|
+
const parsed = new URL(url2);
|
|
26497
|
+
if (parsed.protocol !== "https:") {
|
|
26498
|
+
return false;
|
|
26499
|
+
}
|
|
26500
|
+
const proc = Bun.spawn(["open", url2], { stdout: "ignore", stderr: "ignore" });
|
|
26501
|
+
const exitCode = await proc.exited;
|
|
26502
|
+
if (exitCode !== 0) {
|
|
26503
|
+
const linuxProc = Bun.spawn(["xdg-open", url2], { stdout: "ignore", stderr: "ignore" });
|
|
26504
|
+
return await linuxProc.exited === 0;
|
|
26505
|
+
}
|
|
26506
|
+
return true;
|
|
26507
|
+
} catch {
|
|
26508
|
+
return false;
|
|
26509
|
+
}
|
|
26510
|
+
}
|
|
26511
|
+
|
|
26453
26512
|
// src/format.ts
|
|
26454
26513
|
var SEVERITY_ORDER = {
|
|
26455
26514
|
CRITICAL: 0,
|
|
@@ -26475,29 +26534,6 @@ function getClientId() {
|
|
|
26475
26534
|
"TRACE_WORKOS_CLIENT_ID is not set. Build the CLI with TRACE_WORKOS_CLIENT_ID set, or provide it as an environment variable."
|
|
26476
26535
|
);
|
|
26477
26536
|
}
|
|
26478
|
-
async function openBrowser(url2) {
|
|
26479
|
-
try {
|
|
26480
|
-
const parsed = new URL(url2);
|
|
26481
|
-
if (parsed.protocol !== "https:") {
|
|
26482
|
-
return false;
|
|
26483
|
-
}
|
|
26484
|
-
const proc = Bun.spawn(["open", url2], {
|
|
26485
|
-
stdout: "ignore",
|
|
26486
|
-
stderr: "ignore"
|
|
26487
|
-
});
|
|
26488
|
-
const exitCode = await proc.exited;
|
|
26489
|
-
if (exitCode !== 0) {
|
|
26490
|
-
const linuxProc = Bun.spawn(["xdg-open", url2], {
|
|
26491
|
-
stdout: "ignore",
|
|
26492
|
-
stderr: "ignore"
|
|
26493
|
-
});
|
|
26494
|
-
return await linuxProc.exited === 0;
|
|
26495
|
-
}
|
|
26496
|
-
return true;
|
|
26497
|
-
} catch {
|
|
26498
|
-
return false;
|
|
26499
|
-
}
|
|
26500
|
-
}
|
|
26501
26537
|
var SAFE_ORGANIZATION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
26502
26538
|
function sanitizeForOutput(value) {
|
|
26503
26539
|
return value.replace(/[\r\n\t]/g, " ").trim();
|
|
@@ -26531,6 +26567,10 @@ function isSafeOrganizationId(organizationId) {
|
|
|
26531
26567
|
}
|
|
26532
26568
|
async function fetchOrganizationContext() {
|
|
26533
26569
|
const result = await authenticatedRequest((client) => client.organization.listMyOrganizations());
|
|
26570
|
+
if (result.status === 401) {
|
|
26571
|
+
console.error("Authentication failed. Run `tracecli auth login` to re-authenticate.");
|
|
26572
|
+
process.exit(1);
|
|
26573
|
+
}
|
|
26534
26574
|
if (result.status !== 200) {
|
|
26535
26575
|
console.error(`Failed to list organizations (status ${result.status}).`);
|
|
26536
26576
|
process.exit(1);
|
|
@@ -26857,22 +26897,40 @@ Examples:
|
|
|
26857
26897
|
});
|
|
26858
26898
|
}
|
|
26859
26899
|
function createOrgListCommand() {
|
|
26860
|
-
return new Command("list").description("List organizations available to your account").option("-o, --output <format>", "Output format: table (default), json, tsv").
|
|
26900
|
+
return new Command("list").description("List organizations available to your account").option("-o, --output <format>", "Output format: table (default), json, tsv").option("-L, --limit <n>", "Max organizations to display (default: all)", (v) => {
|
|
26901
|
+
const n = Number.parseInt(v, 10);
|
|
26902
|
+
if (Number.isNaN(n) || n < 1) {
|
|
26903
|
+
throw new Error("--limit must be a positive integer");
|
|
26904
|
+
}
|
|
26905
|
+
return n;
|
|
26906
|
+
}).option("-w, --web", "Open the organization settings in a browser").addHelpText(
|
|
26861
26907
|
"after",
|
|
26862
26908
|
`
|
|
26863
26909
|
Examples:
|
|
26864
26910
|
tracecli org list
|
|
26865
26911
|
tracecli org list --output json
|
|
26866
|
-
tracecli org list --output tsv | cut -f1
|
|
26912
|
+
tracecli org list --output tsv | cut -f1
|
|
26913
|
+
tracecli org list --limit 5
|
|
26914
|
+
tracecli org list --web`
|
|
26867
26915
|
).action(async (options) => {
|
|
26916
|
+
if (options.web) {
|
|
26917
|
+
const slug = await resolveOrganizationSlug();
|
|
26918
|
+
const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings`;
|
|
26919
|
+
const opened = await openBrowser(url2);
|
|
26920
|
+
if (!opened) {
|
|
26921
|
+
console.log(`Open in browser: ${url2}`);
|
|
26922
|
+
}
|
|
26923
|
+
return;
|
|
26924
|
+
}
|
|
26868
26925
|
const organizationContext = await fetchOrganizationContext();
|
|
26869
|
-
const
|
|
26926
|
+
const allItems = organizationContext.organizations.map(
|
|
26870
26927
|
(organization) => ({
|
|
26871
26928
|
...organization,
|
|
26872
26929
|
active: organization.organizationId === organizationContext.activeOrganization.organizationId,
|
|
26873
26930
|
selected: organization.organizationId === organizationContext.selectedOrganizationId
|
|
26874
26931
|
})
|
|
26875
26932
|
);
|
|
26933
|
+
const items = options.limit !== void 0 ? allItems.slice(0, options.limit) : allItems;
|
|
26876
26934
|
if (options.output === "json") {
|
|
26877
26935
|
console.log(JSON.stringify(items, null, 2));
|
|
26878
26936
|
return;
|
|
@@ -26891,15 +26949,27 @@ Examples:
|
|
|
26891
26949
|
}
|
|
26892
26950
|
return;
|
|
26893
26951
|
}
|
|
26894
|
-
|
|
26895
|
-
|
|
26952
|
+
const headers = ["", "Name", "Slug", "Org ID"];
|
|
26953
|
+
const rows = items.map((item) => {
|
|
26896
26954
|
const labels = [item.active ? "active" : null, item.selected ? "selected" : null].filter(
|
|
26897
26955
|
Boolean
|
|
26898
26956
|
);
|
|
26899
|
-
const
|
|
26900
|
-
|
|
26901
|
-
|
|
26902
|
-
|
|
26957
|
+
const marker = item.active ? "*" : " ";
|
|
26958
|
+
const nameSuffix = labels.length > 0 ? ` [${labels.join(", ")}]` : "";
|
|
26959
|
+
return [
|
|
26960
|
+
marker,
|
|
26961
|
+
sanitizeForOutput(item.name) + nameSuffix,
|
|
26962
|
+
sanitizeForOutput(item.slug),
|
|
26963
|
+
item.organizationId
|
|
26964
|
+
];
|
|
26965
|
+
});
|
|
26966
|
+
const colWidths = headers.map(
|
|
26967
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length))
|
|
26968
|
+
);
|
|
26969
|
+
const pad = (s, w3) => s.padEnd(w3);
|
|
26970
|
+
console.log(headers.map((h, i) => pad(h, colWidths[i] ?? h.length)).join(" "));
|
|
26971
|
+
for (const row of rows) {
|
|
26972
|
+
console.log(row.map((cell, i) => pad(cell, colWidths[i] ?? 0)).join(" "));
|
|
26903
26973
|
}
|
|
26904
26974
|
if (organizationContext.staleSelectionDetected) {
|
|
26905
26975
|
console.log("\nYour previous organization selection is no longer available and was reset.");
|
|
@@ -26907,14 +26977,24 @@ Examples:
|
|
|
26907
26977
|
});
|
|
26908
26978
|
}
|
|
26909
26979
|
function createOrgCurrentCommand() {
|
|
26910
|
-
return new Command("current").description("Show the active organization used by CLI commands").option("-o, --output <format>", "Output format: table (default), json, tsv").addHelpText(
|
|
26980
|
+
return new Command("current").description("Show the active organization used by CLI commands").option("-o, --output <format>", "Output format: table (default), json, tsv").option("-w, --web", "Open the organization settings in a browser").addHelpText(
|
|
26911
26981
|
"after",
|
|
26912
26982
|
`
|
|
26913
26983
|
Examples:
|
|
26914
26984
|
tracecli org current
|
|
26915
26985
|
tracecli org current --output json
|
|
26916
|
-
tracecli org current --output tsv
|
|
26986
|
+
tracecli org current --output tsv
|
|
26987
|
+
tracecli org current --web`
|
|
26917
26988
|
).action(async (options) => {
|
|
26989
|
+
if (options.web) {
|
|
26990
|
+
const slug = await resolveOrganizationSlug();
|
|
26991
|
+
const url2 = `${getAppBaseUrl()}/dashboard/${slug}/settings`;
|
|
26992
|
+
const opened = await openBrowser(url2);
|
|
26993
|
+
if (!opened) {
|
|
26994
|
+
console.log(`Open in browser: ${url2}`);
|
|
26995
|
+
}
|
|
26996
|
+
return;
|
|
26997
|
+
}
|
|
26918
26998
|
const organizationContext = await fetchOrganizationContext();
|
|
26919
26999
|
const active = organizationContext.activeOrganization;
|
|
26920
27000
|
const source = organizationContext.selectedOrganizationId === active.organizationId ? "selected" : "default";
|
|
@@ -28153,9 +28233,18 @@ function addRepositoryFilterOptions(command) {
|
|
|
28153
28233
|
).option(
|
|
28154
28234
|
"--dependency <pkg>",
|
|
28155
28235
|
"Filter repositories that use a dependency (e.g. lodash, lodash@4.17.21, @types/node@20)"
|
|
28156
|
-
);
|
|
28236
|
+
).option("-w, --web", "Open the repositories dashboard in a browser");
|
|
28157
28237
|
}
|
|
28158
28238
|
async function runRepositoryListCommand(options) {
|
|
28239
|
+
if (options.web) {
|
|
28240
|
+
const slug = await resolveOrganizationSlug();
|
|
28241
|
+
const url2 = `${getAppBaseUrl()}/dashboard/${slug}/repositories`;
|
|
28242
|
+
const opened = await openBrowser(url2);
|
|
28243
|
+
if (!opened) {
|
|
28244
|
+
console.log(`Open in browser: ${url2}`);
|
|
28245
|
+
}
|
|
28246
|
+
return;
|
|
28247
|
+
}
|
|
28159
28248
|
const organizationId = await resolveOrganizationId();
|
|
28160
28249
|
if (options.dependency) {
|
|
28161
28250
|
await runDependencyFilter(organizationId, {
|
|
@@ -28287,7 +28376,8 @@ Examples:
|
|
|
28287
28376
|
tracecli repo list --output json | jq '.[].repositoryUrl'
|
|
28288
28377
|
tracecli repo list --output tsv | cut -f1
|
|
28289
28378
|
tracecli repo list --filter "language:typescript" --limit 10
|
|
28290
|
-
tracecli repo list --dependency lodash@4.17.21
|
|
28379
|
+
tracecli repo list --dependency lodash@4.17.21
|
|
28380
|
+
tracecli repo list --web`
|
|
28291
28381
|
).action(async (options) => {
|
|
28292
28382
|
await runRepositoryListCommand(options);
|
|
28293
28383
|
});
|
|
@@ -28300,7 +28390,8 @@ function createFilterCommand() {
|
|
|
28300
28390
|
`
|
|
28301
28391
|
Examples:
|
|
28302
28392
|
tracecli repo filter --filter "platform=GITHUB" --filter "status=CONNECTED"
|
|
28303
|
-
tracecli repo filter --language typescript --output json
|
|
28393
|
+
tracecli repo filter --language typescript --output json
|
|
28394
|
+
tracecli repo filter --web`
|
|
28304
28395
|
).action(async (options) => {
|
|
28305
28396
|
await runRepositoryListCommand(options);
|
|
28306
28397
|
});
|