securewithtrace 0.20.2 → 0.20.3
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 +108 -12
- 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(
|
|
@@ -26531,6 +26557,10 @@ function isSafeOrganizationId(organizationId) {
|
|
|
26531
26557
|
}
|
|
26532
26558
|
async function fetchOrganizationContext() {
|
|
26533
26559
|
const result = await authenticatedRequest((client) => client.organization.listMyOrganizations());
|
|
26560
|
+
if (result.status === 401) {
|
|
26561
|
+
console.error("Authentication failed. Run `tracecli auth login` to re-authenticate.");
|
|
26562
|
+
process.exit(1);
|
|
26563
|
+
}
|
|
26534
26564
|
if (result.status !== 200) {
|
|
26535
26565
|
console.error(`Failed to list organizations (status ${result.status}).`);
|
|
26536
26566
|
process.exit(1);
|
|
@@ -26857,22 +26887,30 @@ Examples:
|
|
|
26857
26887
|
});
|
|
26858
26888
|
}
|
|
26859
26889
|
function createOrgListCommand() {
|
|
26860
|
-
return new Command("list").description("List organizations available to your account").option("-o, --output <format>", "Output format: table (default), json, tsv").
|
|
26890
|
+
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) => {
|
|
26891
|
+
const n = Number.parseInt(v, 10);
|
|
26892
|
+
if (Number.isNaN(n) || n < 1) {
|
|
26893
|
+
throw new Error("--limit must be a positive integer");
|
|
26894
|
+
}
|
|
26895
|
+
return n;
|
|
26896
|
+
}).addHelpText(
|
|
26861
26897
|
"after",
|
|
26862
26898
|
`
|
|
26863
26899
|
Examples:
|
|
26864
26900
|
tracecli org list
|
|
26865
26901
|
tracecli org list --output json
|
|
26866
|
-
tracecli org list --output tsv | cut -f1
|
|
26902
|
+
tracecli org list --output tsv | cut -f1
|
|
26903
|
+
tracecli org list --limit 5`
|
|
26867
26904
|
).action(async (options) => {
|
|
26868
26905
|
const organizationContext = await fetchOrganizationContext();
|
|
26869
|
-
const
|
|
26906
|
+
const allItems = organizationContext.organizations.map(
|
|
26870
26907
|
(organization) => ({
|
|
26871
26908
|
...organization,
|
|
26872
26909
|
active: organization.organizationId === organizationContext.activeOrganization.organizationId,
|
|
26873
26910
|
selected: organization.organizationId === organizationContext.selectedOrganizationId
|
|
26874
26911
|
})
|
|
26875
26912
|
);
|
|
26913
|
+
const items = options.limit !== void 0 ? allItems.slice(0, options.limit) : allItems;
|
|
26876
26914
|
if (options.output === "json") {
|
|
26877
26915
|
console.log(JSON.stringify(items, null, 2));
|
|
26878
26916
|
return;
|
|
@@ -26891,15 +26929,27 @@ Examples:
|
|
|
26891
26929
|
}
|
|
26892
26930
|
return;
|
|
26893
26931
|
}
|
|
26894
|
-
|
|
26895
|
-
|
|
26932
|
+
const headers = ["", "Name", "Slug", "Org ID"];
|
|
26933
|
+
const rows = items.map((item) => {
|
|
26896
26934
|
const labels = [item.active ? "active" : null, item.selected ? "selected" : null].filter(
|
|
26897
26935
|
Boolean
|
|
26898
26936
|
);
|
|
26899
|
-
const
|
|
26900
|
-
|
|
26901
|
-
|
|
26902
|
-
|
|
26937
|
+
const marker = item.active ? "*" : " ";
|
|
26938
|
+
const nameSuffix = labels.length > 0 ? ` [${labels.join(", ")}]` : "";
|
|
26939
|
+
return [
|
|
26940
|
+
marker,
|
|
26941
|
+
sanitizeForOutput(item.name) + nameSuffix,
|
|
26942
|
+
sanitizeForOutput(item.slug),
|
|
26943
|
+
item.organizationId
|
|
26944
|
+
];
|
|
26945
|
+
});
|
|
26946
|
+
const colWidths = headers.map(
|
|
26947
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length))
|
|
26948
|
+
);
|
|
26949
|
+
const pad = (s, w3) => s.padEnd(w3);
|
|
26950
|
+
console.log(headers.map((h, i) => pad(h, colWidths[i] ?? h.length)).join(" "));
|
|
26951
|
+
for (const row of rows) {
|
|
26952
|
+
console.log(row.map((cell, i) => pad(cell, colWidths[i] ?? 0)).join(" "));
|
|
26903
26953
|
}
|
|
26904
26954
|
if (organizationContext.staleSelectionDetected) {
|
|
26905
26955
|
console.log("\nYour previous organization selection is no longer available and was reset.");
|
|
@@ -27727,6 +27777,41 @@ function createPentestCommand() {
|
|
|
27727
27777
|
import { chmodSync, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
27728
27778
|
import { tmpdir } from "os";
|
|
27729
27779
|
import { join as join4 } from "path";
|
|
27780
|
+
|
|
27781
|
+
// src/browser.ts
|
|
27782
|
+
var DEFAULT_APP_BASE_URL = "https://app.securewithtrace.com";
|
|
27783
|
+
function getAppBaseUrl() {
|
|
27784
|
+
const override = process.env["TRACE_APP_URL"];
|
|
27785
|
+
if (typeof override === "string" && override.trim().length > 0) {
|
|
27786
|
+
try {
|
|
27787
|
+
const parsed = new URL(override);
|
|
27788
|
+
if (parsed.protocol === "https:") {
|
|
27789
|
+
return override.replace(/\/+$/, "");
|
|
27790
|
+
}
|
|
27791
|
+
} catch {
|
|
27792
|
+
}
|
|
27793
|
+
}
|
|
27794
|
+
return DEFAULT_APP_BASE_URL;
|
|
27795
|
+
}
|
|
27796
|
+
async function openBrowser2(url2) {
|
|
27797
|
+
try {
|
|
27798
|
+
const parsed = new URL(url2);
|
|
27799
|
+
if (parsed.protocol !== "https:") {
|
|
27800
|
+
return false;
|
|
27801
|
+
}
|
|
27802
|
+
const proc = Bun.spawn(["open", url2], { stdout: "ignore", stderr: "ignore" });
|
|
27803
|
+
const exitCode = await proc.exited;
|
|
27804
|
+
if (exitCode !== 0) {
|
|
27805
|
+
const linuxProc = Bun.spawn(["xdg-open", url2], { stdout: "ignore", stderr: "ignore" });
|
|
27806
|
+
return await linuxProc.exited === 0;
|
|
27807
|
+
}
|
|
27808
|
+
return true;
|
|
27809
|
+
} catch {
|
|
27810
|
+
return false;
|
|
27811
|
+
}
|
|
27812
|
+
}
|
|
27813
|
+
|
|
27814
|
+
// src/repo/commands.ts
|
|
27730
27815
|
function stripAnsi(str) {
|
|
27731
27816
|
const ESC2 = String.fromCharCode(27);
|
|
27732
27817
|
const CSI2 = String.fromCharCode(155);
|
|
@@ -28153,9 +28238,18 @@ function addRepositoryFilterOptions(command) {
|
|
|
28153
28238
|
).option(
|
|
28154
28239
|
"--dependency <pkg>",
|
|
28155
28240
|
"Filter repositories that use a dependency (e.g. lodash, lodash@4.17.21, @types/node@20)"
|
|
28156
|
-
);
|
|
28241
|
+
).option("-w, --web", "Open the repositories dashboard in a browser");
|
|
28157
28242
|
}
|
|
28158
28243
|
async function runRepositoryListCommand(options) {
|
|
28244
|
+
if (options.web) {
|
|
28245
|
+
const slug = await resolveOrganizationSlug();
|
|
28246
|
+
const url2 = `${getAppBaseUrl()}/dashboard/${slug}/repositories`;
|
|
28247
|
+
const opened = await openBrowser2(url2);
|
|
28248
|
+
if (!opened) {
|
|
28249
|
+
console.log(`Open in browser: ${url2}`);
|
|
28250
|
+
}
|
|
28251
|
+
return;
|
|
28252
|
+
}
|
|
28159
28253
|
const organizationId = await resolveOrganizationId();
|
|
28160
28254
|
if (options.dependency) {
|
|
28161
28255
|
await runDependencyFilter(organizationId, {
|
|
@@ -28287,7 +28381,8 @@ Examples:
|
|
|
28287
28381
|
tracecli repo list --output json | jq '.[].repositoryUrl'
|
|
28288
28382
|
tracecli repo list --output tsv | cut -f1
|
|
28289
28383
|
tracecli repo list --filter "language:typescript" --limit 10
|
|
28290
|
-
tracecli repo list --dependency lodash@4.17.21
|
|
28384
|
+
tracecli repo list --dependency lodash@4.17.21
|
|
28385
|
+
tracecli repo list --web`
|
|
28291
28386
|
).action(async (options) => {
|
|
28292
28387
|
await runRepositoryListCommand(options);
|
|
28293
28388
|
});
|
|
@@ -28300,7 +28395,8 @@ function createFilterCommand() {
|
|
|
28300
28395
|
`
|
|
28301
28396
|
Examples:
|
|
28302
28397
|
tracecli repo filter --filter "platform=GITHUB" --filter "status=CONNECTED"
|
|
28303
|
-
tracecli repo filter --language typescript --output json
|
|
28398
|
+
tracecli repo filter --language typescript --output json
|
|
28399
|
+
tracecli repo filter --web`
|
|
28304
28400
|
).action(async (options) => {
|
|
28305
28401
|
await runRepositoryListCommand(options);
|
|
28306
28402
|
});
|