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.
Files changed (2) hide show
  1. package/dist/index.js +108 -12
  2. 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").addHelpText(
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 items = organizationContext.organizations.map(
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
- for (const item of items) {
26895
- const marker = item.active ? "*" : " ";
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 suffix = labels.length > 0 ? ` [${labels.join(", ")}]` : "";
26900
- console.log(
26901
- `${marker} ${sanitizeForOutput(item.name)} (${sanitizeForOutput(item.slug)}) - ${item.organizationId}${suffix}`
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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securewithtrace",
3
- "version": "0.20.2",
3
+ "version": "0.20.3",
4
4
  "description": "Official Trace CLI for vulnerability intelligence in your terminal",
5
5
  "type": "module",
6
6
  "bin": {