securewithtrace 0.3.0 → 0.4.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.
Files changed (2) hide show
  1. package/dist/index.js +195 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23985,12 +23985,11 @@ function createCloneCommand() {
23985
23985
  }
23986
23986
  args.push("--", effectiveUrl, targetDir);
23987
23987
  console.log(`Cloning ${cloneUrl} into ${targetDir}...`);
23988
- const extraEnv = {
23989
- GIT_TERMINAL_PROMPT: "0"
23990
- };
23988
+ const extraEnv = {};
23991
23989
  if (installationToken) {
23992
23990
  askPassScript = createAskPassScript(installationToken);
23993
23991
  extraEnv["GIT_ASKPASS"] = askPassScript;
23992
+ extraEnv["GIT_TERMINAL_PROMPT"] = "0";
23994
23993
  }
23995
23994
  try {
23996
23995
  const proc = Bun.spawn(["git", ...args], {
@@ -24031,6 +24030,198 @@ function createRepoCommand() {
24031
24030
  return repo;
24032
24031
  }
24033
24032
 
24033
+ // src/vulnerabilities/commands.ts
24034
+ import { createInterface } from "readline";
24035
+ var SEVERITY_ORDER = {
24036
+ CRITICAL: 0,
24037
+ HIGH: 1,
24038
+ MEDIUM: 2,
24039
+ LOW: 3
24040
+ };
24041
+ var DEFAULT_PAGE_SIZE = 25;
24042
+ async function resolveRepositoryId(client, organizationId, repoIdentifier) {
24043
+ const result = await client.repository.listRepositories({
24044
+ params: { organizationId }
24045
+ });
24046
+ if (result.status !== 200) {
24047
+ console.error(`Failed to list repositories (status ${result.status}).`);
24048
+ process.exit(1);
24049
+ }
24050
+ const repos = result.body;
24051
+ const match = repos.find((r) => {
24052
+ const url2 = r.repositoryUrl;
24053
+ if (url2.endsWith(`/${repoIdentifier}`)) {
24054
+ return true;
24055
+ }
24056
+ if (url2.endsWith(`/${repoIdentifier}.git`)) {
24057
+ return true;
24058
+ }
24059
+ if (url2 === repoIdentifier) {
24060
+ return true;
24061
+ }
24062
+ return false;
24063
+ });
24064
+ if (match) {
24065
+ return match.repositoryId;
24066
+ }
24067
+ const byName = repos.filter((r) => {
24068
+ const segments = r.repositoryUrl.replace(/\.git$/, "").split("/");
24069
+ const name = segments[segments.length - 1];
24070
+ return name === repoIdentifier;
24071
+ });
24072
+ if (byName.length === 1 && byName[0]) {
24073
+ return byName[0].repositoryId;
24074
+ }
24075
+ if (byName.length > 1) {
24076
+ console.error(
24077
+ `Ambiguous repository name '${repoIdentifier}'. Multiple matches found:
24078
+ ${byName.map((r) => ` - ${r.repositoryUrl}`).join("\n")}
24079
+ Please use the full owner/repo format.`
24080
+ );
24081
+ process.exit(1);
24082
+ }
24083
+ console.error(
24084
+ `Repository '${repoIdentifier}' not found.
24085
+ Run \`tracecli repo list\` to see available repositories.`
24086
+ );
24087
+ process.exit(1);
24088
+ }
24089
+ function formatSeverity(severity) {
24090
+ switch (severity) {
24091
+ case "CRITICAL":
24092
+ return "CRIT";
24093
+ case "HIGH":
24094
+ return "HIGH";
24095
+ case "MEDIUM":
24096
+ return "MED";
24097
+ case "LOW":
24098
+ return "LOW";
24099
+ default:
24100
+ return severity;
24101
+ }
24102
+ }
24103
+ function printVulnerabilities(vulnerabilities) {
24104
+ const sorted = [...vulnerabilities].sort(
24105
+ (a, b) => (SEVERITY_ORDER[a.severity] ?? 99) - (SEVERITY_ORDER[b.severity] ?? 99)
24106
+ );
24107
+ for (const vuln of sorted) {
24108
+ const sev = formatSeverity(vuln.severity);
24109
+ const status = vuln.status.toLowerCase().replace("_", " ");
24110
+ const repo = vuln.repositoryName;
24111
+ const file2 = vuln.codeSnippet.filePath;
24112
+ const line = vuln.codeSnippet.startLine;
24113
+ console.log(` [${sev}] ${vuln.title}`);
24114
+ console.log(` ${repo} \xB7 ${file2}:${line} \xB7 ${status}`);
24115
+ console.log(` ${vuln.traceId}`);
24116
+ console.log("");
24117
+ }
24118
+ }
24119
+ async function promptContinue(displayed, total) {
24120
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
24121
+ return new Promise((resolve) => {
24122
+ rl.question(`Showing ${displayed} of ${total}. Show more? [Y/n] `, (answer) => {
24123
+ rl.close();
24124
+ const trimmed = answer.trim().toLowerCase();
24125
+ resolve(trimmed === "" || trimmed === "y" || trimmed === "yes");
24126
+ });
24127
+ });
24128
+ }
24129
+ function createListCommand2() {
24130
+ return new Command("list").description("List vulnerabilities for your organization").option("--repo <repo>", "Filter by repository name or owner/repo").option(
24131
+ "--severity <severity>",
24132
+ "Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)",
24133
+ (value) => value.toUpperCase()
24134
+ ).option(
24135
+ "--status <status>",
24136
+ "Filter by status (OPEN, IN_PROGRESS, FIXED, IGNORED, FALSE_POSITIVE)",
24137
+ (value) => value.toUpperCase()
24138
+ ).option("--page-size <size>", "Number of results per page", (v) => {
24139
+ const n = Number.parseInt(v, 10);
24140
+ if (Number.isNaN(n) || n < 1) {
24141
+ throw new Error("--page-size must be a positive integer");
24142
+ }
24143
+ return Math.min(n, 200);
24144
+ }).option("--json", "Output as JSON").action(
24145
+ async (options) => {
24146
+ const { token } = requireAuth();
24147
+ const client = createClient(token);
24148
+ const organizationId = await resolveOrganizationId(client);
24149
+ const conditions = [];
24150
+ if (options.repo) {
24151
+ const repositoryId = await resolveRepositoryId(client, organizationId, options.repo);
24152
+ conditions.push({ field: "repositoryId", operator: "eq", value: repositoryId });
24153
+ }
24154
+ if (options.severity) {
24155
+ conditions.push({ field: "severity", operator: "eq", value: options.severity });
24156
+ }
24157
+ if (options.status) {
24158
+ conditions.push({ field: "status", operator: "eq", value: options.status });
24159
+ }
24160
+ const filterBody = {
24161
+ filters: conditions.length > 0 ? { operator: "and", conditions } : void 0,
24162
+ defaultBranchOnly: true,
24163
+ sortBy: "severity",
24164
+ sortOrder: "desc"
24165
+ };
24166
+ const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;
24167
+ let page = 1;
24168
+ let totalDisplayed = 0;
24169
+ let total = 0;
24170
+ const allJsonVulnerabilities = [];
24171
+ while (true) {
24172
+ const result = await client.vulnerability.filterVulnerabilities({
24173
+ params: { organizationId },
24174
+ body: { ...filterBody, page, pageSize }
24175
+ });
24176
+ if (result.status !== 200) {
24177
+ console.error(`Failed to list vulnerabilities (status ${result.status}).`);
24178
+ process.exit(1);
24179
+ }
24180
+ total = result.body.total;
24181
+ const vulnerabilities = result.body.statusGroups.flatMap((g) => g.vulnerabilities);
24182
+ if (page === 1 && vulnerabilities.length === 0) {
24183
+ if (options.json) {
24184
+ console.log("[]");
24185
+ } else {
24186
+ console.log("No vulnerabilities found.");
24187
+ }
24188
+ return;
24189
+ }
24190
+ if (options.json) {
24191
+ allJsonVulnerabilities.push(...vulnerabilities);
24192
+ } else {
24193
+ if (page === 1) {
24194
+ console.log(`Found ${total} vulnerabilit${total === 1 ? "y" : "ies"}:
24195
+ `);
24196
+ }
24197
+ printVulnerabilities(vulnerabilities);
24198
+ }
24199
+ totalDisplayed += vulnerabilities.length;
24200
+ if (totalDisplayed >= total || vulnerabilities.length < pageSize) {
24201
+ break;
24202
+ }
24203
+ if (options.json) {
24204
+ page++;
24205
+ continue;
24206
+ }
24207
+ const wantMore = await promptContinue(totalDisplayed, total);
24208
+ if (!wantMore) {
24209
+ break;
24210
+ }
24211
+ page++;
24212
+ }
24213
+ if (options.json) {
24214
+ console.log(JSON.stringify(allJsonVulnerabilities, null, 2));
24215
+ }
24216
+ }
24217
+ );
24218
+ }
24219
+ function createVulnerabilitiesCommand() {
24220
+ const vulnerabilities = new Command("vulnerabilities").description("Manage vulnerabilities");
24221
+ vulnerabilities.addCommand(createListCommand2());
24222
+ return vulnerabilities;
24223
+ }
24224
+
24034
24225
  // src/index.ts
24035
24226
  var program2 = new Command();
24036
24227
  program2.name("tracecli").description("Trace CLI").version("0.0.1");
@@ -24039,4 +24230,5 @@ program2.command("echo").description("Echo a message back to the terminal").argu
24039
24230
  });
24040
24231
  program2.addCommand(createAuthCommand());
24041
24232
  program2.addCommand(createRepoCommand());
24233
+ program2.addCommand(createVulnerabilitiesCommand());
24042
24234
  program2.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securewithtrace",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Trace CLI",
5
5
  "type": "module",
6
6
  "bin": {