@knowttl/checkpoint-axi 0.1.3 → 0.1.4
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/dist/src/catalogue.d.ts +11 -4
- package/dist/src/catalogue.js +9 -3
- package/dist/src/local-commands.js +13 -4
- package/dist/src/reads.js +16 -6
- package/dist/src/transport.js +6 -0
- package/docs/agent-guide.md +2 -1
- package/docs/commands.md +5 -4
- package/docs/reads.md +12 -3
- package/package.json +1 -1
package/dist/src/catalogue.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
export declare const FILTER_OPERATORS: readonly ["is", "contains", "startsWith", "isEmpty", "isNot", "notContains", "isNotEmpty", "greaterThan", "lessThan"];
|
|
1
2
|
export declare const DESCRIPTION = "Inspect Check Point Email Security through compact, guarded AXI commands";
|
|
2
3
|
export declare const SETUP_GUIDANCE = "Run checkpoint-axi config path; configure a region, clientId and clientSecret env/file SecretRef";
|
|
3
4
|
export declare const TASK_WAIT_GUIDANCE: string;
|
|
4
5
|
export declare const DETAIL_EXPANSION_GUIDANCE: string;
|
|
5
6
|
export declare const EMAIL_PAYLOAD_ATTRIBUTES: string[];
|
|
6
7
|
export declare const EMAIL_FILTER_GUIDANCE: string;
|
|
8
|
+
export declare const EVENT_STATES: readonly ["new", "detected", "pending", "remediated", "dismissed", "exception"];
|
|
9
|
+
export declare const LIST_ROW_FIELDS: {
|
|
10
|
+
readonly "email search": readonly ["id", "subject", "state", "verdict"];
|
|
11
|
+
readonly "event list": readonly ["id", "type", "state", "severity"];
|
|
12
|
+
};
|
|
7
13
|
export declare const catalogue: {
|
|
8
14
|
readonly "email download": {
|
|
9
15
|
readonly description: "Download an email to a new private file with profile opt-in, a 50 MiB cap and mandatory SHA-256 verification; scopes and email hash availability are unverified (guide pages 131-132)";
|
|
@@ -189,10 +195,12 @@ export declare const catalogue: {
|
|
|
189
195
|
readonly "event list": {
|
|
190
196
|
readonly description: "List security events with bounded scroll continuation (API guide pages 37-42)";
|
|
191
197
|
readonly flags: {
|
|
198
|
+
readonly fields: `Comma-separated row fields: ${string}; or top-level events,count,total,complete,reason,cursor,expansion,help; default all`;
|
|
192
199
|
readonly saas: "Comma-separated SaaS overrides; default selected profile saas or office365_emails";
|
|
193
200
|
readonly "event-types": "Comma-separated event types; default unfiltered";
|
|
194
|
-
readonly "event-states":
|
|
195
|
-
readonly
|
|
201
|
+
readonly "event-states": `Comma-separated event states: ${string}; default unfiltered`;
|
|
202
|
+
readonly states: "Alias for --event-states; cannot combine with --event-states";
|
|
203
|
+
readonly severities: "Nonempty comma-separated severity strings; vendor documents no fixed severity list; unrecognised severities can return an empty result; default unfiltered";
|
|
196
204
|
readonly "event-ids": "Comma-separated event IDs; default unfiltered";
|
|
197
205
|
readonly "confidence-indicator": "Confidence indicator selector; default unfiltered";
|
|
198
206
|
readonly description: "Description selector; default unfiltered";
|
|
@@ -206,7 +214,6 @@ export declare const catalogue: {
|
|
|
206
214
|
readonly cursor: string;
|
|
207
215
|
readonly config: string;
|
|
208
216
|
readonly profile: string;
|
|
209
|
-
readonly fields: string;
|
|
210
217
|
readonly full: string;
|
|
211
218
|
readonly help: string;
|
|
212
219
|
};
|
|
@@ -250,11 +257,11 @@ export declare const catalogue: {
|
|
|
250
257
|
readonly limit: string;
|
|
251
258
|
readonly all: string;
|
|
252
259
|
readonly cursor: string;
|
|
260
|
+
readonly fields: `Comma-separated row fields: ${string}; or top-level emails,count,total,complete,reason,cursor,expansion,help; default all`;
|
|
253
261
|
readonly saas: "SaaS override; default selected profile saas or office365_emails";
|
|
254
262
|
readonly "saas-entity": "Optional SaaS entity type selector";
|
|
255
263
|
readonly config: string;
|
|
256
264
|
readonly profile: string;
|
|
257
|
-
readonly fields: string;
|
|
258
265
|
readonly full: string;
|
|
259
266
|
readonly help: string;
|
|
260
267
|
};
|
package/dist/src/catalogue.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { exceptionFamilies } from "./exceptions.js";
|
|
2
|
+
export const FILTER_OPERATORS = ["is", "contains", "startsWith", "isEmpty", "isNot", "notContains", "isNotEmpty", "greaterThan", "lessThan"];
|
|
2
3
|
export const DESCRIPTION = "Inspect Check Point Email Security through compact, guarded AXI commands";
|
|
3
4
|
export const SETUP_GUIDANCE = "Run checkpoint-axi config path; configure a region, clientId and clientSecret env/file SecretRef";
|
|
4
5
|
export const TASK_WAIT_GUIDANCE = "Task show reads once by default; use task show <id> --wait --timeout 30 for bounded read-only polling.\n"
|
|
@@ -20,7 +21,9 @@ export const EMAIL_PAYLOAD_ATTRIBUTES = ["subject", "fromEmail", "attachmentCoun
|
|
|
20
21
|
export const EMAIL_FILTER_GUIDANCE = "saasAttrName is a field path, not a closed enum (guide pages 19-20). Documented examples: "
|
|
21
22
|
+ EMAIL_PAYLOAD_ATTRIBUTES.slice(0, 3).join(", ") + ". Other documented email payload paths (pages 15-16, 24-25): "
|
|
22
23
|
+ EMAIL_PAYLOAD_ATTRIBUTES.slice(3).join(", ")
|
|
23
|
-
+
|
|
24
|
+
+ `. saasAttrOp: ${FILTER_OPERATORS.join(", ")}. The guide defines operators globally, without a per-field compatibility matrix; examples pair fromEmail with is and attachmentCount with greaterThan. saasAttrValue is a string.`;
|
|
25
|
+
export const EVENT_STATES = ["new", "detected", "pending", "remediated", "dismissed", "exception"];
|
|
26
|
+
export const LIST_ROW_FIELDS = { "email search": ["id", "subject", "state", "verdict"], "event list": ["id", "type", "state", "severity"] };
|
|
24
27
|
const common = {
|
|
25
28
|
config: "Config path; default CHECKPOINT_AXI_CONFIG or platform path",
|
|
26
29
|
profile: "Profile name; default CHECKPOINT_AXI_PROFILE, env profile, config default, or sole profile",
|
|
@@ -91,10 +94,12 @@ export const catalogue = {
|
|
|
91
94
|
flags: { ...common, type: exceptionType, items: "Click-time item route instead of list route; default false" },
|
|
92
95
|
examples: ["checkpoint-axi exception show phishing-block <id>", "checkpoint-axi exception show url <value> --type allow-url", "checkpoint-axi exception show click-time <id> --items --full"] },
|
|
93
96
|
"event list": { description: "List security events with bounded scroll continuation (API guide pages 37-42)", flags: { ...common, ...paging, ...expansion,
|
|
97
|
+
fields: `Comma-separated row fields: ${LIST_ROW_FIELDS["event list"].join(",")}; or top-level events,count,total,complete,reason,cursor,expansion,help; default all`,
|
|
94
98
|
saas: "Comma-separated SaaS overrides; default selected profile saas or office365_emails",
|
|
95
99
|
"event-types": "Comma-separated event types; default unfiltered",
|
|
96
|
-
"event-states":
|
|
97
|
-
|
|
100
|
+
"event-states": `Comma-separated event states: ${EVENT_STATES.join(", ")}; default unfiltered`,
|
|
101
|
+
states: "Alias for --event-states; cannot combine with --event-states",
|
|
102
|
+
severities: "Nonempty comma-separated severity strings; vendor documents no fixed severity list; unrecognised severities can return an empty result; default unfiltered",
|
|
98
103
|
"event-ids": "Comma-separated event IDs; default unfiltered",
|
|
99
104
|
"confidence-indicator": "Confidence indicator selector; default unfiltered",
|
|
100
105
|
description: "Description selector; default unfiltered",
|
|
@@ -108,6 +113,7 @@ export const catalogue = {
|
|
|
108
113
|
"wait-requests": "Total HTTP request cap including auth and retries; default 10, range 2-10; requires --wait",
|
|
109
114
|
}, examples: ["checkpoint-axi task show <id>", "checkpoint-axi task show <id> --wait --timeout 30 --fields task,wait,help", "checkpoint-axi task show <id> --full"] },
|
|
110
115
|
"email search": { description: "Search emails with a bounded date window and scroll continuation (API guide pages 18-27)", flags: { ...common,
|
|
116
|
+
fields: `Comma-separated row fields: ${LIST_ROW_FIELDS["email search"].join(",")}; or top-level emails,count,total,complete,reason,cursor,expansion,help; default all`,
|
|
111
117
|
saas: "SaaS override; default selected profile saas or office365_emails",
|
|
112
118
|
"saas-entity": "Optional SaaS entity type selector",
|
|
113
119
|
...paging, ...expansion,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
-
import { catalogue, DESCRIPTION, help, SETUP_GUIDANCE } from "./catalogue.js";
|
|
4
|
+
import { catalogue, DESCRIPTION, help, LIST_ROW_FIELDS, SETUP_GUIDANCE } from "./catalogue.js";
|
|
5
5
|
import { doctor } from "./doctor.js";
|
|
6
6
|
import { readCommand } from "./reads.js";
|
|
7
7
|
import { exceptionCommand } from "./exceptions.js";
|
|
@@ -61,9 +61,14 @@ export async function localCommand(argv, store, transport) {
|
|
|
61
61
|
available.splice(0, available.length, "outcome", "preview", "auditId", "tasks", "response", "responseSchema", "help");
|
|
62
62
|
if (isDownload)
|
|
63
63
|
available.splice(0, available.length, "path", "size", "sha256");
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const rowFields = name === "email search" || name === "event list" ? LIST_ROW_FIELDS[name] : [];
|
|
65
|
+
const requested = flags.get("--fields")?.split(",") ?? available;
|
|
66
|
+
const columns = requested.filter((field) => rowFields.includes(field));
|
|
67
|
+
if (requested.some((field) => !available.includes(field) && !rowFields.includes(field)) || new Set(requested).size !== requested.length
|
|
68
|
+
|| (columns.length > 0 && columns.length !== requested.length)) {
|
|
69
|
+
usage(`Invalid --fields; valid top-level fields: ${available.join(",")}${rowFields.length ? `; valid row fields: ${rowFields.join(",")}` : ""}`);
|
|
70
|
+
}
|
|
71
|
+
const fields = columns.length ? available : requested;
|
|
67
72
|
const config = flags.get("--config");
|
|
68
73
|
let result;
|
|
69
74
|
if (isDownload)
|
|
@@ -105,6 +110,10 @@ export async function localCommand(argv, store, transport) {
|
|
|
105
110
|
description: DESCRIPTION, status, profiles: listed.profiles, count: listed.count,
|
|
106
111
|
help: [SETUP_GUIDANCE, "Run checkpoint-axi auth status to validate local credentials", "Run checkpoint-axi profile list to inspect configured profiles"] };
|
|
107
112
|
}
|
|
113
|
+
if (columns.length) {
|
|
114
|
+
const key = name === "event list" ? "events" : "emails";
|
|
115
|
+
result[key] = result[key].map((row) => Object.fromEntries(columns.map((field) => [field, row[field]])));
|
|
116
|
+
}
|
|
108
117
|
let truncated = false;
|
|
109
118
|
const preview = (value) => {
|
|
110
119
|
if (typeof value === "string" && value.length > 500 && !flags.has("--full")) {
|
package/dist/src/reads.js
CHANGED
|
@@ -5,19 +5,20 @@ import { z } from "zod";
|
|
|
5
5
|
import { REGIONS } from "./regions.js";
|
|
6
6
|
import { gateway, READ_LIMITS } from "./transport.js";
|
|
7
7
|
import { responseInvalid } from "./response-invalid.js";
|
|
8
|
+
import { EVENT_STATES, FILTER_OPERATORS } from "./catalogue.js";
|
|
8
9
|
const day = 86_400_000;
|
|
9
10
|
const timestamp = z.iso.datetime({ offset: true });
|
|
10
11
|
const filters = z.array(z.strictObject({ saasAttrName: z.string().min(1),
|
|
11
|
-
saasAttrOp: z.enum(
|
|
12
|
+
saasAttrOp: z.enum(FILTER_OPERATORS),
|
|
12
13
|
saasAttrValue: z.string() }));
|
|
13
14
|
const continuation = z.strictObject({ version: z.literal(1), binding: z.string(), start: timestamp, end: timestamp,
|
|
14
15
|
scroll: z.string().optional(), offset: z.number().int().nonnegative(), replayRisk: z.literal(true).optional() });
|
|
15
16
|
// The guide's prose/table (pp.11,14) says security-result array; its JSON examples use an object.
|
|
16
17
|
const securityResults = z.object({ combinedVerdict: z.unknown().optional() }).passthrough();
|
|
17
18
|
// Entity schemas and SaaS-specific payloads: guide pages 11-15 and 21-24.
|
|
18
|
-
const entity = z.object({ entityInfo: z.object({ entityId: z.string().min(1), entityActionState: z.string().
|
|
19
|
+
const entity = z.object({ entityInfo: z.object({ entityId: z.string().min(1), entityActionState: z.string().nullish().transform((value) => value ?? "unactioned") }).passthrough(),
|
|
19
20
|
entityPayload: z.object({ subject: z.string().optional() }).passthrough(),
|
|
20
|
-
entitySecurityResults: z.union([securityResults, z.array(
|
|
21
|
+
entitySecurityResults: z.union([securityResults, z.array(securityResults)]).optional(),
|
|
21
22
|
}).passthrough();
|
|
22
23
|
// Event and task fields: guide pages 31-32, 35-36 and 40-41.
|
|
23
24
|
const event = z.object({ eventId: z.string().min(1), type: z.string(), state: z.string(), severity: z.string() }).passthrough();
|
|
@@ -68,7 +69,7 @@ export async function readCommand(name, id, flags, store, transport) {
|
|
|
68
69
|
}
|
|
69
70
|
const parsed = filters.safeParse(raw);
|
|
70
71
|
if (!parsed.success)
|
|
71
|
-
invalid(
|
|
72
|
+
invalid(`--filter must contain saasAttrName, saasAttrValue and saasAttrOp from: ${FILTER_OPERATORS.join(", ")}`);
|
|
72
73
|
extended = parsed.data;
|
|
73
74
|
}
|
|
74
75
|
let cursor;
|
|
@@ -96,12 +97,19 @@ export async function readCommand(name, id, flags, store, transport) {
|
|
|
96
97
|
if (flags.has(flag) && !flags.get(flag).trim())
|
|
97
98
|
invalid(`${flag} must not be blank`);
|
|
98
99
|
const eventSelectors = {};
|
|
100
|
+
if (flags.has("--states")) {
|
|
101
|
+
if (flags.has("--event-states"))
|
|
102
|
+
invalid("Use either --states or --event-states");
|
|
103
|
+
flags.set("--event-states", flags.get("--states"));
|
|
104
|
+
}
|
|
99
105
|
for (const [flag, key] of [["event-types", "eventTypes"], ["event-states", "eventStates"], ["severities", "severities"], ["event-ids", "eventIds"], ["saas", "saas"]]) {
|
|
100
106
|
if (!isEvent || !flags.has(`--${flag}`))
|
|
101
107
|
continue;
|
|
102
108
|
const values = flags.get(`--${flag}`).split(",").map((value) => value.trim());
|
|
103
109
|
if (values.some((value) => !value))
|
|
104
|
-
invalid(`--${flag} must contain nonempty comma-separated values`);
|
|
110
|
+
invalid(`--${flag} must contain nonempty comma-separated ${flag === "severities" ? "severity strings" : "values"}`);
|
|
111
|
+
if (flag === "event-states" && values.some((value) => !EVENT_STATES.includes(value)))
|
|
112
|
+
invalid(`--event-states/--states must contain: ${EVENT_STATES.join(", ")}`);
|
|
105
113
|
eventSelectors[key] = values;
|
|
106
114
|
}
|
|
107
115
|
for (const [flag, key] of [["confidence-indicator", "confidenceIndicator"], ["description", "description"]]) {
|
|
@@ -217,7 +225,9 @@ export async function readCommand(name, id, flags, store, transport) {
|
|
|
217
225
|
}
|
|
218
226
|
const value = entity.parse(record);
|
|
219
227
|
return { id: value.entityInfo.entityId, subject: value.entityPayload.subject ?? "",
|
|
220
|
-
state: value.entityInfo.entityActionState
|
|
228
|
+
state: value.entityInfo.entityActionState, verdict: Array.isArray(value.entitySecurityResults)
|
|
229
|
+
? value.entitySecurityResults.find((result) => result.combinedVerdict != null)?.combinedVerdict ?? null
|
|
230
|
+
: value.entitySecurityResults?.combinedVerdict ?? null };
|
|
221
231
|
}));
|
|
222
232
|
offset += rows.length;
|
|
223
233
|
if (offset < page.records.length) {
|
package/dist/src/transport.js
CHANGED
|
@@ -179,6 +179,12 @@ export function gateway(profile, credentials, redactor, dependencies = {}, mutat
|
|
|
179
179
|
throw failure("AUTH_FAILED", "API rejected authentication after one re-exchange");
|
|
180
180
|
if (response.status === 429)
|
|
181
181
|
throw failure("RATE_LIMITED", "API rate limit remains after two read retries");
|
|
182
|
+
if (response.status === 404)
|
|
183
|
+
throw new AxiError("Requested resource was not found", "NOT_FOUND", ["Check the requested ID"]);
|
|
184
|
+
if (response.status === 422 && query.body === undefined) {
|
|
185
|
+
const id = decodeURIComponent(query.path.slice(query.path.lastIndexOf("/") + 1));
|
|
186
|
+
throw new AxiError(`API rejected requested ID ${id} (HTTP 422)`, "VALIDATION_ERROR", ["Check the requested ID and its format"]);
|
|
187
|
+
}
|
|
182
188
|
if (response.status < 200 || response.status >= 300)
|
|
183
189
|
throw failure("HTTP_ERROR", `Regional API returned HTTP ${response.status}`);
|
|
184
190
|
return decodePage(response.value, /^\/(sectools|sectool-exceptions)\//.test(query.path));
|
package/docs/agent-guide.md
CHANGED
|
@@ -97,7 +97,8 @@ checkpoint-axi email search --limit 5 --expand --expand-limit 3 --expand-request
|
|
|
97
97
|
checkpoint-axi event list --limit 5 --expand --fields events,count,complete,cursor,expansion
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
--fields selects top-level output keys
|
|
100
|
+
--fields selects top-level output keys: request emails or events together with count,total,complete,reason,cursor for lists, and email,event,task or exception for details.
|
|
101
|
+
Email search also accepts row fields id,subject,state,verdict; event list accepts id,type,state,severity, retaining pagination metadata when selecting row fields.
|
|
101
102
|
Email rows contain id,subject,state,verdict; event rows contain id,type,state,severity; documented exception rows contain id,sender,subject,comment.
|
|
102
103
|
TOON strings preview at 500 characters; --full expands strings after redaction, while cursors are never truncated.
|
|
103
104
|
|
package/docs/commands.md
CHANGED
|
@@ -187,7 +187,7 @@ Search emails with a bounded date window and scroll continuation (API guide page
|
|
|
187
187
|
|---|---|
|
|
188
188
|
| `--config` | Config path; default CHECKPOINT_AXI_CONFIG or platform path |
|
|
189
189
|
| `--profile` | Profile name; default CHECKPOINT_AXI_PROFILE, env profile, config default, or sole profile |
|
|
190
|
-
| `--fields` | Comma-separated
|
|
190
|
+
| `--fields` | Comma-separated row fields: id,subject,state,verdict; or top-level emails,count,total,complete,reason,cursor,expansion,help; default all |
|
|
191
191
|
| `--full` | Show full strings instead of 500-character previews; default false |
|
|
192
192
|
| `--help` | Show concise command help; default false |
|
|
193
193
|
| `--saas` | SaaS override; default selected profile saas or office365_emails |
|
|
@@ -255,7 +255,7 @@ List security events with bounded scroll continuation (API guide pages 37-42)
|
|
|
255
255
|
|---|---|
|
|
256
256
|
| `--config` | Config path; default CHECKPOINT_AXI_CONFIG or platform path |
|
|
257
257
|
| `--profile` | Profile name; default CHECKPOINT_AXI_PROFILE, env profile, config default, or sole profile |
|
|
258
|
-
| `--fields` | Comma-separated
|
|
258
|
+
| `--fields` | Comma-separated row fields: id,type,state,severity; or top-level events,count,total,complete,reason,cursor,expansion,help; default all |
|
|
259
259
|
| `--full` | Show full strings instead of 500-character previews; default false |
|
|
260
260
|
| `--help` | Show concise command help; default false |
|
|
261
261
|
| `--start-date` | ISO timestamp with timezone; default 24 hours before end-date; maximum window 31 days |
|
|
@@ -268,8 +268,9 @@ List security events with bounded scroll continuation (API guide pages 37-42)
|
|
|
268
268
|
| `--expand-requests` | Total HTTP request cap including auth, list pages, detail and retries; default 10, range 2-10; requires --expand |
|
|
269
269
|
| `--saas` | Comma-separated SaaS overrides; default selected profile saas or office365_emails |
|
|
270
270
|
| `--event-types` | Comma-separated event types; default unfiltered |
|
|
271
|
-
| `--event-states` | Comma-separated event states; default unfiltered |
|
|
272
|
-
| `--
|
|
271
|
+
| `--event-states` | Comma-separated event states: new, detected, pending, remediated, dismissed, exception; default unfiltered |
|
|
272
|
+
| `--states` | Alias for --event-states; cannot combine with --event-states |
|
|
273
|
+
| `--severities` | Nonempty comma-separated severity strings; vendor documents no fixed severity list; unrecognised severities can return an empty result; default unfiltered |
|
|
273
274
|
| `--event-ids` | Comma-separated event IDs; default unfiltered |
|
|
274
275
|
| `--confidence-indicator` | Confidence indicator selector; default unfiltered |
|
|
275
276
|
| `--description` | Description selector; default unfiltered |
|
package/docs/reads.md
CHANGED
|
@@ -20,6 +20,7 @@ Read sessions allow at most 10 HTTP requests; write sessions allow at most 44.
|
|
|
20
20
|
Both are bounded by 8 MiB of JSON response bytes and 60 seconds, including auth, re-exchange, read retries and delays.
|
|
21
21
|
Download bodies have a separate 50 MiB cap per response within the same request/time budgets.
|
|
22
22
|
Reads retry HTTP 429 at most twice, honoring numeric or HTTP-date `Retry-After` within that budget.
|
|
23
|
+
HTTP 404 reads return `NOT_FOUND`; HTTP 422 detail reads return `VALIDATION_ERROR` and identify the requested ID without printing server response data.
|
|
23
24
|
Exception reads and writes share separate 1 request/second Anti-Phishing and 10 requests/second other-exception spacers.
|
|
24
25
|
|
|
25
26
|
## Email reads
|
|
@@ -43,11 +44,11 @@ Cursor strings are never truncated; email text is redacted before 500-character
|
|
|
43
44
|
See [downloads](downloads.md) for private file output.
|
|
44
45
|
|
|
45
46
|
The vendor PDF describes `entitySecurityResults` as an array in its prose/table (pages 11 and 14), while its JSON examples use an object.
|
|
46
|
-
Both
|
|
47
|
-
|
|
47
|
+
Both forms are accepted; search uses `combinedVerdict` from the object or the first array entry containing one, and reports `verdict: null` when none is available.
|
|
48
|
+
Null or missing `entityActionState` within `entityInfo` is rendered as `unactioned` in search and detail.
|
|
48
49
|
`RESPONSE_INVALID` diagnostics for these reads name failing JSON paths and received types, including `missing`, without response values.
|
|
49
50
|
Non-identifier path keys appear as `<key>`.
|
|
50
|
-
|
|
51
|
+
The reported unfiltered-search and spam-detail failures identified null action states; synthetic clean and spam fixtures exercise that shape offline.
|
|
51
52
|
|
|
52
53
|
## Event and task reads
|
|
53
54
|
|
|
@@ -70,10 +71,17 @@ Failures before any snapshot and non-budget read failures remain structured erro
|
|
|
70
71
|
Use `--fields task,wait,help` to retain wait metadata and recovery guidance when projecting output.
|
|
71
72
|
Waiting only repeats the existing task status GET; it never invokes an available action, downloads a file or resubmits the original mutation.
|
|
72
73
|
Event list accepts comma-separated `--event-types`, `--event-states`, `--severities`, `--event-ids` and `--saas`, plus `--confidence-indicator` and `--description` text selectors.
|
|
74
|
+
`--states` is an alias for `--event-states`; use one of these flags per command.
|
|
75
|
+
States must be `new`, `detected`, `pending`, `remediated`, `dismissed` or `exception`, as defined by the vendor Swagger 1.50 `EventState` schema.
|
|
76
|
+
The vendor Swagger defines severities as an array of strings with no format, min/max constraints or fixed severity list, so the CLI validates nonempty comma-separated severity strings.
|
|
77
|
+
Unrecognised severities can return an empty result.
|
|
73
78
|
SaaS defaults to the selected profile's value or `office365_emails`; other event selectors default to unfiltered.
|
|
74
79
|
Event list uses the same date windows, row and transport budgets, bound continuation and honest page replay flags as [email search](reads.md#email-reads).
|
|
75
80
|
Repeat all original event selectors with `--cursor`; the cursor preserves the original date window.
|
|
76
81
|
Event and task text is redacted before 500-character previews; use `--full` for full strings and `--fields` to select top-level fields.
|
|
82
|
+
Email search also accepts row fields `id,subject,state,verdict`; event list accepts `id,type,state,severity`.
|
|
83
|
+
For example, `email search --fields id,subject` narrows each email row while retaining pagination metadata.
|
|
84
|
+
Existing top-level projections such as `--fields emails,count,cursor` remain supported; mixed row and top-level selections are rejected, and errors list both valid sets.
|
|
77
85
|
For writes, see [event actions](writes.md#event-actions).
|
|
78
86
|
These reads are verified offline with synthetic fixtures; authentication, token lifetime and live API behavior require manual verification.
|
|
79
87
|
|
|
@@ -103,6 +111,7 @@ Budget and per-item failures also include a safe error `code`; raw upstream erro
|
|
|
103
111
|
Budget exhaustion stops further detail attempts; an individual HTTP, response-validation or other read failure records that item and continues within the caps.
|
|
104
112
|
List `complete`, `reason` and `cursor` still describe pagination; `complete` inside `expansion` independently describes whether every returned row was expanded.
|
|
105
113
|
With `--fields`, include `expansion` alongside `emails` or `events` so omissions remain visible.
|
|
114
|
+
Row field selections retain expansion metadata but omit each row's `detail`; use a top-level projection to inspect expanded payloads.
|
|
106
115
|
Expansion performs no writes, actions, downloads, cross-resource pivots or task waiting.
|
|
107
116
|
|
|
108
117
|
## Exception reads
|