@chainpatrol/cli 0.10.0 → 0.12.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.
- package/CHANGELOG.md +64 -0
- package/README.md +2 -0
- package/dist/{breakdown-63FAOVL7.js → breakdown-KCTKQNDY.js} +1 -1
- package/dist/{check-7QDINQPT.js → check-P5JJJNEX.js} +1 -1
- package/dist/{chunk-BJISZ3CY.js → chunk-DJVB73FL.js} +1 -1
- package/dist/{chunk-Z76CUWSS.js → chunk-NQT77IB7.js} +62 -9
- package/dist/chunk-OSRFCVBT.js +382 -0
- package/dist/{chunk-R2DZGMGT.js → chunk-W42ITB5J.js} +1 -1
- package/dist/cli.js +486 -65
- package/dist/{completions-D6SOLU2D.js → completions-6C6KG5DH.js} +1 -1
- package/dist/{configs-update-2IOSKZH5.js → configs-update-3ZVXGADV.js} +1 -1
- package/dist/{create-EWS3SFCH.js → create-DFH2G7RH.js} +1 -1
- package/dist/{drift-Q3VG3XG3.js → drift-T74V2C3J.js} +1 -1
- package/dist/{found-22B7RZT5.js → found-EVXJZGYX.js} +1 -1
- package/dist/{healthcheck-C3AIMUJT.js → healthcheck-HZYEIIOR.js} +1 -1
- package/dist/{list-DNRWKM5O.js → list-23QQYAV5.js} +1 -1
- package/dist/list-EIVPGMWJ.js +82 -0
- package/dist/list-I7SBGA52.js +50 -0
- package/dist/{list-IA4CSOIY.js → list-IYJBKE2F.js} +1 -1
- package/dist/list-PBAXQSL5.js +85 -0
- package/dist/list-QUFY4IP7.js +146 -0
- package/dist/list-WJQT2XLE.js +143 -0
- package/dist/{list-HFWSMLGJ.js → list-WX5G3IOF.js} +2 -2
- package/dist/list-YCT6DYDI.js +89 -0
- package/dist/{list-SDBLGBVW.js → list-YRJPN4PI.js} +1 -1
- package/dist/{list-AYHDFSQG.js → list-ZFPML3ZR.js} +47 -3
- package/dist/{list-json-CEPGVUGF.js → list-json-T2Z7NV7G.js} +1 -1
- package/dist/organization-IIIOSTHF.js +75 -0
- package/dist/{run-WJGHJPXN.js → run-BHEXWBAS.js} +2 -2
- package/dist/{run-AQMJRFGL.js → run-CJGN6TX4.js} +1 -1
- package/dist/{run-YTWNQD5X.js → run-MSO6IXEV.js} +1 -1
- package/dist/search-WPSKQGUS.js +71 -0
- package/dist/{setup-skill-BLJLRCXL.js → setup-skill-FA4STSGA.js} +2 -2
- package/dist/{snapshot-C5MZWJTW.js → snapshot-ZWAHEG64.js} +1 -1
- package/dist/{summary-NQDZQEOD.js → summary-Y2LG6UJM.js} +1 -1
- package/dist/{validate-5DVPSXJP.js → validate-SM5DD7I2.js} +1 -1
- package/dist/whoami-DH5HVLFN.js +69 -0
- package/package.json +1 -1
- package/dist/chunk-RIKR2WFT.js +0 -174
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 28cdda8: Two-part change to the external API surface and the CLI:
|
|
8
|
+
|
|
9
|
+
**Part 1: eight new read-only commands** so operators and agents can pull
|
|
10
|
+
asset, threat, detection, report-search, and identity data without leaving the
|
|
11
|
+
terminal:
|
|
12
|
+
|
|
13
|
+
- `chainpatrol asset list` — `POST /asset/list`
|
|
14
|
+
- `chainpatrol threats list` — `POST /threats/list`
|
|
15
|
+
- `chainpatrol detections list` — `POST /detection/list`
|
|
16
|
+
- `chainpatrol reports search` — `POST /reports/search`
|
|
17
|
+
- `chainpatrol orgs assets list` — `GET /organization/assets`
|
|
18
|
+
- `chainpatrol orgs asset-groups list` — `GET /organization/asset-groups`
|
|
19
|
+
- `chainpatrol whoami` — `GET /validate` (with an API key) or `POST /user/me`
|
|
20
|
+
(with a session token)
|
|
21
|
+
|
|
22
|
+
All support the standard `--json` / `--output {human,json,markdown,csv}` shapes
|
|
23
|
+
and integrate with the existing API-key and session auth modes.
|
|
24
|
+
|
|
25
|
+
**Part 2: filter parity** between the external API + CLI and the app's
|
|
26
|
+
detections / takedowns / reports views.
|
|
27
|
+
|
|
28
|
+
- **Detections** — new filter properties on `POST /detection/list`: liveness,
|
|
29
|
+
watchlist, reported, deleted (opt-in), countryCode. CLI flags:
|
|
30
|
+
`--liveness`, `--watchlist`, `--reported`, `--country-code`,
|
|
31
|
+
`--include-deleted`, plus brand filtering via `--brand`.
|
|
32
|
+
- **Takedowns** — new fields on `POST /takedowns/list`: brandIds, assigneeIds,
|
|
33
|
+
startedAtStartDate / startedAtEndDate (computed from the earliest
|
|
34
|
+
IN_PROGRESS TakedownEvent), hideAutomatedTakedowns,
|
|
35
|
+
hideAutomatedLivenessChecks; plus new sort keys `assigneeId`, `brandId`.
|
|
36
|
+
CLI flags: `--brand`, `--assignee`, `--started-from`, `--started-to`,
|
|
37
|
+
`--hide-automated-takedowns`, `--hide-automated-liveness-checks`.
|
|
38
|
+
- **Reports** — the external `/public/getOrganizationReports` endpoint
|
|
39
|
+
already accepted every app filter via its shared schema; the CLI now
|
|
40
|
+
surfaces them. New flags on `chainpatrol reports list`: `--reporter-query`,
|
|
41
|
+
`--exclude-automation`, `--only-rejected`, `--review-status`,
|
|
42
|
+
`--asset-type`, `--brand`, `--country-code`, `--reviewed-by-user-id`,
|
|
43
|
+
`--updated-from`, `--updated-to`, and the existing `--from`/`--to` are now
|
|
44
|
+
wired through.
|
|
45
|
+
|
|
46
|
+
## 0.11.0
|
|
47
|
+
|
|
48
|
+
### Minor Changes
|
|
49
|
+
|
|
50
|
+
- 21e4455: Add `chainpatrol takedowns list` and `chainpatrol metrics organization`
|
|
51
|
+
commands so agents can pull per-takedown detail and org-scoped metrics
|
|
52
|
+
from the CLI instead of stopping at `queues snapshot`'s aggregate
|
|
53
|
+
counts.
|
|
54
|
+
|
|
55
|
+
`takedowns list` wraps `POST /takedowns/list` with filters for status,
|
|
56
|
+
asset type, liveness, date range, search, sort, and pagination, and
|
|
57
|
+
emits the standard human/json/markdown/csv shapes. `metrics
|
|
58
|
+
organization` wraps the documented `GET /organization/metrics`
|
|
59
|
+
endpoint, complementing the existing `metrics summary`/`found`/
|
|
60
|
+
`breakdown` subcommands.
|
|
61
|
+
|
|
62
|
+
Both endpoints now also accept a user-session bearer token (pass
|
|
63
|
+
`--org <slug>`) in addition to an API key, so customer-success operators
|
|
64
|
+
logged in via `chainpatrol login` can use them without provisioning a
|
|
65
|
+
key.
|
|
66
|
+
|
|
3
67
|
## 0.10.0
|
|
4
68
|
|
|
5
69
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -22,7 +22,9 @@ chainpatrol metrics found --org my-org --this-week
|
|
|
22
22
|
chainpatrol reports create --org my-org --title "Phishing report" --asset "https://phish.example:BLOCKED"
|
|
23
23
|
chainpatrol reports list --org my-org --limit 10
|
|
24
24
|
chainpatrol metrics breakdown --org my-org --by type --from 2026-01-01 --to 2026-01-08
|
|
25
|
+
chainpatrol metrics organization --org my-org --from 2026-01-01 --to 2026-02-01
|
|
25
26
|
chainpatrol queues snapshot --all --output markdown
|
|
27
|
+
chainpatrol takedowns list --org my-org --takedown-status TODO,IN_PROGRESS --per-page 50
|
|
26
28
|
chainpatrol presets run cs-weekly-health --org my-org --output json
|
|
27
29
|
```
|
|
28
30
|
|
|
@@ -16,12 +16,16 @@ _chainpatrol() {
|
|
|
16
16
|
commands=(
|
|
17
17
|
'login:Authenticate with ChainPatrol'
|
|
18
18
|
'logout:Clear stored credentials'
|
|
19
|
-
'
|
|
19
|
+
'whoami:Show the current authenticated identity'
|
|
20
|
+
'asset:Check or list assets against ChainPatrol'
|
|
20
21
|
'configs:Manage detection configs'
|
|
21
|
-
'detections:Validate
|
|
22
|
+
'detections:Validate, run, list, update detection configs and results'
|
|
22
23
|
'metrics:Query organization metrics'
|
|
23
|
-
'reports:Create
|
|
24
|
+
'reports:Create, list, search reports from terminal'
|
|
24
25
|
'queues:Snapshot operations queues'
|
|
26
|
+
'takedowns:List individual takedown records'
|
|
27
|
+
'threats:List confirmed threats blocked by ChainPatrol'
|
|
28
|
+
'orgs:List organizations, org assets, and asset groups'
|
|
25
29
|
'presets:Run saved workflows'
|
|
26
30
|
'setup:Install Claude Code skill and shell completions'
|
|
27
31
|
'uninstall:Remove Claude Code skill and shell completions'
|
|
@@ -59,7 +63,10 @@ _chainpatrol() {
|
|
|
59
63
|
case "\${words[2]}" in
|
|
60
64
|
asset)
|
|
61
65
|
local -a asset_subcommands
|
|
62
|
-
asset_subcommands=(
|
|
66
|
+
asset_subcommands=(
|
|
67
|
+
'check:Check asset status against ChainPatrol'
|
|
68
|
+
'list:List assets in the global ChainPatrol blocklist'
|
|
69
|
+
)
|
|
63
70
|
_describe 'subcommand' asset_subcommands
|
|
64
71
|
;;
|
|
65
72
|
configs)
|
|
@@ -74,6 +81,7 @@ _chainpatrol() {
|
|
|
74
81
|
'validate:Validate detection configs'
|
|
75
82
|
'drift:Show detection drift signals'
|
|
76
83
|
'run:Run detection configs'
|
|
84
|
+
'list:List threat detection results'
|
|
77
85
|
'configs:Manage detection configs'
|
|
78
86
|
)
|
|
79
87
|
_describe 'subcommand' detections_subcommands
|
|
@@ -84,6 +92,7 @@ _chainpatrol() {
|
|
|
84
92
|
'summary:Show metrics summary'
|
|
85
93
|
'found:Show found threats count'
|
|
86
94
|
'breakdown:Show metrics breakdown'
|
|
95
|
+
'organization:Get organization metrics (official endpoint)'
|
|
87
96
|
)
|
|
88
97
|
_describe 'subcommand' metrics_subcommands
|
|
89
98
|
;;
|
|
@@ -92,6 +101,7 @@ _chainpatrol() {
|
|
|
92
101
|
reports_subcommands=(
|
|
93
102
|
'create:Create a new report'
|
|
94
103
|
'list:List organization reports'
|
|
104
|
+
'search:Search reports by asset contents'
|
|
95
105
|
)
|
|
96
106
|
_describe 'subcommand' reports_subcommands
|
|
97
107
|
;;
|
|
@@ -100,6 +110,25 @@ _chainpatrol() {
|
|
|
100
110
|
queues_subcommands=('snapshot:Show queue snapshot')
|
|
101
111
|
_describe 'subcommand' queues_subcommands
|
|
102
112
|
;;
|
|
113
|
+
takedowns)
|
|
114
|
+
local -a takedowns_subcommands
|
|
115
|
+
takedowns_subcommands=('list:List individual takedown records')
|
|
116
|
+
_describe 'subcommand' takedowns_subcommands
|
|
117
|
+
;;
|
|
118
|
+
threats)
|
|
119
|
+
local -a threats_subcommands
|
|
120
|
+
threats_subcommands=('list:List confirmed threats')
|
|
121
|
+
_describe 'subcommand' threats_subcommands
|
|
122
|
+
;;
|
|
123
|
+
orgs)
|
|
124
|
+
local -a orgs_subcommands
|
|
125
|
+
orgs_subcommands=(
|
|
126
|
+
'list:List organizations'
|
|
127
|
+
'assets:Manage organization assets'
|
|
128
|
+
'asset-groups:Manage organization asset groups'
|
|
129
|
+
)
|
|
130
|
+
_describe 'subcommand' orgs_subcommands
|
|
131
|
+
;;
|
|
103
132
|
presets)
|
|
104
133
|
local -a presets_subcommands
|
|
105
134
|
presets_subcommands=(
|
|
@@ -124,7 +153,7 @@ var BASH_COMPLETION = `_chainpatrol() {
|
|
|
124
153
|
COMPREPLY=()
|
|
125
154
|
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
126
155
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
127
|
-
commands="login logout asset configs detections metrics reports queues presets setup uninstall completions help"
|
|
156
|
+
commands="login logout whoami asset configs detections metrics reports queues takedowns threats orgs presets setup uninstall completions help"
|
|
128
157
|
|
|
129
158
|
case "\${prev}" in
|
|
130
159
|
chainpatrol)
|
|
@@ -132,7 +161,7 @@ var BASH_COMPLETION = `_chainpatrol() {
|
|
|
132
161
|
return 0
|
|
133
162
|
;;
|
|
134
163
|
asset)
|
|
135
|
-
COMPREPLY=( $(compgen -W "check" -- "\${cur}") )
|
|
164
|
+
COMPREPLY=( $(compgen -W "check list" -- "\${cur}") )
|
|
136
165
|
return 0
|
|
137
166
|
;;
|
|
138
167
|
configs)
|
|
@@ -140,21 +169,45 @@ var BASH_COMPLETION = `_chainpatrol() {
|
|
|
140
169
|
return 0
|
|
141
170
|
;;
|
|
142
171
|
detections)
|
|
143
|
-
COMPREPLY=( $(compgen -W "healthcheck validate drift run configs" -- "\${cur}") )
|
|
172
|
+
COMPREPLY=( $(compgen -W "healthcheck validate drift run list configs" -- "\${cur}") )
|
|
144
173
|
return 0
|
|
145
174
|
;;
|
|
146
175
|
metrics)
|
|
147
|
-
COMPREPLY=( $(compgen -W "summary found breakdown" -- "\${cur}") )
|
|
176
|
+
COMPREPLY=( $(compgen -W "summary found breakdown organization" -- "\${cur}") )
|
|
148
177
|
return 0
|
|
149
178
|
;;
|
|
150
179
|
reports)
|
|
151
|
-
COMPREPLY=( $(compgen -W "create list" -- "\${cur}") )
|
|
180
|
+
COMPREPLY=( $(compgen -W "create list search" -- "\${cur}") )
|
|
152
181
|
return 0
|
|
153
182
|
;;
|
|
154
183
|
queues)
|
|
155
184
|
COMPREPLY=( $(compgen -W "snapshot" -- "\${cur}") )
|
|
156
185
|
return 0
|
|
157
186
|
;;
|
|
187
|
+
takedowns)
|
|
188
|
+
COMPREPLY=( $(compgen -W "list" -- "\${cur}") )
|
|
189
|
+
return 0
|
|
190
|
+
;;
|
|
191
|
+
threats)
|
|
192
|
+
COMPREPLY=( $(compgen -W "list" -- "\${cur}") )
|
|
193
|
+
return 0
|
|
194
|
+
;;
|
|
195
|
+
orgs)
|
|
196
|
+
COMPREPLY=( $(compgen -W "list assets asset-groups" -- "\${cur}") )
|
|
197
|
+
return 0
|
|
198
|
+
;;
|
|
199
|
+
assets)
|
|
200
|
+
if [[ "\${COMP_WORDS[COMP_CWORD-2]}" == "orgs" ]]; then
|
|
201
|
+
COMPREPLY=( $(compgen -W "list" -- "\${cur}") )
|
|
202
|
+
return 0
|
|
203
|
+
fi
|
|
204
|
+
;;
|
|
205
|
+
asset-groups)
|
|
206
|
+
if [[ "\${COMP_WORDS[COMP_CWORD-2]}" == "orgs" ]]; then
|
|
207
|
+
COMPREPLY=( $(compgen -W "list" -- "\${cur}") )
|
|
208
|
+
return 0
|
|
209
|
+
fi
|
|
210
|
+
;;
|
|
158
211
|
presets)
|
|
159
212
|
COMPREPLY=( $(compgen -W "list run" -- "\${cur}") )
|
|
160
213
|
return 0
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getValidCredentials
|
|
3
|
+
} from "./chunk-EGWK6SRQ.js";
|
|
4
|
+
import {
|
|
5
|
+
DateTime
|
|
6
|
+
} from "./chunk-TFCNKBRC.js";
|
|
7
|
+
import {
|
|
8
|
+
getConfig
|
|
9
|
+
} from "./chunk-U73SABXK.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/api-client.ts
|
|
12
|
+
function parseIsoDate(value) {
|
|
13
|
+
if (!value) return void 0;
|
|
14
|
+
const dt = DateTime.fromISO(value, { zone: "utc" });
|
|
15
|
+
if (!dt.isValid) {
|
|
16
|
+
throw new Error(`Invalid ISO date: '${value}'. Use YYYY-MM-DD or full ISO 8601.`);
|
|
17
|
+
}
|
|
18
|
+
return dt.toJSDate();
|
|
19
|
+
}
|
|
20
|
+
function parseIsoDateString(value) {
|
|
21
|
+
return parseIsoDate(value)?.toISOString();
|
|
22
|
+
}
|
|
23
|
+
var REPORT_REVIEW_DECISIONS = ["APPROVE", "REJECT", "SKIP", "ESCALATE"];
|
|
24
|
+
var REPORT_STATUSES = ["TODO", "IN_PROGRESS", "CLOSED"];
|
|
25
|
+
var DETECTION_CONFIDENCE_LEVELS = ["none", "low", "medium", "high"];
|
|
26
|
+
var DETECTION_REPORTED_FILTERS = ["reported", "not_reported"];
|
|
27
|
+
var LIVENESS_FILTER_VALUES = ["ALIVE", "DEAD", "UNKNOWN"];
|
|
28
|
+
var WATCHLIST_FILTER_VALUES = ["ENABLED", "DISABLED"];
|
|
29
|
+
var TAKEDOWN_STATUSES = [
|
|
30
|
+
"TODO",
|
|
31
|
+
"IN_PROGRESS",
|
|
32
|
+
"COMPLETED",
|
|
33
|
+
"CANCELLED",
|
|
34
|
+
"PENDING_RETRACTION",
|
|
35
|
+
"RETRACTION_SENT",
|
|
36
|
+
"RETRACTED",
|
|
37
|
+
"PENDING_INPUT"
|
|
38
|
+
];
|
|
39
|
+
var LIVENESS_STATUSES = ["UNKNOWN", "ALIVE", "DEAD"];
|
|
40
|
+
var TAKEDOWN_SORT_KEYS = [
|
|
41
|
+
"updatedAt",
|
|
42
|
+
"createdAt",
|
|
43
|
+
"takedownStatus",
|
|
44
|
+
"takedownUpdatedAt",
|
|
45
|
+
"assigneeId",
|
|
46
|
+
"brandId"
|
|
47
|
+
];
|
|
48
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
49
|
+
function defaultGetCredential() {
|
|
50
|
+
const envKey = process.env.CHAINPATROL_API_KEY;
|
|
51
|
+
if (envKey && envKey.trim().length > 0) {
|
|
52
|
+
return { kind: "api-key", value: envKey.trim() };
|
|
53
|
+
}
|
|
54
|
+
return { kind: "bearer", value: getValidCredentials().accessToken };
|
|
55
|
+
}
|
|
56
|
+
function createApiClient(options) {
|
|
57
|
+
const config = getConfig();
|
|
58
|
+
const apiUrl = options?.apiUrl ?? config.apiUrl;
|
|
59
|
+
const getCredential = options?.getCredential ?? (options?.getToken ? () => ({ kind: "bearer", value: options.getToken() }) : defaultGetCredential);
|
|
60
|
+
function buildAuthHeaders() {
|
|
61
|
+
const credential = getCredential();
|
|
62
|
+
const headers = {};
|
|
63
|
+
if (credential.kind === "api-key") {
|
|
64
|
+
headers["x-api-key"] = credential.value;
|
|
65
|
+
} else {
|
|
66
|
+
headers["Authorization"] = `Bearer ${credential.value}`;
|
|
67
|
+
}
|
|
68
|
+
return headers;
|
|
69
|
+
}
|
|
70
|
+
async function requestGet(path, query) {
|
|
71
|
+
const headers = buildAuthHeaders();
|
|
72
|
+
const search = new URLSearchParams();
|
|
73
|
+
for (const [key, value] of Object.entries(query)) {
|
|
74
|
+
if (value !== void 0 && value !== "") {
|
|
75
|
+
search.set(key, value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const queryString = search.toString();
|
|
79
|
+
const url = `${apiUrl}/api/v2${path}${queryString ? `?${queryString}` : ""}`;
|
|
80
|
+
let res;
|
|
81
|
+
try {
|
|
82
|
+
res = await fetch(url, {
|
|
83
|
+
method: "GET",
|
|
84
|
+
headers,
|
|
85
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
86
|
+
});
|
|
87
|
+
} catch (err) {
|
|
88
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
89
|
+
throw new Error(
|
|
90
|
+
"Request timed out. Check your network connection and try again."
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
if (err instanceof TypeError && err.code === "ECONNREFUSED") {
|
|
94
|
+
throw new Error(`Cannot connect to ${apiUrl}. Is the server running?`);
|
|
95
|
+
}
|
|
96
|
+
throw new Error("Network error. Check your internet connection and try again.");
|
|
97
|
+
}
|
|
98
|
+
return handleResponse(res);
|
|
99
|
+
}
|
|
100
|
+
async function request(path, body) {
|
|
101
|
+
const headers = buildAuthHeaders();
|
|
102
|
+
headers["Content-Type"] = "application/json";
|
|
103
|
+
let res;
|
|
104
|
+
try {
|
|
105
|
+
res = await fetch(`${apiUrl}/api/v2${path}`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers,
|
|
108
|
+
body: JSON.stringify(body),
|
|
109
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
110
|
+
});
|
|
111
|
+
} catch (err) {
|
|
112
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
113
|
+
throw new Error(
|
|
114
|
+
"Request timed out. Check your network connection and try again."
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (err instanceof TypeError && err.code === "ECONNREFUSED") {
|
|
118
|
+
throw new Error(`Cannot connect to ${apiUrl}. Is the server running?`);
|
|
119
|
+
}
|
|
120
|
+
throw new Error("Network error. Check your internet connection and try again.");
|
|
121
|
+
}
|
|
122
|
+
return handleResponse(res);
|
|
123
|
+
}
|
|
124
|
+
async function handleResponse(res) {
|
|
125
|
+
if (!res.ok) {
|
|
126
|
+
let errorMessageFromResponse = null;
|
|
127
|
+
try {
|
|
128
|
+
const errorBody = await res.json();
|
|
129
|
+
errorMessageFromResponse = errorBody.message ?? null;
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
if (res.status === 401) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
errorMessageFromResponse ?? "Authentication failed. Run `chainpatrol login` to re-authenticate."
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (res.status === 403) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
errorMessageFromResponse ?? "You don't have permission to access this resource. Check your --org slug and permissions."
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
if (res.status === 404) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
errorMessageFromResponse ?? "Organization not found. Check your --org slug."
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (res.status === 422) {
|
|
148
|
+
throw new Error(errorMessageFromResponse ?? "Request validation failed.");
|
|
149
|
+
}
|
|
150
|
+
if (res.status >= 500) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
"ChainPatrol API is temporarily unavailable. Please try again later."
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
throw new Error(
|
|
156
|
+
errorMessageFromResponse ?? `Request failed (${res.status}). Run with --json for details.`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return await res.json();
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
assetCheck(input) {
|
|
163
|
+
return request("/asset/check", input);
|
|
164
|
+
},
|
|
165
|
+
listDetectionConfigs(slug) {
|
|
166
|
+
return request("/detection/configs/list", { slug });
|
|
167
|
+
},
|
|
168
|
+
updateDetectionConfig(input) {
|
|
169
|
+
return request("/detection/configs/update", input);
|
|
170
|
+
},
|
|
171
|
+
runDetectionConfigs(input) {
|
|
172
|
+
return request("/detection/configs/run", input);
|
|
173
|
+
},
|
|
174
|
+
validateDetectionConfigs(input) {
|
|
175
|
+
return request("/detection/configs/validate", input);
|
|
176
|
+
},
|
|
177
|
+
getDetectionDrift(input) {
|
|
178
|
+
return request("/detection/drift", {
|
|
179
|
+
...input,
|
|
180
|
+
startDate: parseIsoDate(input.startDate),
|
|
181
|
+
endDate: parseIsoDate(input.endDate)
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
getOperationsQueuesSnapshot(input) {
|
|
185
|
+
return request(
|
|
186
|
+
"/operations/queues/snapshot",
|
|
187
|
+
input
|
|
188
|
+
);
|
|
189
|
+
},
|
|
190
|
+
getMetricsSummary(input) {
|
|
191
|
+
return request("/metrics/summary", {
|
|
192
|
+
...input,
|
|
193
|
+
startDate: parseIsoDate(input.startDate),
|
|
194
|
+
endDate: parseIsoDate(input.endDate)
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
getMetricsFound(input) {
|
|
198
|
+
return request("/metrics/found", {
|
|
199
|
+
...input,
|
|
200
|
+
startDate: parseIsoDate(input.startDate),
|
|
201
|
+
endDate: parseIsoDate(input.endDate)
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
getMetricsBreakdown(input) {
|
|
205
|
+
return request("/metrics/breakdown", {
|
|
206
|
+
...input,
|
|
207
|
+
startDate: parseIsoDate(input.startDate),
|
|
208
|
+
endDate: parseIsoDate(input.endDate)
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
createReport(input) {
|
|
212
|
+
return request("/report/create", input);
|
|
213
|
+
},
|
|
214
|
+
listOrganizationReports(input) {
|
|
215
|
+
return request("/public/getOrganizationReports", {
|
|
216
|
+
slug: input.slug,
|
|
217
|
+
limit: input.limit ?? 10,
|
|
218
|
+
cursor: input.cursor,
|
|
219
|
+
status: input.status,
|
|
220
|
+
searchQuery: input.searchQuery,
|
|
221
|
+
reporterQuery: input.reporterQuery,
|
|
222
|
+
reportedByCustomer: input.reportedByCustomer,
|
|
223
|
+
excludeAutomation: input.excludeAutomation,
|
|
224
|
+
onlyRejected: input.onlyRejected,
|
|
225
|
+
reviewStatuses: input.reviewStatuses?.length ? input.reviewStatuses : void 0,
|
|
226
|
+
assetTypes: input.assetTypes?.length ? input.assetTypes : void 0,
|
|
227
|
+
brandIds: input.brandIds?.length ? input.brandIds : void 0,
|
|
228
|
+
countryCodes: input.countryCodes?.length ? input.countryCodes : void 0,
|
|
229
|
+
reviewedByUserId: input.reviewedByUserId,
|
|
230
|
+
startDate: parseIsoDateString(input.startDate),
|
|
231
|
+
endDate: parseIsoDateString(input.endDate),
|
|
232
|
+
updatedAtStartDate: parseIsoDateString(input.updatedAtStartDate),
|
|
233
|
+
updatedAtEndDate: parseIsoDateString(input.updatedAtEndDate)
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
listTakedowns(input) {
|
|
237
|
+
return request("/takedowns/list", {
|
|
238
|
+
organizationSlug: input.organizationSlug,
|
|
239
|
+
query: input.query,
|
|
240
|
+
startDate: parseIsoDateString(input.startDate),
|
|
241
|
+
endDate: parseIsoDateString(input.endDate),
|
|
242
|
+
assetType: input.assetType,
|
|
243
|
+
takedownStatus: input.takedownStatus,
|
|
244
|
+
livenessStatus: input.livenessStatus,
|
|
245
|
+
brandIds: input.brandIds?.length ? input.brandIds : void 0,
|
|
246
|
+
assigneeIds: input.assigneeIds?.length ? input.assigneeIds : void 0,
|
|
247
|
+
startedAtStartDate: parseIsoDateString(input.startedAtStartDate),
|
|
248
|
+
startedAtEndDate: parseIsoDateString(input.startedAtEndDate),
|
|
249
|
+
hideAutomatedTakedowns: input.hideAutomatedTakedowns,
|
|
250
|
+
hideAutomatedLivenessChecks: input.hideAutomatedLivenessChecks,
|
|
251
|
+
sorting: input.sorting,
|
|
252
|
+
per_page: input.perPage,
|
|
253
|
+
next_page: input.nextPage
|
|
254
|
+
});
|
|
255
|
+
},
|
|
256
|
+
getOrganizationMetrics(input) {
|
|
257
|
+
return requestGet("/organization/metrics", {
|
|
258
|
+
organizationSlug: input.organizationSlug,
|
|
259
|
+
brandSlug: input.brandSlug,
|
|
260
|
+
startDate: parseIsoDateString(input.startDate),
|
|
261
|
+
endDate: parseIsoDateString(input.endDate)
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
listHealthchecks() {
|
|
265
|
+
return request("/healthchecks/list", {});
|
|
266
|
+
},
|
|
267
|
+
runHealthcheck(endpoint, input) {
|
|
268
|
+
return request(endpoint, input);
|
|
269
|
+
},
|
|
270
|
+
getUserOrgs(input) {
|
|
271
|
+
return request("/user/orgs", input);
|
|
272
|
+
},
|
|
273
|
+
listAssets(input) {
|
|
274
|
+
return request("/asset/list", {
|
|
275
|
+
type: input.type,
|
|
276
|
+
status: input.status,
|
|
277
|
+
startDate: parseIsoDateString(input.startDate),
|
|
278
|
+
endDate: parseIsoDateString(input.endDate),
|
|
279
|
+
per_page: input.perPage,
|
|
280
|
+
next_page: input.nextPage
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
listThreats(input) {
|
|
284
|
+
return request("/threats/list", {
|
|
285
|
+
query: input.query,
|
|
286
|
+
startDate: parseIsoDateString(input.startDate),
|
|
287
|
+
endDate: parseIsoDateString(input.endDate),
|
|
288
|
+
assetType: input.assetType,
|
|
289
|
+
sorting: input.sorting,
|
|
290
|
+
per_page: input.perPage,
|
|
291
|
+
next_page: input.nextPage
|
|
292
|
+
});
|
|
293
|
+
},
|
|
294
|
+
listDetections(input) {
|
|
295
|
+
const filters = [];
|
|
296
|
+
if (input.sources?.length) {
|
|
297
|
+
filters.push({ property: "source", operator: "in", value: input.sources });
|
|
298
|
+
}
|
|
299
|
+
if (input.confidence?.length) {
|
|
300
|
+
filters.push({ property: "confidence", operator: "in", value: input.confidence });
|
|
301
|
+
}
|
|
302
|
+
if (input.assetStatus?.length) {
|
|
303
|
+
filters.push({
|
|
304
|
+
property: "assetStatus",
|
|
305
|
+
operator: "in",
|
|
306
|
+
value: input.assetStatus
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
if (input.assetType?.length) {
|
|
310
|
+
filters.push({ property: "assetType", operator: "in", value: input.assetType });
|
|
311
|
+
}
|
|
312
|
+
if (input.brandIds?.length) {
|
|
313
|
+
filters.push({ property: "brand", operator: "in", value: input.brandIds });
|
|
314
|
+
}
|
|
315
|
+
if (input.liveness?.length) {
|
|
316
|
+
filters.push({ property: "liveness", operator: "in", value: input.liveness });
|
|
317
|
+
}
|
|
318
|
+
if (input.watchlist?.length) {
|
|
319
|
+
filters.push({ property: "watchlist", operator: "in", value: input.watchlist });
|
|
320
|
+
}
|
|
321
|
+
if (input.reported?.length) {
|
|
322
|
+
filters.push({ property: "reported", operator: "in", value: input.reported });
|
|
323
|
+
}
|
|
324
|
+
if (input.countryCodes?.length) {
|
|
325
|
+
filters.push({
|
|
326
|
+
property: "countryCode",
|
|
327
|
+
operator: "in",
|
|
328
|
+
value: input.countryCodes
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
if (input.onlyDeleted) {
|
|
332
|
+
filters.push({ property: "deleted", operator: "in", value: ["deleted"] });
|
|
333
|
+
}
|
|
334
|
+
return request("/detection/list", {
|
|
335
|
+
slug: input.slug,
|
|
336
|
+
cursor: input.cursor,
|
|
337
|
+
limit: input.limit,
|
|
338
|
+
query: input.query,
|
|
339
|
+
startDate: parseIsoDate(input.startDate),
|
|
340
|
+
endDate: parseIsoDate(input.endDate),
|
|
341
|
+
filters: filters.length > 0 ? filters : void 0
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
searchReports(input) {
|
|
345
|
+
return request("/reports/search", input);
|
|
346
|
+
},
|
|
347
|
+
listOrganizationAssets(input) {
|
|
348
|
+
return requestGet("/organization/assets", {
|
|
349
|
+
type: input.type,
|
|
350
|
+
groupId: input.groupId !== void 0 ? String(input.groupId) : void 0,
|
|
351
|
+
query: input.query,
|
|
352
|
+
per_page: input.perPage !== void 0 ? String(input.perPage) : void 0,
|
|
353
|
+
next_page: input.nextPage
|
|
354
|
+
});
|
|
355
|
+
},
|
|
356
|
+
listOrganizationAssetGroups() {
|
|
357
|
+
return requestGet(
|
|
358
|
+
"/organization/asset-groups",
|
|
359
|
+
{}
|
|
360
|
+
);
|
|
361
|
+
},
|
|
362
|
+
getCurrentUser() {
|
|
363
|
+
return request("/user/me", {});
|
|
364
|
+
},
|
|
365
|
+
validateApiKey() {
|
|
366
|
+
return requestGet("/validate", {});
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export {
|
|
372
|
+
REPORT_REVIEW_DECISIONS,
|
|
373
|
+
REPORT_STATUSES,
|
|
374
|
+
DETECTION_CONFIDENCE_LEVELS,
|
|
375
|
+
DETECTION_REPORTED_FILTERS,
|
|
376
|
+
LIVENESS_FILTER_VALUES,
|
|
377
|
+
WATCHLIST_FILTER_VALUES,
|
|
378
|
+
TAKEDOWN_STATUSES,
|
|
379
|
+
LIVENESS_STATUSES,
|
|
380
|
+
TAKEDOWN_SORT_KEYS,
|
|
381
|
+
createApiClient
|
|
382
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
installCompletions,
|
|
3
3
|
uninstallCompletions
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NQT77IB7.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/setup-skill.ts
|
|
7
7
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, readFileSync as readFileSync3, rmSync } from "fs";
|