@chainpatrol/cli 0.16.0 → 0.18.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 +48 -0
- package/dist/{breakdown-PQXHY2VO.js → breakdown-ETSF2BZ3.js} +1 -1
- package/dist/{check-5B4EPWOZ.js → check-EMGFDXUO.js} +1 -1
- package/dist/{chunk-JEBZIBRI.js → chunk-DPLUSURP.js} +6 -0
- package/dist/{chunk-CJPWEWGS.js → chunk-HGAQBGGL.js} +1 -1
- package/dist/{chunk-TTLGCRRR.js → chunk-MDDC4F6Q.js} +76 -9
- package/dist/cli.js +63 -39
- package/dist/{configs-update-6BYB7M37.js → configs-update-EKNLIRA6.js} +1 -1
- package/dist/{create-Y6Z4L656.js → create-M4PV5VVU.js} +1 -1
- package/dist/{drift-5EZK2JA5.js → drift-RQKTGJWB.js} +1 -1
- package/dist/{found-XRJZ4SSY.js → found-LVYBEOS6.js} +1 -1
- package/dist/get-YFYSJFBC.js +74 -0
- package/dist/{healthcheck-47MU5AZ7.js → healthcheck-J6BIZEG7.js} +1 -1
- package/dist/{list-G2F2IFEU.js → list-2ENAEZVP.js} +1 -1
- package/dist/{list-2JCBA3Q2.js → list-44BQZHJD.js} +1 -1
- package/dist/{list-GPWZ52JD.js → list-AEM2KSO4.js} +1 -1
- package/dist/{list-AYXZG3I6.js → list-CNF2FGLN.js} +1 -1
- package/dist/{list-JD4U2SBV.js → list-E2JVJNHV.js} +1 -1
- package/dist/{list-WBZIULUS.js → list-JCJHIJM4.js} +2 -2
- package/dist/{list-FGDMMAPM.js → list-LKNCICLT.js} +1 -1
- package/dist/{list-IA2LRT4X.js → list-O36VWTWR.js} +1 -1
- package/dist/{list-QC7DUKFD.js → list-O62BZKQ5.js} +1 -1
- package/dist/{list-ZIM2MR2Q.js → list-S5Y6GW43.js} +1 -1
- package/dist/{list-KFFNLKZK.js → list-XUYCZG7S.js} +13 -11
- package/dist/{list-json-DXPR3UEY.js → list-json-ZTS5GXNA.js} +1 -1
- package/dist/{organization-NR6JCD5I.js → organization-PFPBZXJZ.js} +1 -1
- package/dist/{run-HDEKIP4L.js → run-HS2EEOM6.js} +1 -1
- package/dist/{run-ANHA5JFB.js → run-LKPKTH3W.js} +2 -2
- package/dist/{run-EJBBPBOR.js → run-R3RR6XQF.js} +1 -1
- package/dist/{search-PBVQ7473.js → search-EBXEP7XC.js} +1 -1
- package/dist/{setup-skill-2RKWIVGS.js → setup-skill-Z6SBI6GC.js} +1 -1
- package/dist/{snapshot-U53T5Q2M.js → snapshot-GNZMYTXT.js} +1 -1
- package/dist/{summary-2IXOMOIA.js → summary-POVQC6B7.js} +1 -1
- package/dist/{validate-LXE3JPET.js → validate-QE2F4PYY.js} +1 -1
- package/dist/{whoami-4XDWPKVV.js → whoami-24KUJUN4.js} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0825606: Drop `automated` from the per-service shape of `orgs list` / `orgs get`
|
|
8
|
+
(and the matching `/user/orgs` and `/user/orgs/{slug}` public APIs) for
|
|
9
|
+
every service except `takedowns`. `automated` only ever had operational
|
|
10
|
+
meaning for takedowns — it controls whether ChainPatrol files the
|
|
11
|
+
takedown on its own. The `isAutomated*Active` columns on
|
|
12
|
+
reporting/reviewing/protection have no runtime effect, so exposing them
|
|
13
|
+
in the public API only invited misleading filters and CSV columns.
|
|
14
|
+
|
|
15
|
+
Concretely:
|
|
16
|
+
|
|
17
|
+
- API response: `services.reporting`, `services.reviewing`, and
|
|
18
|
+
`services.protection` now return `{ "active": boolean }` only.
|
|
19
|
+
`services.takedowns` still returns `{ "active": boolean, "automated":
|
|
20
|
+
boolean }`. `detection` and `darkWebMonitoring` are unchanged.
|
|
21
|
+
- API services filter: same — `reporting`, `reviewing`, and
|
|
22
|
+
`protection` no longer accept an `automated` filter. Only
|
|
23
|
+
`takedowns` does.
|
|
24
|
+
- CLI: `--service-automated` / `--service-manual` now only accept
|
|
25
|
+
`takedowns`. Passing any other service name errors out with a
|
|
26
|
+
clearer message.
|
|
27
|
+
- CLI CSV output: drops the `reportingAutomated` / `reviewingAutomated`
|
|
28
|
+
/ `protectionAutomated` columns. Only `takedownsAutomated` remains.
|
|
29
|
+
- Skill description and OpenAPI endpoint descriptions explain the
|
|
30
|
+
new shape.
|
|
31
|
+
|
|
32
|
+
Server-side work in @chainpatrol/external-trpc and @chainpatrol/validation
|
|
33
|
+
supports the new shape; both are private packages and don't need
|
|
34
|
+
version bumps.
|
|
35
|
+
|
|
36
|
+
## 0.17.0
|
|
37
|
+
|
|
38
|
+
### Minor Changes
|
|
39
|
+
|
|
40
|
+
- 27b18af: Adds `chainpatrol orgs get <slug>` for fetching a single accessible
|
|
41
|
+
organization, backed by a new public `GET /user/orgs/{slug}` endpoint.
|
|
42
|
+
Returns the same per-org shape as one row of `orgs list` (subscription
|
|
43
|
+
status + per-service active/automated flags) and reuses the same access
|
|
44
|
+
gating: org-scoped API keys must match the slug, user sessions / user-scoped
|
|
45
|
+
API keys need an active membership unless the caller is staff. The bundled
|
|
46
|
+
Claude Code skill (`/chainpatrol`) is updated to document the new command.
|
|
47
|
+
Server-side procedure + validation live in the private `@chainpatrol/external-trpc`
|
|
48
|
+
and `@chainpatrol/validation` packages and ship together with this CLI
|
|
49
|
+
release, but are not listed in the frontmatter because they are private.
|
|
50
|
+
|
|
3
51
|
## 0.16.0
|
|
4
52
|
|
|
5
53
|
### Minor Changes
|
|
@@ -297,6 +297,12 @@ function createApiClient(options) {
|
|
|
297
297
|
getUserOrgs(input) {
|
|
298
298
|
return request("/user/orgs", input);
|
|
299
299
|
},
|
|
300
|
+
getUserOrg(input) {
|
|
301
|
+
return requestGet(
|
|
302
|
+
`/user/orgs/${encodeURIComponent(input.slug)}`,
|
|
303
|
+
{}
|
|
304
|
+
);
|
|
305
|
+
},
|
|
300
306
|
listAssets(input) {
|
|
301
307
|
return request("/asset/list", {
|
|
302
308
|
type: input.type,
|
|
@@ -195,6 +195,8 @@ description: |
|
|
|
195
195
|
"customer reports", "reports reported by customer", "find detection gaps",
|
|
196
196
|
"org healthcheck", "organization health check", "audit my org",
|
|
197
197
|
"what's wrong with org", "review org setup", "list orgs", "list organizations",
|
|
198
|
+
"get org", "get organization", "show org details", "org by slug",
|
|
199
|
+
"fetch org details", "org info",
|
|
198
200
|
"orgs with takedowns off", "automation off across orgs",
|
|
199
201
|
"which customers have X enabled", "service toggles by org",
|
|
200
202
|
"is this URL blocked", "is this domain blocked", "is this address blocked",
|
|
@@ -624,10 +626,10 @@ Use \`--all\` to snapshot every org you have access to instead of a single slug.
|
|
|
624
626
|
|
|
625
627
|
Returns every organization the caller can see, with each org's
|
|
626
628
|
subscription status (\`PROSPECT\`, \`TRIAL\`, \`ACTIVE\`, \`INTEGRATION\`) and
|
|
627
|
-
which services are active
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
629
|
+
which services are active. Use it to answer questions like "which
|
|
630
|
+
customers have takedowns enabled but automation off?" or "which prospects
|
|
631
|
+
don't have detection turned on yet?" \u2014 filters compose with AND and are
|
|
632
|
+
applied server-side, so one call returns the final list.
|
|
631
633
|
|
|
632
634
|
\`\`\`bash
|
|
633
635
|
chainpatrol --json orgs list \\
|
|
@@ -636,6 +638,40 @@ chainpatrol --json orgs list \\
|
|
|
636
638
|
--service-manual takedowns
|
|
637
639
|
\`\`\`
|
|
638
640
|
|
|
641
|
+
#### Per-service response shape \u2014 \`automated\` is takedowns-only
|
|
642
|
+
|
|
643
|
+
Every service exposes an \`active\` boolean. **Only \`takedowns\`
|
|
644
|
+
additionally exposes \`automated\`** \u2014 that is the one service where the
|
|
645
|
+
manual-vs-automated distinction changes real platform behavior (whether
|
|
646
|
+
ChainPatrol files the takedown on its own, or queues it for a human to
|
|
647
|
+
file). \`reporting\`, \`reviewing\`, and \`protection\` have backing
|
|
648
|
+
\`isAutomated*Active\` columns in the database, but those flags have no
|
|
649
|
+
operational effect today, so the API deliberately omits them from both
|
|
650
|
+
the response and the \`services\` filter \u2014 surfacing them would invite
|
|
651
|
+
misleading filters like "reporting.automated=true" that don't mean
|
|
652
|
+
anything. \`detection\` and \`darkWebMonitoring\` have always been
|
|
653
|
+
single-flag services.
|
|
654
|
+
|
|
655
|
+
So per-org JSON looks like:
|
|
656
|
+
|
|
657
|
+
\`\`\`json
|
|
658
|
+
{
|
|
659
|
+
"services": {
|
|
660
|
+
"reporting": { "active": true },
|
|
661
|
+
"reviewing": { "active": true },
|
|
662
|
+
"protection": { "active": false },
|
|
663
|
+
"takedowns": { "active": true, "automated": false },
|
|
664
|
+
"detection": { "active": true },
|
|
665
|
+
"darkWebMonitoring": { "active": false }
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
\`\`\`
|
|
669
|
+
|
|
670
|
+
When a user asks about "automated reporting / reviewing / protection",
|
|
671
|
+
explain that the flag exists in the DB but has no operational effect and
|
|
672
|
+
isn't exposed by the public API \u2014 only \`takedowns.automated\` carries a
|
|
673
|
+
real meaning.
|
|
674
|
+
|
|
639
675
|
Filter flags (all optional, all comma-separated lists):
|
|
640
676
|
|
|
641
677
|
- \`--query <text>\` partial name match (substring, case-insensitive)
|
|
@@ -644,11 +680,11 @@ Filter flags (all optional, all comma-separated lists):
|
|
|
644
680
|
through this filter \u2014 \`orgs list\` only ever returns live customers.
|
|
645
681
|
- \`--service-active <list>\` services that must be active
|
|
646
682
|
- \`--service-inactive <list>\` services that must be inactive
|
|
647
|
-
- \`--service-automated <list>\` services whose automation must be ON
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
- \`--service-manual <list>\` services whose automation must be OFF
|
|
651
|
-
|
|
683
|
+
- \`--service-automated <list>\` services whose automation must be ON.
|
|
684
|
+
**Only \`takedowns\` is accepted** \u2014 the other services don't have a
|
|
685
|
+
meaningful automation toggle. Passing any other service name errors out.
|
|
686
|
+
- \`--service-manual <list>\` services whose automation must be OFF.
|
|
687
|
+
Same restriction \u2014 only \`takedowns\`.
|
|
652
688
|
|
|
653
689
|
Service names: \`reporting\`, \`reviewing\`, \`protection\`, \`takedowns\`,
|
|
654
690
|
\`detection\`, \`darkWebMonitoring\`.
|
|
@@ -657,6 +693,37 @@ Customers see only orgs they're a member of. Staff/superuser sessions see
|
|
|
657
693
|
every matching org. The response is the same in both cases; visibility is
|
|
658
694
|
enforced server-side.
|
|
659
695
|
|
|
696
|
+
### \`orgs get\` \u2014 Get a single organization by slug
|
|
697
|
+
|
|
698
|
+
Look up one organization the caller has access to. Returns the same per-org
|
|
699
|
+
shape as a single row from \`orgs list\` \u2014 \`active\` for every service,
|
|
700
|
+
plus \`automated\` on \`takedowns\` only (see the note above on why other
|
|
701
|
+
services don't expose an automation flag). Anything you could read from
|
|
702
|
+
\`orgs list\` you can also read here without paging or filtering. Use it
|
|
703
|
+
when the user names a specific customer ("show me acme's setup", "is
|
|
704
|
+
takedowns automation on for morpho?") and you don't need the rest of the
|
|
705
|
+
catalogue.
|
|
706
|
+
|
|
707
|
+
\`\`\`bash
|
|
708
|
+
chainpatrol orgs get <slug>
|
|
709
|
+
chainpatrol --json orgs get <slug>
|
|
710
|
+
\`\`\`
|
|
711
|
+
|
|
712
|
+
Permission rules match \`orgs list\`:
|
|
713
|
+
|
|
714
|
+
- Org-scoped API keys: must match the slug \u2014 querying another org returns
|
|
715
|
+
403.
|
|
716
|
+
- User sessions / user-scoped API keys: need an active OrganizationMembership
|
|
717
|
+
on the slug. Staff/superusers can read any org.
|
|
718
|
+
- Soft-deleted orgs are not returned (404). A 404 also fires for orgs the
|
|
719
|
+
caller would not be authorized to see \u2014 the endpoint deliberately does
|
|
720
|
+
not distinguish "doesn't exist" from "you can't see this" beyond the
|
|
721
|
+
generic 403/404 envelope.
|
|
722
|
+
|
|
723
|
+
Prefer \`orgs get\` over \`orgs list\` + client-side filter whenever the
|
|
724
|
+
caller already knows the slug; it's one round-trip and side-steps the
|
|
725
|
+
list filters entirely.
|
|
726
|
+
|
|
660
727
|
#### Use case: finding service configuration gaps across the customer base
|
|
661
728
|
|
|
662
729
|
When the user asks something like "which customers are paying us but don't
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getCliVersion,
|
|
14
14
|
isSkillInstalled,
|
|
15
15
|
readInstalledSkillVersion
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MDDC4F6Q.js";
|
|
17
17
|
import "./chunk-NQT77IB7.js";
|
|
18
18
|
import {
|
|
19
19
|
DateTime
|
|
@@ -474,10 +474,11 @@ var HELP = {
|
|
|
474
474
|
]
|
|
475
475
|
},
|
|
476
476
|
orgs: {
|
|
477
|
-
description: "List organizations, their assets, and asset groups. Top-level `orgs list` lists organizations accessible to you; the nested subcommands operate on the org tied to your API key.",
|
|
478
|
-
usage: "chainpatrol orgs <list|assets list|asset-groups list>",
|
|
477
|
+
description: "List organizations, their assets, and asset groups. Top-level `orgs list` lists organizations accessible to you; `orgs get <slug>` returns details for a single accessible org; the nested subcommands operate on the org tied to your API key.",
|
|
478
|
+
usage: "chainpatrol orgs <list|get <slug>|assets list|asset-groups list>",
|
|
479
479
|
examples: [
|
|
480
480
|
"chainpatrol orgs list",
|
|
481
|
+
"chainpatrol orgs get acme",
|
|
481
482
|
"chainpatrol orgs assets list --asset-type URL",
|
|
482
483
|
"chainpatrol orgs asset-groups list"
|
|
483
484
|
]
|
|
@@ -512,15 +513,15 @@ var HELP = {
|
|
|
512
513
|
examples: ["chainpatrol orgs asset-groups list --output csv"]
|
|
513
514
|
},
|
|
514
515
|
"orgs list": {
|
|
515
|
-
description: "List organizations with their subscription status and per-service active
|
|
516
|
+
description: "List organizations with their subscription status and per-service active flag (plus `automated` for takedowns only \u2014 that's the one service where manual-vs-automated changes real platform behavior). All filters compose with AND.",
|
|
516
517
|
usage: "chainpatrol orgs list [filters]",
|
|
517
518
|
options: [
|
|
518
519
|
"--query <text> Partial name match (substring, case-insensitive)",
|
|
519
520
|
"--subscription-status <l> Comma-separated list (PROSPECT,TRIAL,ACTIVE,INTEGRATION)",
|
|
520
521
|
"--service-active <l> Comma-separated services that must be active",
|
|
521
522
|
"--service-inactive <l> Comma-separated services that must be inactive",
|
|
522
|
-
"--service-automated <l> Services whose automation must be ON (
|
|
523
|
-
"--service-manual <l> Services whose automation must be OFF (
|
|
523
|
+
"--service-automated <l> Services whose automation must be ON (only `takedowns` is accepted \u2014 the other services have no meaningful automation toggle)",
|
|
524
|
+
"--service-manual <l> Services whose automation must be OFF (only `takedowns` is accepted)"
|
|
524
525
|
],
|
|
525
526
|
examples: [
|
|
526
527
|
"chainpatrol orgs list --subscription-status ACTIVE",
|
|
@@ -528,6 +529,18 @@ var HELP = {
|
|
|
528
529
|
"chainpatrol --json orgs list --subscription-status ACTIVE,TRIAL --service-active detection"
|
|
529
530
|
]
|
|
530
531
|
},
|
|
532
|
+
"orgs get": {
|
|
533
|
+
description: "Get a single organization by slug. Returns the same shape as one row of `orgs list` (subscription status + per-service active flag, with `automated` exposed only for takedowns \u2014 the one service where manual-vs-automated changes real platform behavior). Caller must have access: org-scoped API keys must match the slug, user sessions/keys need an active membership unless the user is staff.",
|
|
534
|
+
usage: "chainpatrol orgs get <slug>",
|
|
535
|
+
options: [
|
|
536
|
+
"--org <slug> Use the saved default org instead of a positional argument."
|
|
537
|
+
],
|
|
538
|
+
examples: [
|
|
539
|
+
"chainpatrol orgs get acme",
|
|
540
|
+
"chainpatrol --json orgs get acme",
|
|
541
|
+
"chainpatrol orgs get acme --output markdown"
|
|
542
|
+
]
|
|
543
|
+
},
|
|
531
544
|
healthchecks: {
|
|
532
545
|
description: "Run organization healthchecks via the public API. Use `list` to see every available check (including planned ones not yet implemented on the backend) and `run` to execute one or all implemented checks.",
|
|
533
546
|
usage: "chainpatrol healthchecks <list|run <id>|run --all>",
|
|
@@ -1041,12 +1054,12 @@ function parseAttachmentUrls() {
|
|
|
1041
1054
|
}
|
|
1042
1055
|
async function handleConfigsList(org) {
|
|
1043
1056
|
if (jsonMode) {
|
|
1044
|
-
const { listConfigsJson } = await import("./list-json-
|
|
1057
|
+
const { listConfigsJson } = await import("./list-json-ZTS5GXNA.js");
|
|
1045
1058
|
await listConfigsJson({ org });
|
|
1046
1059
|
return;
|
|
1047
1060
|
}
|
|
1048
1061
|
const { render } = await import("ink");
|
|
1049
|
-
const { default: ConfigsList } = await import("./list-
|
|
1062
|
+
const { default: ConfigsList } = await import("./list-AEM2KSO4.js");
|
|
1050
1063
|
const { default: React } = await import("react");
|
|
1051
1064
|
render(React.createElement(ConfigsList, { org }));
|
|
1052
1065
|
}
|
|
@@ -1146,7 +1159,7 @@ async function main() {
|
|
|
1146
1159
|
const positionals = cli.input.slice(2);
|
|
1147
1160
|
const flagAssets = parseAssetInputs();
|
|
1148
1161
|
const contents = [...positionals, ...flagAssets];
|
|
1149
|
-
const { runAssetCheck } = await import("./check-
|
|
1162
|
+
const { runAssetCheck } = await import("./check-EMGFDXUO.js");
|
|
1150
1163
|
await runAssetCheck({
|
|
1151
1164
|
contents,
|
|
1152
1165
|
json: jsonMode,
|
|
@@ -1156,7 +1169,7 @@ async function main() {
|
|
|
1156
1169
|
break;
|
|
1157
1170
|
}
|
|
1158
1171
|
if (subcommand === "list") {
|
|
1159
|
-
const { runAssetList } = await import("./list-
|
|
1172
|
+
const { runAssetList } = await import("./list-2ENAEZVP.js");
|
|
1160
1173
|
await runAssetList({
|
|
1161
1174
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1162
1175
|
status: cli.flags.assetStatus ?? cli.flags.status,
|
|
@@ -1177,7 +1190,7 @@ async function main() {
|
|
|
1177
1190
|
case "detections": {
|
|
1178
1191
|
const org = await resolveOrg();
|
|
1179
1192
|
if (subcommand === "healthcheck") {
|
|
1180
|
-
const { runDetectionsHealthcheck } = await import("./healthcheck-
|
|
1193
|
+
const { runDetectionsHealthcheck } = await import("./healthcheck-J6BIZEG7.js");
|
|
1181
1194
|
await runDetectionsHealthcheck({
|
|
1182
1195
|
org,
|
|
1183
1196
|
source: cli.flags.source,
|
|
@@ -1192,7 +1205,7 @@ async function main() {
|
|
|
1192
1205
|
break;
|
|
1193
1206
|
}
|
|
1194
1207
|
if (subcommand === "validate") {
|
|
1195
|
-
const { runDetectionsValidate } = await import("./validate-
|
|
1208
|
+
const { runDetectionsValidate } = await import("./validate-QE2F4PYY.js");
|
|
1196
1209
|
await runDetectionsValidate({
|
|
1197
1210
|
org,
|
|
1198
1211
|
source: cli.flags.source,
|
|
@@ -1207,7 +1220,7 @@ async function main() {
|
|
|
1207
1220
|
break;
|
|
1208
1221
|
}
|
|
1209
1222
|
if (subcommand === "drift") {
|
|
1210
|
-
const { runDetectionsDrift } = await import("./drift-
|
|
1223
|
+
const { runDetectionsDrift } = await import("./drift-RQKTGJWB.js");
|
|
1211
1224
|
await runDetectionsDrift({
|
|
1212
1225
|
org,
|
|
1213
1226
|
source: cli.flags.source,
|
|
@@ -1221,7 +1234,7 @@ async function main() {
|
|
|
1221
1234
|
break;
|
|
1222
1235
|
}
|
|
1223
1236
|
if (subcommand === "run") {
|
|
1224
|
-
const { runDetectionsRun } = await import("./run-
|
|
1237
|
+
const { runDetectionsRun } = await import("./run-HS2EEOM6.js");
|
|
1225
1238
|
await runDetectionsRun({
|
|
1226
1239
|
org,
|
|
1227
1240
|
configId: cli.flags.configId,
|
|
@@ -1235,7 +1248,7 @@ async function main() {
|
|
|
1235
1248
|
break;
|
|
1236
1249
|
}
|
|
1237
1250
|
if (subcommand === "list") {
|
|
1238
|
-
const { runDetectionsList } = await import("./list-
|
|
1251
|
+
const { runDetectionsList } = await import("./list-LKNCICLT.js");
|
|
1239
1252
|
await runDetectionsList({
|
|
1240
1253
|
org,
|
|
1241
1254
|
cursor: cli.flags.cursor,
|
|
@@ -1264,7 +1277,7 @@ async function main() {
|
|
|
1264
1277
|
break;
|
|
1265
1278
|
}
|
|
1266
1279
|
if (action === "run") {
|
|
1267
|
-
const { runDetectionsRun } = await import("./run-
|
|
1280
|
+
const { runDetectionsRun } = await import("./run-HS2EEOM6.js");
|
|
1268
1281
|
await runDetectionsRun({
|
|
1269
1282
|
org,
|
|
1270
1283
|
configId: cli.flags.configId,
|
|
@@ -1282,7 +1295,7 @@ async function main() {
|
|
|
1282
1295
|
throw new Error("detections configs update requires --config-id");
|
|
1283
1296
|
}
|
|
1284
1297
|
const configPatch = getConfigPatchFromSetFlags();
|
|
1285
|
-
const { runDetectionsConfigsUpdate } = await import("./configs-update-
|
|
1298
|
+
const { runDetectionsConfigsUpdate } = await import("./configs-update-EKNLIRA6.js");
|
|
1286
1299
|
await runDetectionsConfigsUpdate({
|
|
1287
1300
|
org,
|
|
1288
1301
|
configId: cli.flags.configId,
|
|
@@ -1318,7 +1331,7 @@ async function main() {
|
|
|
1318
1331
|
const slugs = parseCsvList(cli.flags.slugs);
|
|
1319
1332
|
const allMyOrgs = cli.flags.allMyOrgs;
|
|
1320
1333
|
const org2 = slugs && slugs.length > 0 || allMyOrgs ? void 0 : await tryResolveOrg();
|
|
1321
|
-
const { runMetricsOrganization } = await import("./organization-
|
|
1334
|
+
const { runMetricsOrganization } = await import("./organization-PFPBZXJZ.js");
|
|
1322
1335
|
await runMetricsOrganization({
|
|
1323
1336
|
org: org2,
|
|
1324
1337
|
slugs,
|
|
@@ -1337,7 +1350,7 @@ async function main() {
|
|
|
1337
1350
|
}
|
|
1338
1351
|
const org = await resolveOrg();
|
|
1339
1352
|
if (subcommand === "summary") {
|
|
1340
|
-
const { runMetricsSummary } = await import("./summary-
|
|
1353
|
+
const { runMetricsSummary } = await import("./summary-POVQC6B7.js");
|
|
1341
1354
|
await runMetricsSummary({
|
|
1342
1355
|
org,
|
|
1343
1356
|
from: cli.flags.from,
|
|
@@ -1350,7 +1363,7 @@ async function main() {
|
|
|
1350
1363
|
break;
|
|
1351
1364
|
}
|
|
1352
1365
|
if (subcommand === "found") {
|
|
1353
|
-
const { runMetricsFound } = await import("./found-
|
|
1366
|
+
const { runMetricsFound } = await import("./found-LVYBEOS6.js");
|
|
1354
1367
|
await runMetricsFound({
|
|
1355
1368
|
org,
|
|
1356
1369
|
from: cli.flags.from,
|
|
@@ -1367,7 +1380,7 @@ async function main() {
|
|
|
1367
1380
|
if (!by || !["day", "type", "brand"].includes(by)) {
|
|
1368
1381
|
throw new Error("metrics breakdown requires --by <day|type|brand>");
|
|
1369
1382
|
}
|
|
1370
|
-
const { runMetricsBreakdown } = await import("./breakdown-
|
|
1383
|
+
const { runMetricsBreakdown } = await import("./breakdown-ETSF2BZ3.js");
|
|
1371
1384
|
await runMetricsBreakdown({
|
|
1372
1385
|
org,
|
|
1373
1386
|
by,
|
|
@@ -1388,7 +1401,7 @@ async function main() {
|
|
|
1388
1401
|
case "reports": {
|
|
1389
1402
|
if (subcommand === "list") {
|
|
1390
1403
|
const org = await resolveOrg();
|
|
1391
|
-
const { runReportsList } = await import("./list-
|
|
1404
|
+
const { runReportsList } = await import("./list-44BQZHJD.js");
|
|
1392
1405
|
await runReportsList({
|
|
1393
1406
|
org,
|
|
1394
1407
|
limit: cli.flags.limit,
|
|
@@ -1416,7 +1429,7 @@ async function main() {
|
|
|
1416
1429
|
}
|
|
1417
1430
|
if (subcommand === "create") {
|
|
1418
1431
|
const org = await tryResolveOrg();
|
|
1419
|
-
const { runReportsCreate } = await import("./create-
|
|
1432
|
+
const { runReportsCreate } = await import("./create-M4PV5VVU.js");
|
|
1420
1433
|
await runReportsCreate({
|
|
1421
1434
|
org,
|
|
1422
1435
|
title: cli.flags.title,
|
|
@@ -1437,7 +1450,7 @@ async function main() {
|
|
|
1437
1450
|
const positionals = cli.input.slice(2);
|
|
1438
1451
|
const flagAssets = parseAssetInputs();
|
|
1439
1452
|
const assetContents = [...positionals, ...flagAssets];
|
|
1440
|
-
const { runReportsSearch } = await import("./search-
|
|
1453
|
+
const { runReportsSearch } = await import("./search-EBXEP7XC.js");
|
|
1441
1454
|
await runReportsSearch({
|
|
1442
1455
|
assetContents,
|
|
1443
1456
|
reportedByCustomer: cli.flags.reportedByCustomer,
|
|
@@ -1453,7 +1466,7 @@ async function main() {
|
|
|
1453
1466
|
}
|
|
1454
1467
|
case "threats": {
|
|
1455
1468
|
if (subcommand === "list") {
|
|
1456
|
-
const { runThreatsList } = await import("./list-
|
|
1469
|
+
const { runThreatsList } = await import("./list-E2JVJNHV.js");
|
|
1457
1470
|
await runThreatsList({
|
|
1458
1471
|
query: cli.flags.query,
|
|
1459
1472
|
from: cli.flags.from,
|
|
@@ -1476,7 +1489,7 @@ async function main() {
|
|
|
1476
1489
|
case "takedowns": {
|
|
1477
1490
|
if (subcommand === "list") {
|
|
1478
1491
|
const org = await tryResolveOrg();
|
|
1479
|
-
const { runTakedownsList } = await import("./list-
|
|
1492
|
+
const { runTakedownsList } = await import("./list-S5Y6GW43.js");
|
|
1480
1493
|
await runTakedownsList({
|
|
1481
1494
|
org,
|
|
1482
1495
|
query: cli.flags.query,
|
|
@@ -1507,7 +1520,7 @@ async function main() {
|
|
|
1507
1520
|
}
|
|
1508
1521
|
case "queues": {
|
|
1509
1522
|
if (subcommand === "snapshot") {
|
|
1510
|
-
const { runQueuesSnapshot } = await import("./snapshot-
|
|
1523
|
+
const { runQueuesSnapshot } = await import("./snapshot-GNZMYTXT.js");
|
|
1511
1524
|
await runQueuesSnapshot({
|
|
1512
1525
|
org: cli.flags.org,
|
|
1513
1526
|
all: cli.flags.all,
|
|
@@ -1525,7 +1538,7 @@ async function main() {
|
|
|
1525
1538
|
}
|
|
1526
1539
|
case "orgs": {
|
|
1527
1540
|
if (subcommand === "list") {
|
|
1528
|
-
const { runOrgsList } = await import("./list-
|
|
1541
|
+
const { runOrgsList } = await import("./list-XUYCZG7S.js");
|
|
1529
1542
|
await runOrgsList({
|
|
1530
1543
|
query: cli.flags.query,
|
|
1531
1544
|
subscriptionStatus: cli.flags.subscriptionStatus,
|
|
@@ -1538,9 +1551,20 @@ async function main() {
|
|
|
1538
1551
|
});
|
|
1539
1552
|
break;
|
|
1540
1553
|
}
|
|
1554
|
+
if (subcommand === "get") {
|
|
1555
|
+
const positionalSlug = action;
|
|
1556
|
+
const slug = positionalSlug ?? await tryResolveOrg();
|
|
1557
|
+
const { runOrgsGet } = await import("./get-YFYSJFBC.js");
|
|
1558
|
+
await runOrgsGet({
|
|
1559
|
+
slug,
|
|
1560
|
+
json: jsonMode,
|
|
1561
|
+
outputFormat: cliContext.outputFormat
|
|
1562
|
+
});
|
|
1563
|
+
break;
|
|
1564
|
+
}
|
|
1541
1565
|
if (subcommand === "assets") {
|
|
1542
1566
|
if (action === "list") {
|
|
1543
|
-
const { runOrgsAssetsList } = await import("./list-
|
|
1567
|
+
const { runOrgsAssetsList } = await import("./list-O62BZKQ5.js");
|
|
1544
1568
|
await runOrgsAssetsList({
|
|
1545
1569
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1546
1570
|
groupId: cli.flags.groupId,
|
|
@@ -1556,7 +1580,7 @@ async function main() {
|
|
|
1556
1580
|
}
|
|
1557
1581
|
if (subcommand === "asset-groups") {
|
|
1558
1582
|
if (action === "list") {
|
|
1559
|
-
const { runOrgsAssetGroupsList } = await import("./list-
|
|
1583
|
+
const { runOrgsAssetGroupsList } = await import("./list-O36VWTWR.js");
|
|
1560
1584
|
await runOrgsAssetGroupsList({
|
|
1561
1585
|
json: jsonMode,
|
|
1562
1586
|
outputFormat: cliContext.outputFormat
|
|
@@ -1565,13 +1589,13 @@ async function main() {
|
|
|
1565
1589
|
}
|
|
1566
1590
|
throw new Error("Usage: chainpatrol orgs asset-groups list");
|
|
1567
1591
|
}
|
|
1568
|
-
const hint = subcommand ? suggest(subcommand, ["list", "assets", "asset-groups"]) : null;
|
|
1592
|
+
const hint = subcommand ? suggest(subcommand, ["list", "get", "assets", "asset-groups"]) : null;
|
|
1569
1593
|
throw new Error(
|
|
1570
|
-
subcommand ? `Unknown subcommand: orgs ${subcommand}${hint ? `. Did you mean "orgs ${hint}"?` : ""}` : "Usage: chainpatrol orgs <list|assets list|asset-groups list> [filters]"
|
|
1594
|
+
subcommand ? `Unknown subcommand: orgs ${subcommand}${hint ? `. Did you mean "orgs ${hint}"?` : ""}` : "Usage: chainpatrol orgs <list|get <slug>|assets list|asset-groups list> [filters]"
|
|
1571
1595
|
);
|
|
1572
1596
|
}
|
|
1573
1597
|
case "whoami": {
|
|
1574
|
-
const { runWhoami } = await import("./whoami-
|
|
1598
|
+
const { runWhoami } = await import("./whoami-24KUJUN4.js");
|
|
1575
1599
|
await runWhoami({
|
|
1576
1600
|
json: jsonMode,
|
|
1577
1601
|
outputFormat: cliContext.outputFormat
|
|
@@ -1580,7 +1604,7 @@ async function main() {
|
|
|
1580
1604
|
}
|
|
1581
1605
|
case "healthchecks": {
|
|
1582
1606
|
if (subcommand === "list") {
|
|
1583
|
-
const { runHealthchecksList } = await import("./list-
|
|
1607
|
+
const { runHealthchecksList } = await import("./list-CNF2FGLN.js");
|
|
1584
1608
|
await runHealthchecksList({
|
|
1585
1609
|
json: jsonMode,
|
|
1586
1610
|
outputFormat: cliContext.outputFormat
|
|
@@ -1594,7 +1618,7 @@ async function main() {
|
|
|
1594
1618
|
thresholds.minResults = cli.flags.minResults;
|
|
1595
1619
|
if (cli.flags.lookbackHours !== void 0)
|
|
1596
1620
|
thresholds.lookbackHours = cli.flags.lookbackHours;
|
|
1597
|
-
const { runHealthchecksRun } = await import("./run-
|
|
1621
|
+
const { runHealthchecksRun } = await import("./run-R3RR6XQF.js");
|
|
1598
1622
|
await runHealthchecksRun({
|
|
1599
1623
|
org,
|
|
1600
1624
|
id: action,
|
|
@@ -1612,7 +1636,7 @@ async function main() {
|
|
|
1612
1636
|
}
|
|
1613
1637
|
case "presets": {
|
|
1614
1638
|
if (subcommand === "list") {
|
|
1615
|
-
const { runPresetsList } = await import("./list-
|
|
1639
|
+
const { runPresetsList } = await import("./list-JCJHIJM4.js");
|
|
1616
1640
|
await runPresetsList({ outputFormat: cliContext.outputFormat });
|
|
1617
1641
|
break;
|
|
1618
1642
|
}
|
|
@@ -1623,7 +1647,7 @@ async function main() {
|
|
|
1623
1647
|
);
|
|
1624
1648
|
}
|
|
1625
1649
|
const org = await resolveOrg();
|
|
1626
|
-
const { runPresetsRun } = await import("./run-
|
|
1650
|
+
const { runPresetsRun } = await import("./run-LKPKTH3W.js");
|
|
1627
1651
|
await runPresetsRun({
|
|
1628
1652
|
presetId: action,
|
|
1629
1653
|
org,
|
|
@@ -1640,12 +1664,12 @@ async function main() {
|
|
|
1640
1664
|
case "setup":
|
|
1641
1665
|
case "install":
|
|
1642
1666
|
case "i": {
|
|
1643
|
-
const { setupSkill } = await import("./setup-skill-
|
|
1667
|
+
const { setupSkill } = await import("./setup-skill-Z6SBI6GC.js");
|
|
1644
1668
|
setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
|
|
1645
1669
|
break;
|
|
1646
1670
|
}
|
|
1647
1671
|
case "uninstall": {
|
|
1648
|
-
const { uninstallSkill } = await import("./setup-skill-
|
|
1672
|
+
const { uninstallSkill } = await import("./setup-skill-Z6SBI6GC.js");
|
|
1649
1673
|
uninstallSkill({ json: jsonMode });
|
|
1650
1674
|
break;
|
|
1651
1675
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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-DPLUSURP.js";
|
|
12
|
+
import "./chunk-EGWK6SRQ.js";
|
|
13
|
+
import "./chunk-TFCNKBRC.js";
|
|
14
|
+
import "./chunk-U73SABXK.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/orgs/get.ts
|
|
17
|
+
function summarizeServices(org) {
|
|
18
|
+
const parts = [];
|
|
19
|
+
if (org.services.takedowns.active) {
|
|
20
|
+
parts.push(`takedowns=${org.services.takedowns.automated ? "auto" : "manual"}`);
|
|
21
|
+
}
|
|
22
|
+
if (org.services.reporting.active) parts.push("reporting");
|
|
23
|
+
if (org.services.reviewing.active) parts.push("reviewing");
|
|
24
|
+
if (org.services.protection.active) parts.push("protection");
|
|
25
|
+
if (org.services.detection.active) parts.push("detection");
|
|
26
|
+
if (org.services.darkWebMonitoring.active) parts.push("darkWebMonitoring");
|
|
27
|
+
return parts.length > 0 ? parts.join(" ") : "(no services enabled)";
|
|
28
|
+
}
|
|
29
|
+
async function runOrgsGet(options) {
|
|
30
|
+
const slug = options.slug?.trim();
|
|
31
|
+
if (!slug) {
|
|
32
|
+
throw new CliExitError(
|
|
33
|
+
"orgs get requires an organization slug. Example: chainpatrol orgs get acme",
|
|
34
|
+
ExitCode.USAGE
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const client = options.apiClient ?? createApiClient();
|
|
38
|
+
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
39
|
+
const result = await client.getUserOrg({ slug });
|
|
40
|
+
const { organization } = result;
|
|
41
|
+
printOutput({
|
|
42
|
+
outputFormat,
|
|
43
|
+
json: result,
|
|
44
|
+
markdown: [
|
|
45
|
+
`# ${organization.name} (\`${organization.slug}\`)`,
|
|
46
|
+
"",
|
|
47
|
+
`- Subscription status: ${organization.subscriptionStatus}`,
|
|
48
|
+
`- Services: ${summarizeServices(organization)}`
|
|
49
|
+
].join("\n"),
|
|
50
|
+
csv: toCsvRows([
|
|
51
|
+
{
|
|
52
|
+
slug: organization.slug,
|
|
53
|
+
name: organization.name,
|
|
54
|
+
subscriptionStatus: organization.subscriptionStatus,
|
|
55
|
+
reportingActive: organization.services.reporting.active,
|
|
56
|
+
reviewingActive: organization.services.reviewing.active,
|
|
57
|
+
protectionActive: organization.services.protection.active,
|
|
58
|
+
takedownsActive: organization.services.takedowns.active,
|
|
59
|
+
// `takedowns` is the only service with a meaningful automation flag.
|
|
60
|
+
takedownsAutomated: organization.services.takedowns.automated,
|
|
61
|
+
detectionActive: organization.services.detection.active,
|
|
62
|
+
darkWebMonitoringActive: organization.services.darkWebMonitoring.active
|
|
63
|
+
}
|
|
64
|
+
]),
|
|
65
|
+
human: () => {
|
|
66
|
+
console.log(`${organization.name} (slug: ${organization.slug})`);
|
|
67
|
+
console.log(` subscriptionStatus: ${organization.subscriptionStatus}`);
|
|
68
|
+
console.log(` services: ${summarizeServices(organization)}`);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
runOrgsGet
|
|
74
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PRESETS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HGAQBGGL.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-DPLUSURP.js";
|
|
10
10
|
import "./chunk-EGWK6SRQ.js";
|
|
11
11
|
import "./chunk-TFCNKBRC.js";
|
|
12
12
|
import "./chunk-U73SABXK.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-VFT3TD3E.js";
|
|
9
9
|
import {
|
|
10
10
|
createApiClient
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DPLUSURP.js";
|
|
12
12
|
import "./chunk-EGWK6SRQ.js";
|
|
13
13
|
import "./chunk-TFCNKBRC.js";
|
|
14
14
|
import "./chunk-U73SABXK.js";
|
|
@@ -20,8 +20,14 @@ var VALID_SUBSCRIPTION_STATUSES = /* @__PURE__ */ new Set([
|
|
|
20
20
|
"ACTIVE",
|
|
21
21
|
"INTEGRATION"
|
|
22
22
|
]);
|
|
23
|
-
var DUAL_SERVICES = ["
|
|
24
|
-
var SINGLE_SERVICES = [
|
|
23
|
+
var DUAL_SERVICES = ["takedowns"];
|
|
24
|
+
var SINGLE_SERVICES = [
|
|
25
|
+
"reporting",
|
|
26
|
+
"reviewing",
|
|
27
|
+
"protection",
|
|
28
|
+
"detection",
|
|
29
|
+
"darkWebMonitoring"
|
|
30
|
+
];
|
|
25
31
|
var ALL_SERVICES = [...DUAL_SERVICES, ...SINGLE_SERVICES];
|
|
26
32
|
function splitCsv(value) {
|
|
27
33
|
if (!value) return [];
|
|
@@ -60,7 +66,7 @@ function parseServiceList(raw, flagName) {
|
|
|
60
66
|
function requireDualService(service, flagName) {
|
|
61
67
|
if (!DUAL_SERVICES.includes(service)) {
|
|
62
68
|
throw new CliExitError(
|
|
63
|
-
`Service '${service}' does not have
|
|
69
|
+
`Service '${service}' does not have a meaningful automation toggle and can't be used with --${flagName}. Only 'takedowns' supports --service-automated / --service-manual; use --service-active / --service-inactive for the others.`,
|
|
64
70
|
ExitCode.USAGE
|
|
65
71
|
);
|
|
66
72
|
}
|
|
@@ -114,10 +120,8 @@ function buildServicesFilter(options) {
|
|
|
114
120
|
}
|
|
115
121
|
function summarizeServices(org) {
|
|
116
122
|
const parts = [];
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (!entry.active) continue;
|
|
120
|
-
parts.push(`${service}=${entry.automated ? "auto" : "manual"}`);
|
|
123
|
+
if (org.services.takedowns.active) {
|
|
124
|
+
parts.push(`takedowns=${org.services.takedowns.automated ? "auto" : "manual"}`);
|
|
121
125
|
}
|
|
122
126
|
for (const service of SINGLE_SERVICES) {
|
|
123
127
|
if (org.services[service].active) parts.push(service);
|
|
@@ -150,12 +154,10 @@ async function runOrgsList(options) {
|
|
|
150
154
|
name: org.name,
|
|
151
155
|
subscriptionStatus: org.subscriptionStatus,
|
|
152
156
|
reportingActive: org.services.reporting.active,
|
|
153
|
-
reportingAutomated: org.services.reporting.automated,
|
|
154
157
|
reviewingActive: org.services.reviewing.active,
|
|
155
|
-
reviewingAutomated: org.services.reviewing.automated,
|
|
156
158
|
protectionActive: org.services.protection.active,
|
|
157
|
-
protectionAutomated: org.services.protection.automated,
|
|
158
159
|
takedownsActive: org.services.takedowns.active,
|
|
160
|
+
// `takedowns` is the only service with a meaningful automation flag.
|
|
159
161
|
takedownsAutomated: org.services.takedowns.automated,
|
|
160
162
|
detectionActive: org.services.detection.active,
|
|
161
163
|
darkWebMonitoringActive: org.services.darkWebMonitoring.active
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPresetDefinition,
|
|
3
3
|
runPreset
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HGAQBGGL.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-DPLUSURP.js";
|
|
11
11
|
import "./chunk-EGWK6SRQ.js";
|
|
12
12
|
import "./chunk-TFCNKBRC.js";
|
|
13
13
|
import "./chunk-U73SABXK.js";
|
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.18.0",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|