@knowttl/falcon-axi 1.0.0-rc.1 → 1.0.0-rc.2

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.
@@ -9,6 +9,18 @@ export function responseFailure(response, subject, token = false, member = false
9
9
  const envelope = object(response.body) ? response.body : {};
10
10
  const meta = object(envelope.meta) ? envelope.meta : {};
11
11
  const details = typeof meta.trace_id === "string" ? { trace_id: meta.trace_id } : {};
12
+ const requestHelp = operationId === "RTRAuditSessions"
13
+ ? [
14
+ `Check that the API client has ${scopes.join(" and ")} in the Falcon console under Support and resources > API clients and keys; run \`falcon-axi scopes\` for the matrix`,
15
+ "This rejection does not confirm a missing scope; if the scope is granted, report the request command and trace_id to CrowdStrike support",
16
+ ]
17
+ : operationId === "GetSearchStatusV1"
18
+ ? [
19
+ "A stopped or expired job may no longer be queryable; this rejection does not confirm that the job was stopped",
20
+ "Check the job identifier and pass the same `--repository` the job was started against",
21
+ "Run `falcon-axi search start --query '<cql>'` to start a new job if needed",
22
+ ]
23
+ : undefined;
12
24
  if (response.status === 400) {
13
25
  if (operationId === "api_preempt_proxy_post_graphql")
14
26
  throw new CliError("UPSTREAM_ERROR", `Falcon rejected falcon-axi's fixed Identity Protection query for ${subject}`, [
@@ -86,15 +98,16 @@ export function responseFailure(response, subject, token = false, member = false
86
98
  ? ["host list", "hostname:'WIN-*'"]
87
99
  : ["detection list", "severity_name:'High'+status:'new'"]);
88
100
  const errors = Array.isArray(envelope.errors) ? envelope.errors : [];
89
- if (errors.some((error) => object(error) &&
90
- typeof error.message === "string" &&
91
- /\b(fql|filter|query)\b/i.test(error.message)))
101
+ if (operationId !== "GetSearchStatusV1" &&
102
+ errors.some((error) => object(error) &&
103
+ typeof error.message === "string" &&
104
+ /\b(fql|filter|query)\b/i.test(error.message)))
92
105
  throw new CliError("FQL_INVALID", `the filter for ${subject} was rejected`, [
93
106
  "FQL uses + for AND, `,` for OR, and values must be quoted",
94
107
  `Example: \`--filter "${example}"\``,
95
108
  `Run \`falcon-axi ${command} --help\` for the filterable fields`,
96
109
  ]);
97
- throw new CliError("UPSTREAM_ERROR", `Falcon rejected the request for ${subject}`, ["Check the flags for this command with `--help`"], details);
110
+ throw new CliError("UPSTREAM_ERROR", `Falcon rejected the request for ${subject}`, requestHelp ?? ["Check the flags for this command with `--help`"], details);
98
111
  }
99
112
  if (response.status === 401)
100
113
  throw new CliError("AUTH_FAILED", "the Falcon credential was rejected", [
@@ -162,6 +175,7 @@ export function responseFailure(response, subject, token = false, member = false
162
175
  throw new CliError("UPSTREAM_ERROR", `Falcon could not answer the request for ${subject}`, [
163
176
  "Retry shortly",
164
177
  "Quote the trace_id when opening a CrowdStrike support case",
178
+ ...(requestHelp ?? []),
165
179
  ], details);
166
180
  }
167
181
  export function observeRate(session, response) {
@@ -1,5 +1,5 @@
1
- import { realpathSync, statSync, accessSync, constants } from "node:fs";
2
- import { dirname, isAbsolute, join, resolve, sep, delimiter } from "node:path";
1
+ import { realpathSync, statSync } from "node:fs";
2
+ import { dirname, join, resolve, sep } from "node:path";
3
3
  import { CliError } from "./core.js";
4
4
  export function shellArgument(value) {
5
5
  return process.platform === "win32"
@@ -12,23 +12,6 @@ export function executableCommand(hook = false) {
12
12
  const name = hook ? "falcon-axi-hook" : "falcon-axi";
13
13
  if (!statSync(target).isFile())
14
14
  throw new CliError("CONFIG_INVALID", `cannot locate ${name}; reinstall falcon-axi`);
15
- // npm's Windows .cmd wrapper is a shell script, so use Node plus its entry point.
16
- if (hook && process.platform !== "win32")
17
- for (const directory of (process.env.PATH ?? "").split(delimiter)) {
18
- const candidate = join(directory || ".", name);
19
- try {
20
- accessSync(candidate, constants.X_OK);
21
- if (!statSync(candidate).isFile())
22
- continue;
23
- if (isAbsolute(directory) && realpathSync(candidate) === target)
24
- return [name];
25
- break;
26
- }
27
- catch (error) {
28
- if (!["ENOENT", "ENOTDIR", "EACCES", "ELOOP"].includes(error.code ?? ""))
29
- throw error;
30
- }
31
- }
32
15
  return [process.execPath, target];
33
16
  }
34
17
  export function durableInstallation() {
@@ -10,7 +10,7 @@
10
10
  "detection show": "falcon-axi detection show <composite id> [--full]\n\n--full print long fields such as the command line without truncation\n\nExample: falcon-axi detection show \"ldt:aid:1234\"\n\nThis command is read-only and requires only Alerts:read.",
11
11
  "detection process": "falcon-axi detection process <composite id> [--full]\n\n--full print command lines without the default 800-character truncation\n\nShow the triggering process, parent, and grandparent recorded on the alert.\nRows contain relation, filename, filepath, cmdline, sha256, and process_id.\ntriggering_process_graph_id is the alert's graph pivot; this view does not fetch a graph.\nAbsent ancestors and alerts without a process are stated explicitly.\nExamples:\n falcon-axi detection process 'ldt:synthetic-agent:1001'\n falcon-axi detection process 'ldt:synthetic-agent:1001' --full\n\nThis command is read-only and requires only Alerts:read.",
12
12
  "host list": "falcon-axi host list [--hostname <name>] [--platform <name>] [--status <name>] [--since <window>] [--filter <FQL>] [--limit N] [--cursor <token>] [--all] [--max-rows N] [--fields <names>]\n\n--hostname hostname to match; Hosts filters accept wildcards, so WIN-* works\n--platform one of windows, mac, linux\n--status one of normal, containment_pending, contained, lift_containment_pending\n--since last_seen within a relative window such as 24h or 7d\n--filter raw FQL; + is AND, `,` is OR, values are single-quoted, relative dates are lowercase\n--limit rows in this call (default 20, ceiling 5000)\n--cursor opaque continuation token from a previous call\n--all walk pages; page size is independent of --limit\n--max-rows row budget (default 1000; requires --all)\n--fields extra columns, comma-separated: os_version, agent_version, status, first_seen, machine_domain\n\nFilterable fields include hostname, platform_name, os_version, agent_version, status,\nlast_seen, first_seen, machine_domain, and local_ip.\nExamples:\n falcon-axi host list --platform windows --since 24h\n falcon-axi host list --filter \"hostname:'WIN-*'+platform_name:'Windows'\"\n\nThis command is read-only and requires only Hosts:read. It reports containment status as\ndata and cannot change it.",
13
- "host show": "falcon-axi host show <device id>\n\nThe device id is the agent id Falcon calls the AID, as printed by `falcon-axi host list`.\n\nExample: falcon-axi host show abc123\n\nThis command is read-only and requires only Hosts:read.",
13
+ "host show": "falcon-axi host show <device id>\n\nThe device id is the agent id Falcon calls the AID, as printed by `falcon-axi host list`.\n\nExample: falcon-axi host show 0123456789abcdef0123456789abcdef\n\nThis command is read-only and requires only Hosts:read.",
14
14
  "host logins": "falcon-axi host logins <device id> [--since <window>] [--limit N]\nfalcon-axi host logins --hostname <pattern> [--since <window>] [--limit N]\n\nThe device id is the agent id Falcon calls the AID, as printed by `falcon-axi host list`.\n--hostname match a hostname (wildcards allowed), instead of a device id; requires exactly one match\n--since window to read, such as 24h or 7d (default 7d, Falcon's own default)\n--limit logins per host in this call (default 20, ceiling 100)\n\nReports recent interactive logins from the Host Timeline as device_id, user_name, and\nlogin_time. It is a window, not a full audit trail: a host that returns its limit may have more.\nExample: falcon-axi host logins abc123 --since 24h\nExample: falcon-axi host logins --hostname 'synthetic-host-*' --since 24h --limit 2\nHostname form: one lookup capped at 2 IDs, then one history read; 60s total deadline.\nAmbiguous or incomplete lookups fail without reading history; upstream partial errors are disclosed.\n\nThis command is read-only and requires only Hosts:read.",
15
15
  "host network": "falcon-axi host network <device id>\nfalcon-axi host network --hostname <pattern>\n\nRetrieves the IP and MAC address history Falcon retains for one sensor host.\nThe device id is the AID printed by `falcon-axi host list`.\n--hostname match a hostname (wildcards allowed), instead of a device id; requires exactly one match\nExample: falcon-axi host network abc123\nExample: falcon-axi host network --hostname 'synthetic-host-*'\nHostname form: one lookup capped at 2 IDs, then one history read; 60s total deadline.\nAmbiguous or incomplete lookups fail without reading history; upstream partial errors are disclosed.\nRead-only; requires Hosts:read. This endpoint has no pagination parameters.",
16
16
  "ioc list": "falcon-axi ioc list [--filter <FQL>] [--limit N] [--cursor <token>]\n\n--filter FQL on type, value, action, source, severity_number, expired, created_on, modified_on\n--limit rows per call (default 20, ceiling 500)\n--cursor opaque continuation token\n\nExamples:\n falcon-axi ioc list --filter \"type:'domain'+expired:false\"\n falcon-axi ioc list --limit 100\n\nRead-only; requires IOC Management:read.",
@@ -150,6 +150,10 @@ export function parse(argv) {
150
150
  throw new CliError("VALIDATION_ERROR", "--max-rows must be a positive integer");
151
151
  }
152
152
  const id = positionals[0];
153
+ if (command.name === "host show" &&
154
+ id &&
155
+ (!/^[a-fA-F0-9]{32}$/.test(id) || /^0{32}$/.test(id)))
156
+ throw new CliError("VALIDATION_ERROR", "host show requires a nonzero 32-character hexadecimal device id (AID)", ["Run `falcon-axi host list` to see current device identifiers"]);
153
157
  if (!flags.has("--help"))
154
158
  validateInspection(command.name, flags, limit);
155
159
  if (command.name === "cve show" && id && !/^CVE-[0-9]{4}-[0-9]{4,}$/.test(id))
@@ -95,7 +95,7 @@ export async function rtrRun(invocation, credential, base, cancelled) {
95
95
  const policy = credential.rtr ?? rtrPolicy(undefined);
96
96
  const commandBase = parseRtr(command, policy.commands);
97
97
  if (executing && (credential.channel !== "file" || !policy.enabled))
98
- throw new CliError("READ_ONLY_VIOLATION", "RTR execution requires explicit profile opt-in");
98
+ throw new CliError("READ_ONLY_VIOLATION", "RTR execution requires explicit profile opt-in", ['Set "rtr": {"enabled": true} on the selected file profile']);
99
99
  if (executing && (process.platform !== "linux" || process.arch !== "x64"))
100
100
  throw new CliError("CONFIG_INSECURE", "RTR execution requires a supported POSIX controller");
101
101
  process.stdout.write(render({
@@ -116,7 +116,7 @@ export async function search(domain) {
116
116
  return {
117
117
  value: { stopped: id, repository },
118
118
  help: [
119
- `Run \`${follow("status")}\` to confirm the job reports cancelled`,
119
+ "A stopped job may no longer be queryable with `falcon-axi search status`",
120
120
  "Run `falcon-axi search start --query '<cql>'` to run a narrower search",
121
121
  ],
122
122
  };
@@ -1 +1 @@
1
- export const VERSION = "1.0.0-rc.1";
1
+ export const VERSION = "1.0.0-rc.2"; // x-release-please-version
package/README.md CHANGED
@@ -131,7 +131,7 @@ Run `falcon-axi config path` to inspect config and journal paths.
131
131
  | `FALCON_AXI_WRITE_LOG` | Mandatory RTR execution journal | State directory `writes.log` |
132
132
  | `XDG_CONFIG_HOME`, `XDG_STATE_HOME` | Absolute POSIX config / state roots | `~/.config`, `~/.local/state` |
133
133
  | `APPDATA`, `LOCALAPPDATA` | Windows config / state roots | `~/AppData/Roaming`, `~/AppData/Local` |
134
- | `HOME`, `PATH` | Home and hook executable discovery | Process environment / OS home |
134
+ | `HOME` | Home directory for session integrations | OS home directory |
135
135
  | `CLAUDECODE`, `CODEX_THREAD_ID`, `CODEX_SESSION_ID`, `PI_CODING_AGENT`, `OPENCODE` | Detect the host for skill-install hints | Unset |
136
136
  | `CLAUDE_CONFIG_DIR`, `PI_CODING_AGENT_DIR` | Host skill-discovery roots | `~/.claude`, `~/.pi/agent` |
137
137
  | `FALCON_CLIENT_ID`, `FALCON_CLIENT_SECRET`, `FALCON_MEMBER_CID`, `FALCON_BASE_URL`, `FALCON_PROXY_URL` | Deprecated aliases; replacements win | Unset |
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "parser": {
10
10
  "path": ".typescript-build/src/parser.js",
11
- "sha256": "19fc9b9145604071e06b790992dedfa9c09a162aac18dbf00ffd8184e003f1ca"
11
+ "sha256": "245e0b7b86311cb7876ef94dc3eab0550529501d14e25073516fad1c028c5552"
12
12
  },
13
13
  "skill": {
14
14
  "path": "skills/falcon-axi/SKILL.md",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowttl/falcon-axi",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -18,7 +18,7 @@ Do not allow a whole noun such as `host` or `search`: other subcommands can crea
18
18
  | Alert detail: `detection show <id>` | `falcon-axi detection show 'ldt:synthetic-agent-01:1001' --full` | `--full` removes long-field previews |
19
19
  | Alert process lineage: `detection process <id>` | `falcon-axi detection process 'ldt:synthetic-agent:1001'` | Trigger, parent, grandparent, hashes and graph pivot in one call; `--full` removes 800-character command-line previews |
20
20
  | Find host: `host list` | `falcon-axi host list --hostname 'synthetic-host-*' --limit 2 --fields status,os_version,agent_version` | `--platform windows`, `--since 24h`, `--filter <FQL>`; returns device IDs (AIDs) |
21
- | Host detail: `host show <device-id>` | `falcon-axi host show synthetic-device-01` | Full host record; no `--full` flag |
21
+ | Host detail: `host show <device-id>` | `falcon-axi host show 00000000000000000000000000000001` | Full host record; no `--full` flag |
22
22
  | Host address history: `host network <device-id>` | `falcon-axi host network synthetic-device-01` | Retained IP/MAC history; no pagination or time flag |
23
23
  | Interactive logins: `host logins <device-id>` | `falcon-axi host logins synthetic-device-01 --since 24h --limit 2` | Default window 7d; default 20, maximum 100 logins; a filled window may omit older logins |
24
24
  | Graph lineage: `process tree <pid-id>` | `falcon-axi process tree pid:synthetic-device:1` | Up to five ancestors and one child level, 100 child edges per page; `--cursor <token>` continues children; `--full` for complete command lines |
@@ -7,7 +7,7 @@ npx -y @knowttl/falcon-axi@next host show <device id>
7
7
 
8
8
  The device id is the agent id Falcon calls the AID, as printed by `npx -y @knowttl/falcon-axi@next host list`.
9
9
 
10
- Example: npx -y @knowttl/falcon-axi@next host show abc123
10
+ Example: npx -y @knowttl/falcon-axi@next host show 0123456789abcdef0123456789abcdef
11
11
 
12
12
  This command is read-only and requires only Hosts:read.
13
13
  ```