@chainpatrol/cli 0.22.0 → 0.23.1
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/CHANGELOG.md +16 -0
- package/dist/{breakdown-3LJBT3JQ.js → breakdown-XA6UUD3T.js} +1 -1
- package/dist/{check-G64UQCEL.js → check-NQZPNAUF.js} +1 -1
- package/dist/{chunk-2JZAPTY6.js → chunk-DVNTYW7L.js} +1 -1
- package/dist/{chunk-O7TMOF4W.js → chunk-GOQL7UCG.js} +3 -0
- package/dist/cli.js +77 -39
- package/dist/{configs-update-MVX7Q5NW.js → configs-update-VDZVBTIF.js} +1 -1
- package/dist/{create-ANCO4FXB.js → create-DGCWT2YJ.js} +1 -1
- package/dist/{drift-SHPMEJDU.js → drift-YZHCIQ5O.js} +1 -1
- package/dist/{found-OPL4HWOW.js → found-6JAOLM6M.js} +1 -1
- package/dist/{get-GTACVCLE.js → get-RC75EJFC.js} +1 -1
- package/dist/{healthcheck-QNLFKAXM.js → healthcheck-7YWSOY6Y.js} +1 -1
- package/dist/{list-X4Z3CPO7.js → list-4HX2R7HU.js} +1 -1
- package/dist/{list-XSIXAHOG.js → list-4KIZLIVN.js} +1 -1
- package/dist/{list-AQ7E23T3.js → list-EJDWUF6W.js} +1 -1
- package/dist/{list-WPPNX7G3.js → list-H7NVUX42.js} +1 -1
- package/dist/{list-FJBWSGTD.js → list-IDR7WH5J.js} +2 -2
- package/dist/{list-SWHKM5R6.js → list-Q3MMBL4Y.js} +1 -1
- package/dist/{list-JK4SRMPL.js → list-SRVNEUHC.js} +1 -1
- package/dist/{list-FVFF4VW3.js → list-UDT5MDQZ.js} +1 -1
- package/dist/{list-QHEFB4KE.js → list-WQFDRXHD.js} +1 -1
- package/dist/{list-Q5PRMAN5.js → list-YNQ6VSYV.js} +1 -1
- package/dist/{list-4VKMEKZS.js → list-ZARZ72DG.js} +1 -1
- package/dist/{list-FWXQUOCP.js → list-ZBC53OYA.js} +1 -1
- package/dist/{list-json-B5L5PXKH.js → list-json-7FDHNRYP.js} +1 -1
- package/dist/{organization-SOMHMGTM.js → organization-NEZA6JX2.js} +1 -1
- package/dist/{run-J5TQ2YC2.js → run-5QV3YD7V.js} +1 -1
- package/dist/{run-RV6P2OCD.js → run-CCVJIK7L.js} +1 -1
- package/dist/{run-YAAMSWKK.js → run-JLTNFOJK.js} +2 -2
- package/dist/{search-FQUR75WR.js → search-JXJLBV43.js} +1 -1
- package/dist/search-ZXTJPVM6.js +221 -0
- package/dist/{snapshot-2GDJMN3L.js → snapshot-NYOLPGRW.js} +1 -1
- package/dist/{summary-LF53KXRR.js → summary-FE6ROSOO.js} +1 -1
- package/dist/{types-PTMFLYUV.js → types-M6QMFNUS.js} +2 -1
- package/dist/{validate-UYKOMUEI.js → validate-RPQEEQ36.js} +1 -1
- package/dist/{whoami-OYOG63BX.js → whoami-ZIWZCBGI.js} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.23.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0f1d7d1: Fix `asset search` bulk lookups by ID. The `--id` (and `--asset`) flags are
|
|
8
|
+
documented and handled as repeatable for bulk lookup, but meow rejected the
|
|
9
|
+
second occurrence with `The flag --id can only be set once.`. Mark both flags
|
|
10
|
+
`isMultiple` so `chainpatrol asset search --id 1 --id 2 --id 3` works as
|
|
11
|
+
advertised instead of erroring out.
|
|
12
|
+
|
|
13
|
+
## 0.23.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 689e094: Adds `chainpatrol asset search` command for looking up assets by content or by numeric ID. Supports bulk ID lookup via repeated `--id` flags in a single API call. Server-side work in @chainpatrol/external-trpc adds `assetIds` array support to the `/asset/search` endpoint.
|
|
18
|
+
|
|
3
19
|
## 0.22.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
|
@@ -184,6 +184,9 @@ function createApiClient(options) {
|
|
|
184
184
|
assetCheck(input) {
|
|
185
185
|
return request("/asset/check", input);
|
|
186
186
|
},
|
|
187
|
+
assetSearch(input) {
|
|
188
|
+
return request("/asset/search", input);
|
|
189
|
+
},
|
|
187
190
|
listDetectionConfigs(slug) {
|
|
188
191
|
return request("/detection/configs/list", { slug });
|
|
189
192
|
},
|
package/dist/cli.js
CHANGED
|
@@ -92,10 +92,11 @@ var HELP = {
|
|
|
92
92
|
usage: "chainpatrol logout"
|
|
93
93
|
},
|
|
94
94
|
asset: {
|
|
95
|
-
description: "Check asset status, list blocked/allowed assets across the global ChainPatrol blocklist, or list every supported asset type.",
|
|
96
|
-
usage: "chainpatrol asset <check|list|types>",
|
|
95
|
+
description: "Check asset status, search assets by content or ID, list blocked/allowed assets across the global ChainPatrol blocklist, or list every supported asset type.",
|
|
96
|
+
usage: "chainpatrol asset <check|list|search|types>",
|
|
97
97
|
examples: [
|
|
98
98
|
"chainpatrol asset check https://phish.example",
|
|
99
|
+
"chainpatrol asset search --id 12345",
|
|
99
100
|
"chainpatrol asset list --asset-type URL --from 2026-05-01",
|
|
100
101
|
"chainpatrol asset types",
|
|
101
102
|
"chainpatrol --json asset check 0xabc123\u2026"
|
|
@@ -142,6 +143,21 @@ var HELP = {
|
|
|
142
143
|
"chainpatrol --json asset check 0xabc123\u2026"
|
|
143
144
|
]
|
|
144
145
|
},
|
|
146
|
+
"asset search": {
|
|
147
|
+
description: "Search for assets by content or by numeric ID. Returns detailed asset information including status, associated reports, takedown details, and which platforms have consumed (blocked) the asset. Supports bulk lookup by passing multiple --id flags. Unlike `asset check` (which queries the public blocklist aggregation), `asset search` queries the internal asset database directly and returns richer context.",
|
|
148
|
+
usage: "chainpatrol asset search [<content> ...] [--id <id> ...]",
|
|
149
|
+
options: [
|
|
150
|
+
"--id <number> Asset ID (repeatable for bulk lookup)",
|
|
151
|
+
"--asset <content> Asset content (repeatable; alternative to positional args)"
|
|
152
|
+
],
|
|
153
|
+
examples: [
|
|
154
|
+
"chainpatrol asset search https://phish.example",
|
|
155
|
+
"chainpatrol asset search --id 4175269",
|
|
156
|
+
"chainpatrol asset search --id 4175269 --id 4144496 --id 4642520",
|
|
157
|
+
"chainpatrol --json asset search --id 4175269 --id 4144496 --id 4642520",
|
|
158
|
+
"chainpatrol asset search --id 12345 --output markdown"
|
|
159
|
+
]
|
|
160
|
+
},
|
|
145
161
|
configs: {
|
|
146
162
|
description: "Manage detection configs for an organization.",
|
|
147
163
|
usage: "chainpatrol configs <list>",
|
|
@@ -651,7 +667,7 @@ function getTopLevelHelp() {
|
|
|
651
667
|
" login Authenticate with ChainPatrol",
|
|
652
668
|
" logout Clear stored credentials",
|
|
653
669
|
" whoami Show the current authenticated identity",
|
|
654
|
-
" asset Check or list assets, or list supported asset types",
|
|
670
|
+
" asset Check, search, or list assets, or list supported asset types",
|
|
655
671
|
" configs Manage detection configs",
|
|
656
672
|
" detections Validate, run, list, update detection configs and results",
|
|
657
673
|
" healthchecks List and run organization healthchecks",
|
|
@@ -905,7 +921,7 @@ ${getTopLevelHelp()}
|
|
|
905
921
|
description: { type: "string" },
|
|
906
922
|
cron: { type: "string" },
|
|
907
923
|
mergeConfig: { type: "boolean", default: true },
|
|
908
|
-
asset: { type: "string" },
|
|
924
|
+
asset: { type: "string", isMultiple: true },
|
|
909
925
|
limit: { type: "number" },
|
|
910
926
|
cursor: { type: "number" },
|
|
911
927
|
status: { type: "string" },
|
|
@@ -961,7 +977,8 @@ ${getTopLevelHelp()}
|
|
|
961
977
|
quiet: { type: "boolean", default: false, shortFlag: "q" },
|
|
962
978
|
noInput: { type: "boolean", default: false },
|
|
963
979
|
noColor: { type: "boolean", default: false },
|
|
964
|
-
cloud: { type: "boolean", default: false }
|
|
980
|
+
cloud: { type: "boolean", default: false },
|
|
981
|
+
id: { type: "string", isMultiple: true }
|
|
965
982
|
}
|
|
966
983
|
});
|
|
967
984
|
var [command, subcommand, action] = cli.input;
|
|
@@ -1076,12 +1093,12 @@ function parseAttachmentUrls() {
|
|
|
1076
1093
|
}
|
|
1077
1094
|
async function handleConfigsList(org) {
|
|
1078
1095
|
if (jsonMode) {
|
|
1079
|
-
const { listConfigsJson } = await import("./list-json-
|
|
1096
|
+
const { listConfigsJson } = await import("./list-json-7FDHNRYP.js");
|
|
1080
1097
|
await listConfigsJson({ org });
|
|
1081
1098
|
return;
|
|
1082
1099
|
}
|
|
1083
1100
|
const { render } = await import("ink");
|
|
1084
|
-
const { default: ConfigsList } = await import("./list-
|
|
1101
|
+
const { default: ConfigsList } = await import("./list-4HX2R7HU.js");
|
|
1085
1102
|
const { default: React } = await import("react");
|
|
1086
1103
|
render(React.createElement(ConfigsList, { org }));
|
|
1087
1104
|
}
|
|
@@ -1181,7 +1198,7 @@ async function main() {
|
|
|
1181
1198
|
const positionals = cli.input.slice(2);
|
|
1182
1199
|
const flagAssets = parseAssetInputs();
|
|
1183
1200
|
const contents = [...positionals, ...flagAssets];
|
|
1184
|
-
const { runAssetCheck } = await import("./check-
|
|
1201
|
+
const { runAssetCheck } = await import("./check-NQZPNAUF.js");
|
|
1185
1202
|
await runAssetCheck({
|
|
1186
1203
|
contents,
|
|
1187
1204
|
json: jsonMode,
|
|
@@ -1191,7 +1208,7 @@ async function main() {
|
|
|
1191
1208
|
break;
|
|
1192
1209
|
}
|
|
1193
1210
|
if (subcommand === "list") {
|
|
1194
|
-
const { runAssetList } = await import("./list-
|
|
1211
|
+
const { runAssetList } = await import("./list-4KIZLIVN.js");
|
|
1195
1212
|
await runAssetList({
|
|
1196
1213
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1197
1214
|
status: cli.flags.assetStatus ?? cli.flags.status,
|
|
@@ -1204,23 +1221,44 @@ async function main() {
|
|
|
1204
1221
|
});
|
|
1205
1222
|
break;
|
|
1206
1223
|
}
|
|
1224
|
+
if (subcommand === "search") {
|
|
1225
|
+
const positionals = cli.input.slice(2);
|
|
1226
|
+
const flagAssets = parseAssetInputs();
|
|
1227
|
+
const contents = [...positionals, ...flagAssets];
|
|
1228
|
+
const rawIds = getRepeatedFlag("id");
|
|
1229
|
+
const ids = rawIds.map((v) => {
|
|
1230
|
+
const n = Number(v);
|
|
1231
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
1232
|
+
throw new Error(`Invalid asset ID: ${v}. IDs must be positive integers.`);
|
|
1233
|
+
}
|
|
1234
|
+
return n;
|
|
1235
|
+
});
|
|
1236
|
+
const { runAssetSearch } = await import("./search-ZXTJPVM6.js");
|
|
1237
|
+
await runAssetSearch({
|
|
1238
|
+
contents: contents.length > 0 ? contents : void 0,
|
|
1239
|
+
ids: ids.length > 0 ? ids : void 0,
|
|
1240
|
+
json: jsonMode,
|
|
1241
|
+
outputFormat: cliContext.outputFormat
|
|
1242
|
+
});
|
|
1243
|
+
break;
|
|
1244
|
+
}
|
|
1207
1245
|
if (subcommand === "types") {
|
|
1208
|
-
const { runAssetTypes } = await import("./types-
|
|
1246
|
+
const { runAssetTypes } = await import("./types-M6QMFNUS.js");
|
|
1209
1247
|
runAssetTypes({
|
|
1210
1248
|
json: jsonMode,
|
|
1211
1249
|
outputFormat: cliContext.outputFormat
|
|
1212
1250
|
});
|
|
1213
1251
|
break;
|
|
1214
1252
|
}
|
|
1215
|
-
const hint = subcommand ? suggest(subcommand, ["check", "list", "types"]) : null;
|
|
1253
|
+
const hint = subcommand ? suggest(subcommand, ["check", "list", "search", "types"]) : null;
|
|
1216
1254
|
throw new Error(
|
|
1217
|
-
subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list|types>"
|
|
1255
|
+
subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list|search|types>"
|
|
1218
1256
|
);
|
|
1219
1257
|
}
|
|
1220
1258
|
case "detections": {
|
|
1221
1259
|
const org = await resolveOrg();
|
|
1222
1260
|
if (subcommand === "healthcheck") {
|
|
1223
|
-
const { runDetectionsHealthcheck } = await import("./healthcheck-
|
|
1261
|
+
const { runDetectionsHealthcheck } = await import("./healthcheck-7YWSOY6Y.js");
|
|
1224
1262
|
await runDetectionsHealthcheck({
|
|
1225
1263
|
org,
|
|
1226
1264
|
source: cli.flags.source,
|
|
@@ -1235,7 +1273,7 @@ async function main() {
|
|
|
1235
1273
|
break;
|
|
1236
1274
|
}
|
|
1237
1275
|
if (subcommand === "validate") {
|
|
1238
|
-
const { runDetectionsValidate } = await import("./validate-
|
|
1276
|
+
const { runDetectionsValidate } = await import("./validate-RPQEEQ36.js");
|
|
1239
1277
|
await runDetectionsValidate({
|
|
1240
1278
|
org,
|
|
1241
1279
|
source: cli.flags.source,
|
|
@@ -1250,7 +1288,7 @@ async function main() {
|
|
|
1250
1288
|
break;
|
|
1251
1289
|
}
|
|
1252
1290
|
if (subcommand === "drift") {
|
|
1253
|
-
const { runDetectionsDrift } = await import("./drift-
|
|
1291
|
+
const { runDetectionsDrift } = await import("./drift-YZHCIQ5O.js");
|
|
1254
1292
|
await runDetectionsDrift({
|
|
1255
1293
|
org,
|
|
1256
1294
|
source: cli.flags.source,
|
|
@@ -1264,7 +1302,7 @@ async function main() {
|
|
|
1264
1302
|
break;
|
|
1265
1303
|
}
|
|
1266
1304
|
if (subcommand === "run") {
|
|
1267
|
-
const { runDetectionsRun } = await import("./run-
|
|
1305
|
+
const { runDetectionsRun } = await import("./run-CCVJIK7L.js");
|
|
1268
1306
|
await runDetectionsRun({
|
|
1269
1307
|
org,
|
|
1270
1308
|
configId: cli.flags.configId,
|
|
@@ -1278,7 +1316,7 @@ async function main() {
|
|
|
1278
1316
|
break;
|
|
1279
1317
|
}
|
|
1280
1318
|
if (subcommand === "list") {
|
|
1281
|
-
const { runDetectionsList } = await import("./list-
|
|
1319
|
+
const { runDetectionsList } = await import("./list-Q3MMBL4Y.js");
|
|
1282
1320
|
await runDetectionsList({
|
|
1283
1321
|
org,
|
|
1284
1322
|
cursor: cli.flags.cursor,
|
|
@@ -1307,7 +1345,7 @@ async function main() {
|
|
|
1307
1345
|
break;
|
|
1308
1346
|
}
|
|
1309
1347
|
if (action === "run") {
|
|
1310
|
-
const { runDetectionsRun } = await import("./run-
|
|
1348
|
+
const { runDetectionsRun } = await import("./run-CCVJIK7L.js");
|
|
1311
1349
|
await runDetectionsRun({
|
|
1312
1350
|
org,
|
|
1313
1351
|
configId: cli.flags.configId,
|
|
@@ -1325,7 +1363,7 @@ async function main() {
|
|
|
1325
1363
|
throw new Error("detections configs update requires --config-id");
|
|
1326
1364
|
}
|
|
1327
1365
|
const configPatch = getConfigPatchFromSetFlags();
|
|
1328
|
-
const { runDetectionsConfigsUpdate } = await import("./configs-update-
|
|
1366
|
+
const { runDetectionsConfigsUpdate } = await import("./configs-update-VDZVBTIF.js");
|
|
1329
1367
|
await runDetectionsConfigsUpdate({
|
|
1330
1368
|
org,
|
|
1331
1369
|
configId: cli.flags.configId,
|
|
@@ -1361,7 +1399,7 @@ async function main() {
|
|
|
1361
1399
|
const slugs = parseCsvList(cli.flags.slugs);
|
|
1362
1400
|
const allMyOrgs = cli.flags.allMyOrgs;
|
|
1363
1401
|
const org2 = slugs && slugs.length > 0 || allMyOrgs ? void 0 : await tryResolveOrg();
|
|
1364
|
-
const { runMetricsOrganization } = await import("./organization-
|
|
1402
|
+
const { runMetricsOrganization } = await import("./organization-NEZA6JX2.js");
|
|
1365
1403
|
await runMetricsOrganization({
|
|
1366
1404
|
org: org2,
|
|
1367
1405
|
slugs,
|
|
@@ -1380,7 +1418,7 @@ async function main() {
|
|
|
1380
1418
|
}
|
|
1381
1419
|
const org = await resolveOrg();
|
|
1382
1420
|
if (subcommand === "summary") {
|
|
1383
|
-
const { runMetricsSummary } = await import("./summary-
|
|
1421
|
+
const { runMetricsSummary } = await import("./summary-FE6ROSOO.js");
|
|
1384
1422
|
await runMetricsSummary({
|
|
1385
1423
|
org,
|
|
1386
1424
|
from: cli.flags.from,
|
|
@@ -1393,7 +1431,7 @@ async function main() {
|
|
|
1393
1431
|
break;
|
|
1394
1432
|
}
|
|
1395
1433
|
if (subcommand === "found") {
|
|
1396
|
-
const { runMetricsFound } = await import("./found-
|
|
1434
|
+
const { runMetricsFound } = await import("./found-6JAOLM6M.js");
|
|
1397
1435
|
await runMetricsFound({
|
|
1398
1436
|
org,
|
|
1399
1437
|
from: cli.flags.from,
|
|
@@ -1410,7 +1448,7 @@ async function main() {
|
|
|
1410
1448
|
if (!by || !["day", "type", "brand"].includes(by)) {
|
|
1411
1449
|
throw new Error("metrics breakdown requires --by <day|type|brand>");
|
|
1412
1450
|
}
|
|
1413
|
-
const { runMetricsBreakdown } = await import("./breakdown-
|
|
1451
|
+
const { runMetricsBreakdown } = await import("./breakdown-XA6UUD3T.js");
|
|
1414
1452
|
await runMetricsBreakdown({
|
|
1415
1453
|
org,
|
|
1416
1454
|
by,
|
|
@@ -1431,7 +1469,7 @@ async function main() {
|
|
|
1431
1469
|
case "reports": {
|
|
1432
1470
|
if (subcommand === "list") {
|
|
1433
1471
|
const org = await resolveOrg();
|
|
1434
|
-
const { runReportsList } = await import("./list-
|
|
1472
|
+
const { runReportsList } = await import("./list-H7NVUX42.js");
|
|
1435
1473
|
await runReportsList({
|
|
1436
1474
|
org,
|
|
1437
1475
|
limit: cli.flags.limit,
|
|
@@ -1459,7 +1497,7 @@ async function main() {
|
|
|
1459
1497
|
}
|
|
1460
1498
|
if (subcommand === "create") {
|
|
1461
1499
|
const org = await tryResolveOrg();
|
|
1462
|
-
const { runReportsCreate } = await import("./create-
|
|
1500
|
+
const { runReportsCreate } = await import("./create-DGCWT2YJ.js");
|
|
1463
1501
|
await runReportsCreate({
|
|
1464
1502
|
org,
|
|
1465
1503
|
title: cli.flags.title,
|
|
@@ -1480,7 +1518,7 @@ async function main() {
|
|
|
1480
1518
|
const positionals = cli.input.slice(2);
|
|
1481
1519
|
const flagAssets = parseAssetInputs();
|
|
1482
1520
|
const assetContents = [...positionals, ...flagAssets];
|
|
1483
|
-
const { runReportsSearch } = await import("./search-
|
|
1521
|
+
const { runReportsSearch } = await import("./search-JXJLBV43.js");
|
|
1484
1522
|
await runReportsSearch({
|
|
1485
1523
|
assetContents,
|
|
1486
1524
|
reportedByCustomer: cli.flags.reportedByCustomer,
|
|
@@ -1496,7 +1534,7 @@ async function main() {
|
|
|
1496
1534
|
}
|
|
1497
1535
|
case "threats": {
|
|
1498
1536
|
if (subcommand === "list") {
|
|
1499
|
-
const { runThreatsList } = await import("./list-
|
|
1537
|
+
const { runThreatsList } = await import("./list-YNQ6VSYV.js");
|
|
1500
1538
|
await runThreatsList({
|
|
1501
1539
|
query: cli.flags.query,
|
|
1502
1540
|
from: cli.flags.from,
|
|
@@ -1519,7 +1557,7 @@ async function main() {
|
|
|
1519
1557
|
case "takedowns": {
|
|
1520
1558
|
if (subcommand === "list") {
|
|
1521
1559
|
const org = await tryResolveOrg();
|
|
1522
|
-
const { runTakedownsList } = await import("./list-
|
|
1560
|
+
const { runTakedownsList } = await import("./list-ZBC53OYA.js");
|
|
1523
1561
|
await runTakedownsList({
|
|
1524
1562
|
org,
|
|
1525
1563
|
query: cli.flags.query,
|
|
@@ -1550,7 +1588,7 @@ async function main() {
|
|
|
1550
1588
|
}
|
|
1551
1589
|
case "queues": {
|
|
1552
1590
|
if (subcommand === "snapshot") {
|
|
1553
|
-
const { runQueuesSnapshot } = await import("./snapshot-
|
|
1591
|
+
const { runQueuesSnapshot } = await import("./snapshot-NYOLPGRW.js");
|
|
1554
1592
|
await runQueuesSnapshot({
|
|
1555
1593
|
org: cli.flags.org,
|
|
1556
1594
|
all: cli.flags.all,
|
|
@@ -1568,7 +1606,7 @@ async function main() {
|
|
|
1568
1606
|
}
|
|
1569
1607
|
case "orgs": {
|
|
1570
1608
|
if (subcommand === "list") {
|
|
1571
|
-
const { runOrgsList } = await import("./list-
|
|
1609
|
+
const { runOrgsList } = await import("./list-SRVNEUHC.js");
|
|
1572
1610
|
await runOrgsList({
|
|
1573
1611
|
query: cli.flags.query,
|
|
1574
1612
|
subscriptionStatus: cli.flags.subscriptionStatus,
|
|
@@ -1590,7 +1628,7 @@ async function main() {
|
|
|
1590
1628
|
if (subcommand === "get") {
|
|
1591
1629
|
const positionalSlug = action;
|
|
1592
1630
|
const slug = positionalSlug ?? await tryResolveOrg();
|
|
1593
|
-
const { runOrgsGet } = await import("./get-
|
|
1631
|
+
const { runOrgsGet } = await import("./get-RC75EJFC.js");
|
|
1594
1632
|
await runOrgsGet({
|
|
1595
1633
|
slug,
|
|
1596
1634
|
json: jsonMode,
|
|
@@ -1600,7 +1638,7 @@ async function main() {
|
|
|
1600
1638
|
}
|
|
1601
1639
|
if (subcommand === "assets") {
|
|
1602
1640
|
if (action === "list") {
|
|
1603
|
-
const { runOrgsAssetsList } = await import("./list-
|
|
1641
|
+
const { runOrgsAssetsList } = await import("./list-WQFDRXHD.js");
|
|
1604
1642
|
await runOrgsAssetsList({
|
|
1605
1643
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1606
1644
|
groupId: cli.flags.groupId,
|
|
@@ -1616,7 +1654,7 @@ async function main() {
|
|
|
1616
1654
|
}
|
|
1617
1655
|
if (subcommand === "asset-groups") {
|
|
1618
1656
|
if (action === "list") {
|
|
1619
|
-
const { runOrgsAssetGroupsList } = await import("./list-
|
|
1657
|
+
const { runOrgsAssetGroupsList } = await import("./list-UDT5MDQZ.js");
|
|
1620
1658
|
await runOrgsAssetGroupsList({
|
|
1621
1659
|
json: jsonMode,
|
|
1622
1660
|
outputFormat: cliContext.outputFormat
|
|
@@ -1638,7 +1676,7 @@ async function main() {
|
|
|
1638
1676
|
"brands list --type must be ORGANIZATION or INDIVIDUAL (case-insensitive)."
|
|
1639
1677
|
);
|
|
1640
1678
|
}
|
|
1641
|
-
const { runBrandsList } = await import("./list-
|
|
1679
|
+
const { runBrandsList } = await import("./list-ZARZ72DG.js");
|
|
1642
1680
|
await runBrandsList({
|
|
1643
1681
|
type: rawType,
|
|
1644
1682
|
json: jsonMode,
|
|
@@ -1652,7 +1690,7 @@ async function main() {
|
|
|
1652
1690
|
);
|
|
1653
1691
|
}
|
|
1654
1692
|
case "whoami": {
|
|
1655
|
-
const { runWhoami } = await import("./whoami-
|
|
1693
|
+
const { runWhoami } = await import("./whoami-ZIWZCBGI.js");
|
|
1656
1694
|
await runWhoami({
|
|
1657
1695
|
json: jsonMode,
|
|
1658
1696
|
outputFormat: cliContext.outputFormat
|
|
@@ -1661,7 +1699,7 @@ async function main() {
|
|
|
1661
1699
|
}
|
|
1662
1700
|
case "healthchecks": {
|
|
1663
1701
|
if (subcommand === "list") {
|
|
1664
|
-
const { runHealthchecksList } = await import("./list-
|
|
1702
|
+
const { runHealthchecksList } = await import("./list-EJDWUF6W.js");
|
|
1665
1703
|
await runHealthchecksList({
|
|
1666
1704
|
json: jsonMode,
|
|
1667
1705
|
outputFormat: cliContext.outputFormat
|
|
@@ -1675,7 +1713,7 @@ async function main() {
|
|
|
1675
1713
|
thresholds.minResults = cli.flags.minResults;
|
|
1676
1714
|
if (cli.flags.lookbackHours !== void 0)
|
|
1677
1715
|
thresholds.lookbackHours = cli.flags.lookbackHours;
|
|
1678
|
-
const { runHealthchecksRun } = await import("./run-
|
|
1716
|
+
const { runHealthchecksRun } = await import("./run-5QV3YD7V.js");
|
|
1679
1717
|
await runHealthchecksRun({
|
|
1680
1718
|
org,
|
|
1681
1719
|
id: action,
|
|
@@ -1693,7 +1731,7 @@ async function main() {
|
|
|
1693
1731
|
}
|
|
1694
1732
|
case "presets": {
|
|
1695
1733
|
if (subcommand === "list") {
|
|
1696
|
-
const { runPresetsList } = await import("./list-
|
|
1734
|
+
const { runPresetsList } = await import("./list-IDR7WH5J.js");
|
|
1697
1735
|
await runPresetsList({ outputFormat: cliContext.outputFormat });
|
|
1698
1736
|
break;
|
|
1699
1737
|
}
|
|
@@ -1704,7 +1742,7 @@ async function main() {
|
|
|
1704
1742
|
);
|
|
1705
1743
|
}
|
|
1706
1744
|
const org = await resolveOrg();
|
|
1707
|
-
const { runPresetsRun } = await import("./run-
|
|
1745
|
+
const { runPresetsRun } = await import("./run-JLTNFOJK.js");
|
|
1708
1746
|
await runPresetsRun({
|
|
1709
1747
|
presetId: action,
|
|
1710
1748
|
org,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PRESETS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DVNTYW7L.js";
|
|
4
4
|
import "./chunk-E2LAMILJ.js";
|
|
5
5
|
import {
|
|
6
6
|
printOutput,
|
|
7
7
|
toCsvRows
|
|
8
8
|
} from "./chunk-VFT3TD3E.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-GOQL7UCG.js";
|
|
10
10
|
import "./chunk-EGWK6SRQ.js";
|
|
11
11
|
import "./chunk-TFCNKBRC.js";
|
|
12
12
|
import "./chunk-U73SABXK.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPresetDefinition,
|
|
3
3
|
runPreset
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DVNTYW7L.js";
|
|
5
5
|
import {
|
|
6
6
|
CliExitError,
|
|
7
7
|
ExitCode
|
|
8
8
|
} from "./chunk-E2LAMILJ.js";
|
|
9
9
|
import "./chunk-VFT3TD3E.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-GOQL7UCG.js";
|
|
11
11
|
import "./chunk-EGWK6SRQ.js";
|
|
12
12
|
import "./chunk-TFCNKBRC.js";
|
|
13
13
|
import "./chunk-U73SABXK.js";
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CliExitError,
|
|
3
|
+
ExitCode
|
|
4
|
+
} from "./chunk-E2LAMILJ.js";
|
|
5
|
+
import {
|
|
6
|
+
printOutput,
|
|
7
|
+
toCsvRows
|
|
8
|
+
} from "./chunk-VFT3TD3E.js";
|
|
9
|
+
import {
|
|
10
|
+
createApiClient
|
|
11
|
+
} from "./chunk-GOQL7UCG.js";
|
|
12
|
+
import "./chunk-EGWK6SRQ.js";
|
|
13
|
+
import "./chunk-TFCNKBRC.js";
|
|
14
|
+
import "./chunk-U73SABXK.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/asset/search.ts
|
|
17
|
+
function formatAssetRow(item) {
|
|
18
|
+
if (!item.asset) {
|
|
19
|
+
return " (not found)";
|
|
20
|
+
}
|
|
21
|
+
const a = item.asset;
|
|
22
|
+
const lines = [
|
|
23
|
+
` [${a.status}] ${a.content} (id=${a.id}, type=${a.type}, watch=${a.watchStatus})`
|
|
24
|
+
];
|
|
25
|
+
if (item.reports.length > 0) {
|
|
26
|
+
lines.push(` Reports: ${item.reports.length}`);
|
|
27
|
+
}
|
|
28
|
+
if (item.takedown) {
|
|
29
|
+
lines.push(
|
|
30
|
+
` Takedown: ${item.takedown.status} (${item.takedown.tasks.length} task(s))`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
if (item.blockedBy.length > 0) {
|
|
34
|
+
lines.push(` Blocked by: ${item.blockedBy.map((b) => b.consumer).join(", ")}`);
|
|
35
|
+
}
|
|
36
|
+
return lines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
function toMarkdownRow(item, label) {
|
|
39
|
+
if (!item.asset) {
|
|
40
|
+
return `| ${label ?? "unknown"} | \u2014 | \u2014 | \u2014 | not found |`;
|
|
41
|
+
}
|
|
42
|
+
const a = item.asset;
|
|
43
|
+
return `| ${a.id} | ${a.content} | ${a.type} | ${a.status} | ${a.watchStatus} |`;
|
|
44
|
+
}
|
|
45
|
+
function toCsvRow(item, label) {
|
|
46
|
+
if (!item.asset) {
|
|
47
|
+
return {
|
|
48
|
+
id: label ?? "",
|
|
49
|
+
content: label ?? "",
|
|
50
|
+
type: "",
|
|
51
|
+
status: "NOT_FOUND",
|
|
52
|
+
watchStatus: "",
|
|
53
|
+
reports: 0,
|
|
54
|
+
takedownStatus: "",
|
|
55
|
+
blockedByCount: 0
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const a = item.asset;
|
|
59
|
+
return {
|
|
60
|
+
id: a.id,
|
|
61
|
+
content: a.content,
|
|
62
|
+
type: a.type,
|
|
63
|
+
status: a.status,
|
|
64
|
+
watchStatus: a.watchStatus,
|
|
65
|
+
reports: item.reports.length,
|
|
66
|
+
takedownStatus: item.takedown?.status ?? "",
|
|
67
|
+
blockedByCount: item.blockedBy.length
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function runAssetSearch(options) {
|
|
71
|
+
const contents = (options.contents ?? []).map((v) => v.trim()).filter((v) => v.length > 0);
|
|
72
|
+
const ids = options.ids ?? [];
|
|
73
|
+
if (contents.length === 0 && ids.length === 0) {
|
|
74
|
+
throw new CliExitError(
|
|
75
|
+
"asset search requires at least one asset content or --id. Example: chainpatrol asset search https://example.com or chainpatrol asset search --id 12345",
|
|
76
|
+
ExitCode.USAGE
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (contents.length > 0 && ids.length > 0) {
|
|
80
|
+
throw new CliExitError(
|
|
81
|
+
"asset search does not support mixing content and --id in the same call. Use one or the other.",
|
|
82
|
+
ExitCode.USAGE
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
86
|
+
const client = options.apiClient ?? createApiClient();
|
|
87
|
+
let items;
|
|
88
|
+
let labels = [];
|
|
89
|
+
if (ids.length > 0) {
|
|
90
|
+
labels = ids.map((id) => `ID ${id}`);
|
|
91
|
+
const result = await client.assetSearch({ assetIds: ids });
|
|
92
|
+
items = result.results ?? [result];
|
|
93
|
+
} else if (contents.length === 1) {
|
|
94
|
+
labels = [contents[0]];
|
|
95
|
+
const result = await client.assetSearch({ content: contents[0] });
|
|
96
|
+
items = [result];
|
|
97
|
+
} else {
|
|
98
|
+
labels = contents;
|
|
99
|
+
const settled = await Promise.allSettled(
|
|
100
|
+
contents.map((content) => client.assetSearch({ content }))
|
|
101
|
+
);
|
|
102
|
+
let errored = 0;
|
|
103
|
+
items = settled.map((r, i) => {
|
|
104
|
+
if (r.status === "fulfilled") return r.value;
|
|
105
|
+
errored += 1;
|
|
106
|
+
console.error(
|
|
107
|
+
`Error searching ${contents[i]}: ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`
|
|
108
|
+
);
|
|
109
|
+
return { asset: null, reports: [], takedown: null, blockedBy: [] };
|
|
110
|
+
});
|
|
111
|
+
if (errored === contents.length) {
|
|
112
|
+
throw new CliExitError(
|
|
113
|
+
`asset search: all ${errored} request(s) failed.`,
|
|
114
|
+
ExitCode.UNKNOWN
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const found = items.filter((i) => i.asset !== null).length;
|
|
119
|
+
const notFound = items.length - found;
|
|
120
|
+
const jsonPayload = items.length === 1 ? items[0] : {
|
|
121
|
+
results: items,
|
|
122
|
+
summary: { total: items.length, found, notFound }
|
|
123
|
+
};
|
|
124
|
+
const markdown = items.length === 1 && items[0].asset ? buildSingleMarkdown(items[0]) : [
|
|
125
|
+
`# Asset Search (${items.length})`,
|
|
126
|
+
"",
|
|
127
|
+
`- Found: ${found}`,
|
|
128
|
+
`- Not found: ${notFound}`,
|
|
129
|
+
"",
|
|
130
|
+
"| ID | Content | Type | Status | Watch |",
|
|
131
|
+
"| --- | --- | --- | --- | --- |",
|
|
132
|
+
...items.map((item, i) => toMarkdownRow(item, labels[i]))
|
|
133
|
+
].join("\n");
|
|
134
|
+
const csv = toCsvRows(items.map((item, i) => toCsvRow(item, labels[i])));
|
|
135
|
+
printOutput({
|
|
136
|
+
outputFormat,
|
|
137
|
+
json: jsonPayload,
|
|
138
|
+
markdown,
|
|
139
|
+
csv,
|
|
140
|
+
human: () => {
|
|
141
|
+
if (items.length === 1) {
|
|
142
|
+
const item = items[0];
|
|
143
|
+
if (!item.asset) {
|
|
144
|
+
console.log(`${labels[0] ?? "Asset"} not found.`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
console.log(formatAssetRow(item));
|
|
148
|
+
if (item.reports.length > 0) {
|
|
149
|
+
console.log(" Reports:");
|
|
150
|
+
for (const r of item.reports) {
|
|
151
|
+
console.log(
|
|
152
|
+
` #${r.id} [${r.status}] ${r.title ?? "(untitled)"} \u2014 ${r.createdAt}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (item.takedown) {
|
|
157
|
+
console.log(` Takedown #${item.takedown.id} [${item.takedown.status}]`);
|
|
158
|
+
for (const t of item.takedown.tasks) {
|
|
159
|
+
console.log(
|
|
160
|
+
` Task #${t.id} [${t.status}] ${t.takedownProvider?.name ?? "unknown provider"}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
console.log(
|
|
167
|
+
`Asset Search \u2014 ${found} found, ${notFound} not found (${items.length} total)`
|
|
168
|
+
);
|
|
169
|
+
for (let i = 0; i < items.length; i++) {
|
|
170
|
+
const item = items[i];
|
|
171
|
+
if (!item.asset) {
|
|
172
|
+
console.log(`${labels[i] ?? "unknown"} -> NOT FOUND`);
|
|
173
|
+
} else {
|
|
174
|
+
console.log(formatAssetRow(item));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function buildSingleMarkdown(item) {
|
|
181
|
+
if (!item.asset) {
|
|
182
|
+
return "# Asset Search\n\nAsset not found.";
|
|
183
|
+
}
|
|
184
|
+
const a = item.asset;
|
|
185
|
+
const lines = [
|
|
186
|
+
`# Asset Search: ${a.content}`,
|
|
187
|
+
"",
|
|
188
|
+
`- ID: ${a.id}`,
|
|
189
|
+
`- Type: ${a.type}`,
|
|
190
|
+
`- Status: **${a.status}**`,
|
|
191
|
+
`- Watch: ${a.watchStatus}`,
|
|
192
|
+
`- Created: ${a.createdAt}`,
|
|
193
|
+
`- Updated: ${a.updatedAt}`
|
|
194
|
+
];
|
|
195
|
+
if (item.reports.length > 0) {
|
|
196
|
+
lines.push("", "## Reports", "");
|
|
197
|
+
for (const r of item.reports) {
|
|
198
|
+
lines.push(`- #${r.id} [${r.status}] ${r.title ?? "(untitled)"} \u2014 ${r.createdAt}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (item.takedown) {
|
|
202
|
+
lines.push("", `## Takedown #${item.takedown.id} [${item.takedown.status}]`, "");
|
|
203
|
+
for (const t of item.takedown.tasks) {
|
|
204
|
+
lines.push(
|
|
205
|
+
`- Task #${t.id} [${t.status}] ${t.takedownProvider?.name ?? "unknown provider"}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (item.blockedBy.length > 0) {
|
|
210
|
+
lines.push("", "## Blocked By", "");
|
|
211
|
+
for (const b of item.blockedBy) {
|
|
212
|
+
lines.push(
|
|
213
|
+
`- ${b.consumer}${b.name ? ` (${b.name})` : ""} \u2014 since ${b.consumedAt}`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return lines.join("\n");
|
|
218
|
+
}
|
|
219
|
+
export {
|
|
220
|
+
runAssetSearch
|
|
221
|
+
};
|
|
@@ -217,7 +217,8 @@ var ASSET_TYPES = [
|
|
|
217
217
|
type: "FIVE_HUNDRED_PX",
|
|
218
218
|
label: "500px",
|
|
219
219
|
description: "A 500px photographer profile."
|
|
220
|
-
}
|
|
220
|
+
},
|
|
221
|
+
{ type: "LUMA", label: "Luma", description: "A Luma page or profile." }
|
|
221
222
|
];
|
|
222
223
|
var ASSET_TYPE_LABELS = Object.freeze(
|
|
223
224
|
Object.fromEntries(ASSET_TYPES.map((entry) => [entry.type, entry.label]))
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@chainpatrol/cli",
|
|
3
3
|
"description": "The official ChainPatrol CLI — terminal interface for threat detection",
|
|
4
4
|
"author": "Umar Ahmed <umar@chainpatrol.io>",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.23.1",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|