securewithtrace 0.21.1 → 0.21.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/README.md +20 -1
- package/dist/index.js +70 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -129,6 +129,12 @@ tracecli vulnerabilities list --severity CRITICAL --status OPEN
|
|
|
129
129
|
# Increase result limit
|
|
130
130
|
tracecli vulnerabilities list --limit 100
|
|
131
131
|
|
|
132
|
+
# Filter by CWE ID
|
|
133
|
+
tracecli vulnerabilities list --filter cweId=CWE-89
|
|
134
|
+
|
|
135
|
+
# Filter by vulnerability type and scan mode (repeatable)
|
|
136
|
+
tracecli vulnerabilities list --filter vulnerabilityType=SAST --filter scanMode!=DAST
|
|
137
|
+
|
|
132
138
|
# JSON output for scripting
|
|
133
139
|
tracecli vulnerabilities list --output json | jq '.[].title'
|
|
134
140
|
|
|
@@ -146,6 +152,7 @@ Flags:
|
|
|
146
152
|
| `--repo <repo>` | | Filter by repository name or `owner/repo` |
|
|
147
153
|
| `--severity <level>` | | Filter by severity |
|
|
148
154
|
| `--status <status>` | | Filter by status |
|
|
155
|
+
| `--filter <expression>` | `-f` | Repeatable filter expression: `field=value` or `field!=value`. Supported fields: `repositoryId`, `severity`, `vulnerabilityType`, `status`, `cweId`, `scanMode` |
|
|
149
156
|
| `--limit <n>` | `-L` | Max results (default: 30, max: 100) |
|
|
150
157
|
| `--output <format>` | `-o` | Output format: `table` (default), `json`, `tsv` |
|
|
151
158
|
| `--web` | `-w` | Open vulnerabilities dashboard in browser |
|
|
@@ -179,6 +186,9 @@ tracecli pentest list --limit 50
|
|
|
179
186
|
# JSON output for scripting
|
|
180
187
|
tracecli pentest list --output json | jq '.[].title'
|
|
181
188
|
|
|
189
|
+
# Open pentests dashboard in browser
|
|
190
|
+
tracecli pentest list --web
|
|
191
|
+
|
|
182
192
|
# List findings for a pentest
|
|
183
193
|
tracecli pentest findings list --pentest PT-3
|
|
184
194
|
|
|
@@ -187,6 +197,9 @@ tracecli pentest findings list --pentest PT-3 --output json
|
|
|
187
197
|
|
|
188
198
|
# Findings as TSV
|
|
189
199
|
tracecli pentest findings list --pentest PT-3 --output tsv | cut -f1,4
|
|
200
|
+
|
|
201
|
+
# Open pentests dashboard in browser
|
|
202
|
+
tracecli pentest findings list --pentest PT-3 --web
|
|
190
203
|
```
|
|
191
204
|
|
|
192
205
|
Flags for `pentest list`:
|
|
@@ -195,6 +208,7 @@ Flags for `pentest list`:
|
|
|
195
208
|
|------|-----------|-------------|
|
|
196
209
|
| `--limit <n>` | `-L` | Max results (default: 30, max: 100) |
|
|
197
210
|
| `--output <format>` | `-o` | Output format: `table` (default), `json`, `tsv` |
|
|
211
|
+
| `--web` | `-w` | Open pentests dashboard in browser |
|
|
198
212
|
|
|
199
213
|
Flags for `pentest findings list`:
|
|
200
214
|
|
|
@@ -202,6 +216,7 @@ Flags for `pentest findings list`:
|
|
|
202
216
|
|------|-----------|-------------|
|
|
203
217
|
| `--pentest <id>` | | Pentest display ID (e.g. `PT-3`) or UUID (required) |
|
|
204
218
|
| `--output <format>` | `-o` | Output format: `table` (default), `json`, `tsv` |
|
|
219
|
+
| `--web` | `-w` | Open pentests dashboard in browser |
|
|
205
220
|
|
|
206
221
|
### Upgrades
|
|
207
222
|
|
|
@@ -214,6 +229,9 @@ tracecli upgrade --check
|
|
|
214
229
|
# Upgrade to the latest published CLI version
|
|
215
230
|
tracecli upgrade
|
|
216
231
|
|
|
232
|
+
# Non-interactive upgrade (CI/scripts)
|
|
233
|
+
tracecli upgrade --no-confirm
|
|
234
|
+
|
|
217
235
|
# Alias
|
|
218
236
|
tracecli self-update
|
|
219
237
|
```
|
|
@@ -223,7 +241,8 @@ Flags:
|
|
|
223
241
|
| Flag | Shorthand | Description |
|
|
224
242
|
|------|-----------|-------------|
|
|
225
243
|
| `--check` | | Check for updates without installing |
|
|
226
|
-
| `--
|
|
244
|
+
| `--no-confirm` | | Skip confirmation prompt (for CI/scripts) |
|
|
245
|
+
| `--yes` | `-y` | Skip confirmation prompt (alias: `--no-confirm`) |
|
|
227
246
|
|
|
228
247
|
## Security Notes
|
|
229
248
|
|
package/dist/index.js
CHANGED
|
@@ -27598,7 +27598,7 @@ function createListCommand() {
|
|
|
27598
27598
|
}
|
|
27599
27599
|
return Math.min(n, MAX_LIMIT);
|
|
27600
27600
|
}
|
|
27601
|
-
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
27601
|
+
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option("-w, --web", "Open the pentests dashboard in a browser").addHelpText(
|
|
27602
27602
|
"after",
|
|
27603
27603
|
`
|
|
27604
27604
|
Examples:
|
|
@@ -27606,8 +27606,18 @@ Examples:
|
|
|
27606
27606
|
tracecli pentest list --status IN_PROGRESS
|
|
27607
27607
|
tracecli pentest list --limit 10
|
|
27608
27608
|
tracecli pentest list --output json | jq '.[].title'
|
|
27609
|
-
tracecli pentest list --output tsv | cut -f1,2
|
|
27609
|
+
tracecli pentest list --output tsv | cut -f1,2
|
|
27610
|
+
tracecli pentest list --web`
|
|
27610
27611
|
).action(async (options) => {
|
|
27612
|
+
if (options.web) {
|
|
27613
|
+
const slug = await resolveOrganizationSlug();
|
|
27614
|
+
const url2 = `${getAppBaseUrl()}/dashboard/${slug}/pentests`;
|
|
27615
|
+
const opened = await openBrowser(url2);
|
|
27616
|
+
if (!opened) {
|
|
27617
|
+
console.log(`Open in browser: ${url2}`);
|
|
27618
|
+
}
|
|
27619
|
+
return;
|
|
27620
|
+
}
|
|
27611
27621
|
const organizationId = await resolveOrganizationId();
|
|
27612
27622
|
const result = await authenticatedRequest(
|
|
27613
27623
|
(client) => client.pentest.listPentests({
|
|
@@ -27695,7 +27705,7 @@ function createFindingsListCommand() {
|
|
|
27695
27705
|
}
|
|
27696
27706
|
return Math.min(n, MAX_LIMIT);
|
|
27697
27707
|
}
|
|
27698
|
-
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").addHelpText(
|
|
27708
|
+
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option("-w, --web", "Open the pentests dashboard in a browser").addHelpText(
|
|
27699
27709
|
"after",
|
|
27700
27710
|
`
|
|
27701
27711
|
Examples:
|
|
@@ -27703,9 +27713,19 @@ Examples:
|
|
|
27703
27713
|
tracecli pentest findings list --pentest PT-3 --severity CRITICAL
|
|
27704
27714
|
tracecli pentest findings list --pentest PT-3 --status OPEN --limit 20
|
|
27705
27715
|
tracecli pentest findings list --pentest PT-3 --output json
|
|
27706
|
-
tracecli pentest findings list --pentest PT-3 --output tsv | cut -f1,4
|
|
27716
|
+
tracecli pentest findings list --pentest PT-3 --output tsv | cut -f1,4
|
|
27717
|
+
tracecli pentest findings list --pentest PT-3 --web`
|
|
27707
27718
|
).action(
|
|
27708
27719
|
async (options) => {
|
|
27720
|
+
if (options.web) {
|
|
27721
|
+
const slug = await resolveOrganizationSlug();
|
|
27722
|
+
const url2 = `${getAppBaseUrl()}/dashboard/${slug}/pentests`;
|
|
27723
|
+
const opened = await openBrowser(url2);
|
|
27724
|
+
if (!opened) {
|
|
27725
|
+
console.log(`Open in browser: ${url2}`);
|
|
27726
|
+
}
|
|
27727
|
+
return;
|
|
27728
|
+
}
|
|
27709
27729
|
const organizationId = await resolveOrganizationId();
|
|
27710
27730
|
const pentestId = await resolvePentestId(organizationId, options.pentest);
|
|
27711
27731
|
const result = await authenticatedRequest(
|
|
@@ -28902,12 +28922,13 @@ async function promptForUpgradeConfirmation(latestVersion) {
|
|
|
28902
28922
|
}
|
|
28903
28923
|
}
|
|
28904
28924
|
function createUpgradeCommand() {
|
|
28905
|
-
return new Command("upgrade").alias("self-update").description("Upgrade tracecli to the latest version").option("--check", "Check whether an update is available").option("-y, --yes", "Skip upgrade confirmation prompt").addHelpText(
|
|
28925
|
+
return new Command("upgrade").alias("self-update").description("Upgrade tracecli to the latest version").option("--check", "Check whether an update is available").option("--no-confirm", "Skip upgrade confirmation prompt (for CI/scripts)").option("-y, --yes", "Skip upgrade confirmation prompt (alias: --no-confirm)").addHelpText(
|
|
28906
28926
|
"after",
|
|
28907
28927
|
`
|
|
28908
28928
|
Examples:
|
|
28909
28929
|
tracecli upgrade
|
|
28910
28930
|
tracecli upgrade --check
|
|
28931
|
+
tracecli upgrade --no-confirm
|
|
28911
28932
|
tracecli self-update`
|
|
28912
28933
|
).action(async (options) => {
|
|
28913
28934
|
const availability = await getUpdateAvailability(true);
|
|
@@ -28929,7 +28950,7 @@ Examples:
|
|
|
28929
28950
|
return;
|
|
28930
28951
|
}
|
|
28931
28952
|
const versionLabel = availability.latestVersion ?? "the latest available version";
|
|
28932
|
-
const shouldUpgrade = options.yes ? true : await promptForUpgradeConfirmation(versionLabel);
|
|
28953
|
+
const shouldUpgrade = !options.confirm || !!options.yes ? true : await promptForUpgradeConfirmation(versionLabel);
|
|
28933
28954
|
if (!shouldUpgrade) {
|
|
28934
28955
|
console.log("Upgrade cancelled.");
|
|
28935
28956
|
return;
|
|
@@ -28961,6 +28982,34 @@ Examples:
|
|
|
28961
28982
|
// src/vulnerabilities/commands.ts
|
|
28962
28983
|
var DEFAULT_LIMIT3 = 30;
|
|
28963
28984
|
var MAX_LIMIT3 = 100;
|
|
28985
|
+
var VULNERABILITY_FILTER_FIELDS = [
|
|
28986
|
+
"repositoryId",
|
|
28987
|
+
"severity",
|
|
28988
|
+
"vulnerabilityType",
|
|
28989
|
+
"status",
|
|
28990
|
+
"cweId",
|
|
28991
|
+
"scanMode"
|
|
28992
|
+
];
|
|
28993
|
+
function parseVulnerabilityFilter(expression) {
|
|
28994
|
+
const match = expression.match(/^([^!=]+)(!=|=)(.+)$/);
|
|
28995
|
+
if (!match?.[1] || !match[2] || !match[3]) {
|
|
28996
|
+
return {
|
|
28997
|
+
error: `Invalid filter expression '${expression}'. Expected format: field=value or field!=value (e.g. cweId=CWE-89).`
|
|
28998
|
+
};
|
|
28999
|
+
}
|
|
29000
|
+
const field = match[1].trim();
|
|
29001
|
+
const op = match[2];
|
|
29002
|
+
const value = match[3].trim();
|
|
29003
|
+
if (value.length === 0) {
|
|
29004
|
+
return { error: `Filter value cannot be empty in expression '${expression}'.` };
|
|
29005
|
+
}
|
|
29006
|
+
if (!VULNERABILITY_FILTER_FIELDS.includes(field)) {
|
|
29007
|
+
return {
|
|
29008
|
+
error: `Unknown filter field '${field}'. Supported fields: ${VULNERABILITY_FILTER_FIELDS.join(", ")}.`
|
|
29009
|
+
};
|
|
29010
|
+
}
|
|
29011
|
+
return { field, operator: op === "!=" ? "neq" : "eq", value };
|
|
29012
|
+
}
|
|
28964
29013
|
async function resolveRepositoryIdAuthenticated(organizationId, repoIdentifier) {
|
|
28965
29014
|
const result = await authenticatedRequest(
|
|
28966
29015
|
(client) => client.repository.listRepositories({
|
|
@@ -29078,6 +29127,11 @@ function createListCommand3() {
|
|
|
29078
29127
|
}
|
|
29079
29128
|
return Math.min(n, MAX_LIMIT3);
|
|
29080
29129
|
}
|
|
29130
|
+
).option(
|
|
29131
|
+
"-f, --filter <expression>",
|
|
29132
|
+
"Additional filter expression: field=value or field!=value. Repeatable. Supported fields: vulnerabilityType, cweId, scanMode (and any other API-supported field).",
|
|
29133
|
+
(value, previous) => [...previous, value],
|
|
29134
|
+
[]
|
|
29081
29135
|
).option("-o, --output <format>", "Output format: table, json, tsv (default: table)", "table").option("-w, --web", "Open the vulnerabilities dashboard in a browser").addHelpText(
|
|
29082
29136
|
"after",
|
|
29083
29137
|
`
|
|
@@ -29085,6 +29139,8 @@ Examples:
|
|
|
29085
29139
|
tracecli vulnerabilities list
|
|
29086
29140
|
tracecli vulnerabilities list --severity CRITICAL --status OPEN
|
|
29087
29141
|
tracecli vulnerabilities list --repo securewithtrace/trace --limit 50
|
|
29142
|
+
tracecli vulnerabilities list --filter cweId=CWE-89
|
|
29143
|
+
tracecli vulnerabilities list --filter vulnerabilityType=SAST --filter scanMode=sast
|
|
29088
29144
|
tracecli vulnerabilities list --output json | jq '.[].title'
|
|
29089
29145
|
tracecli vulnerabilities list --output tsv | cut -f1,7
|
|
29090
29146
|
tracecli vulnerabilities list --web`
|
|
@@ -29111,6 +29167,14 @@ Examples:
|
|
|
29111
29167
|
if (options.status) {
|
|
29112
29168
|
conditions.push({ field: "status", operator: "eq", value: options.status });
|
|
29113
29169
|
}
|
|
29170
|
+
for (const expression of options.filter) {
|
|
29171
|
+
const parsed = parseVulnerabilityFilter(expression);
|
|
29172
|
+
if ("error" in parsed) {
|
|
29173
|
+
console.error(parsed.error);
|
|
29174
|
+
process.exit(1);
|
|
29175
|
+
}
|
|
29176
|
+
conditions.push({ field: parsed.field, operator: parsed.operator, value: parsed.value });
|
|
29177
|
+
}
|
|
29114
29178
|
const filterBody = {
|
|
29115
29179
|
filters: conditions.length > 0 ? { operator: "and", conditions } : void 0,
|
|
29116
29180
|
defaultBranchOnly: true,
|