securenow 8.11.2 → 8.11.3

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/SKILL-CLI.md CHANGED
@@ -1,255 +1,255 @@
1
- # SecureNow CLI — Agent Skill
2
-
3
- Use the `securenow` CLI to perform security DevOps from the terminal: manage apps, investigate threats, control the firewall, analyze traces, handle false positives, and run instrumented Node.js processes. Every command supports `--json` for machine-readable output.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- # Install globally (recommended for CLI usage)
9
- npm install -g securenow
10
-
11
- # Or install per-project and use via npx
12
- npm install securenow@latest
13
- npx securenow <command>
14
- ```
15
-
16
- **Full parity with the SDK:** every capability the `securenow` Node SDK exposes has a CLI counterpart — redaction, CIDR matching, log/span emission, firewall preload, config inspection. If you can do it in code, you can do it from the terminal.
17
-
18
- **MCP parity (v8.0+):** the same package also ships a local stdio MCP server for Codex, Claude, and other MCP clients:
19
-
20
- ```bash
21
- npx securenow login
22
- codex mcp add securenow -- npx securenow mcp
23
- # or
24
- npx -p securenow securenow-mcp
25
- ```
26
-
27
- The MCP server reads admin/control-plane auth from `.securenow/admin.json` and SDK runtime app credentials from `.securenow/runtime.json`, with legacy `.securenow/credentials.json` still supported. Admin/global tools use admin auth; runtime-scoped read tools can use the runtime API key where its scopes allow it. Write tools require `confirm:true` plus a reason.
28
-
29
- ### Authenticate
30
-
31
- ```bash
32
- securenow login # friendly flow: admin auth + app runtime connection
33
- securenow admin login # admin/control-plane CLI and MCP auth only
34
- securenow app connect # app/runtime SDK connection only
35
- securenow admin login --token <JWT> # headless / CI admin auth
36
- securenow whoami # verify both admin auth and runtime app status
37
- ```
38
-
39
- **Two-lane credentials (v8.0+):** admin/control-plane auth lives in `.securenow/admin.json`; SDK runtime app config and the runtime API key live in `.securenow/runtime.json`. `securenow login` can run both lanes for onboarding, but `securenow admin login` never replaces runtime app config and `securenow app connect` never replaces admin auth. Legacy combined `.securenow/credentials.json` files are still read.
40
-
41
- **Zero-config runtime flow:** the browser step lets the user pick (or create) an app. The CLI stores the app's **key (UUID)** and **name** in `.securenow/runtime.json`. The SDK sends traces/logs to the default SecureNow ingestion gateway, which routes by app key, so no env vars or per-instance collector URLs are required for local dev or production.
42
-
43
- **Default-on security (v8.0+):** after picking or creating the app, `securenow app connect` turns on that app's firewall toggle, mints a runtime API key with `traces:write + logs:write + firewall:read + blocklist:read + allowlist:read` scopes, and writes it into `.securenow/runtime.json`. Traces, logs, POST body capture, multipart metadata capture, and the firewall are enabled by default. No `SECURENOW_API_KEY` env var is needed. To add or rotate a key later without re-running app connect, use `securenow api-key create` or `securenow api-key set snk_live_...` (see [API Key Management](#api-key-management) below).
44
-
45
- Runtime credentials resolve in order: project `.securenow/runtime.json` -> legacy project `.securenow/credentials.json` -> project named runtime credentials -> global `.securenow/runtime.json` -> legacy global credentials -> global named runtime credentials. Admin auth resolves from `admin.json` first, then legacy `credentials.json`. Runtime config is credentials-json based; environment-variable fallbacks are not supported.
46
-
47
- The **runtime API key** should live in runtime credentials as `apiKey`; it authenticates telemetry ingestion and firewall sync.
48
-
49
- For CI / Docker / production, use `securenow credentials runtime --env production` to generate a tokenless runtime file, then mount/copy it as `.securenow/credentials.json`. Since v7.7.2, mounting the generated `.securenow/credentials.production.json` filename directly also works when `credentials.json` is absent.
50
-
51
- **Environment model:** use one SecureNow app key for local, preview, staging, and production. The credentials field `config.runtime.deploymentEnvironment` separates traces/logs/firewall/forensics by environment. CLI security commands default to `production`; pass `--env local`, `--env staging`, or `--env all` only when that scope is intentional.
52
-
53
- ### Integrate With Your App
54
-
55
- The CLI can also instrument any Node.js app at launch — no code changes:
56
-
57
- ```bash
58
- # Express, Fastify, NestJS, Koa, Hapi, raw Node.js
59
- securenow run src/index.js
60
-
61
- # Or via the Node preload flag
62
- node -r securenow/register src/index.js
63
- ```
64
-
65
- For Next.js, run the interactive scaffolding:
66
-
67
- ```bash
68
- securenow login
69
- securenow init
70
- ```
71
-
72
- This auto-detects your framework, creates the necessary `instrumentation.ts` and `next.config.js` changes, and reuses the app, instance, and runtime API key written by login or `app connect` to `.securenow/runtime.json`.
73
-
74
- ### Install This Skill in Cursor
75
-
76
- Save this file as `.cursor/skills/securenow-cli/SKILL.md` in your project. Your AI agent will auto-discover it whenever you ask about CLI commands, security investigations, or firewall management.
77
-
78
- ## Configuration
79
-
80
- Config lives in `~/.securenow/` (global) and optionally `.securenow/` (per-project):
81
-
82
- | File | Content |
83
- |------|---------|
84
- | `~/.securenow/config.json` | `apiUrl`, `appUrl`, `defaultApp`, `output` |
85
- | `~/.securenow/admin.json` | `token`, `email`, `expiresAt` for global admin/control-plane CLI and MCP auth |
86
- | `~/.securenow/runtime.json` | `apiKey`, `app`, `config` for global SDK runtime |
87
- | `.securenow/admin.json` | `token`, `email`, `expiresAt` for project-local admin/control-plane CLI and MCP auth |
88
- | `.securenow/runtime.json` | `apiKey`, `app`, `config`, `_securenow.explanations` for project-local SDK runtime |
89
- | `.securenow/credentials.json` | Legacy combined credentials; still read for backward compatibility |
90
- | `.securenow/credentials.<environment>.json` | Tokenless runtime credentials generated by `securenow credentials runtime --env <environment>`; read in a fixed order, not selected from env vars |
91
-
92
- **Credential resolution order:** runtime config resolves from project `.securenow/runtime.json` -> legacy project `.securenow/credentials.json` -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global `.securenow/runtime.json` -> legacy global credentials -> global named runtime credentials. Admin auth resolves from `admin.json` first, then legacy `credentials.json`. Environment-variable fallbacks are not supported.
93
-
94
- **Runtime API key resolution (v8.0+):** project `.securenow/runtime.json` -> legacy project credentials -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global runtime credentials -> legacy global credentials -> global named runtime credentials. Use `securenow app connect` for runtime setup or `securenow api-key set` to rotate a key without touching admin auth or env vars.
95
-
96
- ```bash
97
- securenow config set apiUrl https://api.securenow.ai
98
- securenow config set defaultApp my-app-key
99
- securenow config get # show all
100
- securenow config get defaultApp # show one
101
- securenow config path # print file paths + active auth source
102
- ```
103
-
104
- Legacy CLI overrides still exist for operator automation, but runtime SDK config should stay in the credentials file.
105
-
106
- ## Global Flags
107
-
108
- | Flag | Short | Effect |
109
- |------|-------|--------|
110
- | `--json` | `-j` | JSON output (pipe-friendly) |
111
- | `--help` | | Show help for any command |
112
- | `--verbose` | `-v` | Verbose output |
113
- | `--force` | `-f` | Skip confirmations |
114
- | `--yes` | `-y` | Auto-confirm prompts |
115
-
116
- SecureNow-specific environment overrides are not supported; use `.securenow/runtime.json`, `.securenow/admin.json`, or `securenow config set`.
117
-
118
- ---
119
-
120
- ## Command Reference
121
-
122
- ### Run — Instrument Any Node.js App
123
-
124
- ```bash
125
- securenow run <script> # auto-detect CJS/ESM, inject OTel preload
126
- securenow run --watch src/index.js # pass Node flags through
127
- securenow run --inspect src/server.js --port 3000
128
- securenow run --firewall-only app.js # preload firewall only (no tracing overhead)
129
- securenow src/index.js # shorthand — auto-detected as "run"
130
- ```
131
-
132
- Spawns `node --require securenow/register [--import otel/hook.mjs] <script>`. ESM detection uses nearest `package.json` `"type"` field or `.mjs`/`.cjs` extension. With `--firewall-only`, uses `securenow/firewall-only` instead (credentials-file firewall, no OpenTelemetry).
133
-
134
- ### Authentication
135
-
136
- ```bash
137
- securenow login # friendly flow: admin auth + app runtime connection
138
- securenow admin login # admin/control-plane CLI and MCP auth only
139
- securenow admin login --token <JWT> # headless / CI admin auth
140
- securenow app connect # app/runtime SDK connection only
141
- securenow logout # clear admin auth; runtime app config remains
142
- securenow logout --global # clear global admin auth only
143
- securenow whoami # show admin auth and runtime app status separately
144
- ```
145
-
146
- ### Applications
147
-
148
- ```bash
149
- securenow apps # list all apps (default subcommand)
150
- securenow apps list # same as above
151
- securenow apps create <name> [--hosts h1,h2] [--instance <id>] # interactive instance picker
152
- securenow apps info <id> # show app details
153
- securenow apps delete <id> [--force] # delete an app
154
- securenow apps default <app-key> # set default app for all commands
155
- securenow apps discover [appId] [--domain example.com] # discover subdomains, add as apps
156
- securenow apps scan [--yes] # scan all app domains for new subdomains
157
- ```
158
-
159
- ### API Key Management
160
-
161
- Manage the runtime API key stored in runtime credentials. Since v8.0 the app runtime flow writes app-scoped `snk_live_...` keys to `.securenow/runtime.json` by default, so no env var is required for local dev.
162
-
163
- ```bash
164
- securenow api-key create --name "CLI runtime" # mint + save a current-app runtime key
165
- securenow api-key create --app <key-or-id> # mint + save a runtime key scoped to another app
166
- securenow api-key set snk_live_xxxxxxxxxx # save to project ./.securenow/ (default)
167
- securenow api-key set snk_live_xxx --global # save to ~/.securenow/ instead
168
- securenow api-key show # print the masked current key + its source
169
- securenow api-key clear # remove just the API key (keeps session/app)
170
- securenow api-key clear --global # same, but from the global file
171
- securenow credentials runtime --env production # write .securenow/credentials.production.json for production secret-file deploys
172
- ```
173
-
174
- The key must start with `snk_live_`. `securenow app connect` writes the key automatically; use `api-key create` when you have admin auth but no runtime key yet, or `api-key set` when you already have a key from the dashboard. `api-key create` defaults to the current app in `.securenow/runtime.json`, resolves that app UUID to the server app id, creates a one-app `runtime_app` key with `traces:write`, `logs:write`, `firewall:read`, `blocklist:read`, and `allowlist:read`, then stores the one-time plaintext key as `apiKey`.
175
-
176
- ### Init — Project Setup
177
-
178
- ```bash
179
- securenow init [--env local] [--key <API_KEY>]
180
- ```
181
-
182
- Auto-detects framework (Next.js, Nuxt, Express, Fastify, Koa, Hapi, Node) from `package.json`. Then:
183
- - **Credentials**: ensures `.securenow/runtime.json` exists with secure defaults and explanations
184
- - **Next.js**: creates `instrumentation.ts/js` with `securenow/nextjs` + `securenow/nextjs-auto-capture`, and adds `serverExternalPackages: ['securenow']` plus `outputFileTracingIncludes` when the config can be patched safely
185
- - **Existing Next.js files**: prints a Codex/Claude-ready merge prompt when instrumentation or config already exists or is too custom to safely patch
186
- - **Nuxt**: tells you to add `securenow/nuxt` to modules
187
- - **Node/Express/etc.**: suggests adding `-r securenow/register` to start script
188
- - Reuses `.securenow/runtime.json` written by login/app connect; production should mount/copy the tokenless runtime file generated by `securenow credentials runtime --env production`
189
-
190
- ### Dashboard & Status
191
-
192
- ```bash
193
- securenow status [--app <key>] [--env local|production|all] # dashboard overview
194
- securenow analytics [--app <key>] # response analytics
195
- ```
196
-
197
- ---
198
-
199
- ### Traces
200
-
201
- ```bash
202
- securenow traces [--app <key>] [--env production] [--limit N] [--start ISO] [--end ISO]
203
- securenow traces list --app my-app --env production --limit 50
204
- securenow traces show <traceId> --env production # full trace detail with spans
205
- securenow traces analyze <traceId> --env production # AI-powered trace analysis
206
- ```
207
-
208
- ### Logs
209
-
210
- ```bash
211
- securenow logs [--app <key>] [--env production] [--limit N] [--minutes M] [--level error|warn|info]
212
- securenow logs list --app my-app --env production --minutes 30 --level error
213
- securenow logs trace <traceId> --env production # logs correlated to a specific trace
214
- ```
215
-
216
- ### Notifications
217
-
218
- ```bash
219
- securenow notifications [--limit N] [--page P]
220
- securenow notifications list --limit 20
221
- securenow notifications read <id> # mark one as read
222
- securenow notifications read-all # mark all as read
223
- securenow notifications unread # unread count
224
- ```
225
-
226
- ### Human Actions — AI-Prepared Decision Queue
227
-
228
- Use this for the same work shown in **Requires Human**: AI has already grouped alerts, fetched traces, built a report, and left a final Block IP or False Positive decision.
229
-
230
- ```bash
231
- securenow human # list human decisions, most urgent first
232
- securenow human list --limit 20
233
- securenow human show 1 # inspect row 1 with AI report, investigation steps, proofs, trace links
234
- securenow human block 1 --yes --reason "AI evidence confirmed malicious"
235
- securenow human fp 1 --yes --reason "Scoped false positive after evidence review"
236
- securenow human action 1 --status rejected --yes --reason "Tuning guard is too broad"
237
- securenow human prompt 1 # print a Codex/Claude MCP prompt for this row
238
- securenow human work --limit 10 # list queue + print MCP runbook for deep queue work
239
- ```
240
-
241
- MCP parity:
242
-
243
- - `securenow_human_actions_list`
244
- - `securenow_notifications_get`
245
- - `securenow_human_action_report`
246
- - `securenow_human_action_block`
247
- - `securenow_human_action_false_positive`
248
- - `securenow_human_case_action_update`
249
- - prompts: `investigate_human_action_row`, `work_human_actions`
250
-
251
- Write tools still require `confirm:true` plus a reason. False positives should stay restrictive to the app, alert rule, path, method/status, user-agent, body pattern, or other exact evidence the AI report supports. Notification IP investigations can include `metadata.matchedSubdetectors`; prefer that exact field over inferring which subdetector fired from the title or sample body.
252
-
1
+ # SecureNow CLI — Agent Skill
2
+
3
+ Use the `securenow` CLI to perform security DevOps from the terminal: manage apps, investigate threats, control the firewall, analyze traces, handle false positives, and run instrumented Node.js processes. Every command supports `--json` for machine-readable output.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Install globally (recommended for CLI usage)
9
+ npm install -g securenow
10
+
11
+ # Or install per-project and use via npx
12
+ npm install securenow@latest
13
+ npx securenow <command>
14
+ ```
15
+
16
+ **Full parity with the SDK:** every capability the `securenow` Node SDK exposes has a CLI counterpart — redaction, CIDR matching, log/span emission, firewall preload, config inspection. If you can do it in code, you can do it from the terminal.
17
+
18
+ **MCP parity (v8.0+):** the same package also ships a local stdio MCP server for Codex, Claude, and other MCP clients:
19
+
20
+ ```bash
21
+ npx securenow login
22
+ codex mcp add securenow -- npx securenow mcp
23
+ # or
24
+ npx -p securenow securenow-mcp
25
+ ```
26
+
27
+ The MCP server reads admin/control-plane auth from `.securenow/admin.json` and SDK runtime app credentials from `.securenow/runtime.json`, with legacy `.securenow/credentials.json` still supported. Admin/global tools use admin auth; runtime-scoped read tools can use the runtime API key where its scopes allow it. Write tools require `confirm:true` plus a reason.
28
+
29
+ ### Authenticate
30
+
31
+ ```bash
32
+ securenow login # friendly flow: admin auth + app runtime connection
33
+ securenow admin login # admin/control-plane CLI and MCP auth only
34
+ securenow app connect # app/runtime SDK connection only
35
+ securenow admin login --token <JWT> # headless / CI admin auth
36
+ securenow whoami # verify both admin auth and runtime app status
37
+ ```
38
+
39
+ **Two-lane credentials (v8.0+):** admin/control-plane auth lives in `.securenow/admin.json`; SDK runtime app config and the runtime API key live in `.securenow/runtime.json`. `securenow login` can run both lanes for onboarding, but `securenow admin login` never replaces runtime app config and `securenow app connect` never replaces admin auth. Legacy combined `.securenow/credentials.json` files are still read.
40
+
41
+ **Zero-config runtime flow:** the browser step lets the user pick (or create) an app. The CLI stores the app's **key (UUID)** and **name** in `.securenow/runtime.json`. The SDK sends traces/logs to the default SecureNow ingestion gateway, which routes by app key, so no env vars or per-instance collector URLs are required for local dev or production.
42
+
43
+ **Default-on security (v8.0+):** after picking or creating the app, `securenow app connect` turns on that app's firewall toggle, mints a runtime API key with `traces:write + logs:write + firewall:read + blocklist:read + allowlist:read` scopes, and writes it into `.securenow/runtime.json`. Traces, logs, POST body capture, multipart metadata capture, and the firewall are enabled by default. No `SECURENOW_API_KEY` env var is needed. To add or rotate a key later without re-running app connect, use `securenow api-key create` or `securenow api-key set snk_live_...` (see [API Key Management](#api-key-management) below).
44
+
45
+ Runtime credentials resolve in order: project `.securenow/runtime.json` -> legacy project `.securenow/credentials.json` -> project named runtime credentials -> global `.securenow/runtime.json` -> legacy global credentials -> global named runtime credentials. Admin auth resolves from `admin.json` first, then legacy `credentials.json`. Runtime config is credentials-json based; environment-variable fallbacks are not supported.
46
+
47
+ The **runtime API key** should live in runtime credentials as `apiKey`; it authenticates telemetry ingestion and firewall sync.
48
+
49
+ For CI / Docker / production, use `securenow credentials runtime --env production` to generate a tokenless runtime file, then mount/copy it as `.securenow/credentials.json`. Since v7.7.2, mounting the generated `.securenow/credentials.production.json` filename directly also works when `credentials.json` is absent.
50
+
51
+ **Environment model:** use one SecureNow app key for local, preview, staging, and production. The credentials field `config.runtime.deploymentEnvironment` separates traces/logs/firewall/forensics by environment. CLI security commands default to `production`; pass `--env local`, `--env staging`, or `--env all` only when that scope is intentional.
52
+
53
+ ### Integrate With Your App
54
+
55
+ The CLI can also instrument any Node.js app at launch — no code changes:
56
+
57
+ ```bash
58
+ # Express, Fastify, NestJS, Koa, Hapi, raw Node.js
59
+ securenow run src/index.js
60
+
61
+ # Or via the Node preload flag
62
+ node -r securenow/register src/index.js
63
+ ```
64
+
65
+ For Next.js, run the interactive scaffolding:
66
+
67
+ ```bash
68
+ securenow login
69
+ securenow init
70
+ ```
71
+
72
+ This auto-detects your framework, creates the necessary `instrumentation.ts` and `next.config.js` changes, and reuses the app, instance, and runtime API key written by login or `app connect` to `.securenow/runtime.json`.
73
+
74
+ ### Install This Skill in Cursor
75
+
76
+ Save this file as `.cursor/skills/securenow-cli/SKILL.md` in your project. Your AI agent will auto-discover it whenever you ask about CLI commands, security investigations, or firewall management.
77
+
78
+ ## Configuration
79
+
80
+ Config lives in `~/.securenow/` (global) and optionally `.securenow/` (per-project):
81
+
82
+ | File | Content |
83
+ |------|---------|
84
+ | `~/.securenow/config.json` | `apiUrl`, `appUrl`, `defaultApp`, `output` |
85
+ | `~/.securenow/admin.json` | `token`, `email`, `expiresAt` for global admin/control-plane CLI and MCP auth |
86
+ | `~/.securenow/runtime.json` | `apiKey`, `app`, `config` for global SDK runtime |
87
+ | `.securenow/admin.json` | `token`, `email`, `expiresAt` for project-local admin/control-plane CLI and MCP auth |
88
+ | `.securenow/runtime.json` | `apiKey`, `app`, `config`, `_securenow.explanations` for project-local SDK runtime |
89
+ | `.securenow/credentials.json` | Legacy combined credentials; still read for backward compatibility |
90
+ | `.securenow/credentials.<environment>.json` | Tokenless runtime credentials generated by `securenow credentials runtime --env <environment>`; read in a fixed order, not selected from env vars |
91
+
92
+ **Credential resolution order:** runtime config resolves from project `.securenow/runtime.json` -> legacy project `.securenow/credentials.json` -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global `.securenow/runtime.json` -> legacy global credentials -> global named runtime credentials. Admin auth resolves from `admin.json` first, then legacy `credentials.json`. Environment-variable fallbacks are not supported.
93
+
94
+ **Runtime API key resolution (v8.0+):** project `.securenow/runtime.json` -> legacy project credentials -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global runtime credentials -> legacy global credentials -> global named runtime credentials. Use `securenow app connect` for runtime setup or `securenow api-key set` to rotate a key without touching admin auth or env vars.
95
+
96
+ ```bash
97
+ securenow config set apiUrl https://api.securenow.ai
98
+ securenow config set defaultApp my-app-key
99
+ securenow config get # show all
100
+ securenow config get defaultApp # show one
101
+ securenow config path # print file paths + active auth source
102
+ ```
103
+
104
+ Legacy CLI overrides still exist for operator automation, but runtime SDK config should stay in the credentials file.
105
+
106
+ ## Global Flags
107
+
108
+ | Flag | Short | Effect |
109
+ |------|-------|--------|
110
+ | `--json` | `-j` | JSON output (pipe-friendly) |
111
+ | `--help` | | Show help for any command |
112
+ | `--verbose` | `-v` | Verbose output |
113
+ | `--force` | `-f` | Skip confirmations |
114
+ | `--yes` | `-y` | Auto-confirm prompts |
115
+
116
+ SecureNow-specific environment overrides are not supported; use `.securenow/runtime.json`, `.securenow/admin.json`, or `securenow config set`.
117
+
118
+ ---
119
+
120
+ ## Command Reference
121
+
122
+ ### Run — Instrument Any Node.js App
123
+
124
+ ```bash
125
+ securenow run <script> # auto-detect CJS/ESM, inject OTel preload
126
+ securenow run --watch src/index.js # pass Node flags through
127
+ securenow run --inspect src/server.js --port 3000
128
+ securenow run --firewall-only app.js # preload firewall only (no tracing overhead)
129
+ securenow src/index.js # shorthand — auto-detected as "run"
130
+ ```
131
+
132
+ Spawns `node --require securenow/register [--import otel/hook.mjs] <script>`. ESM detection uses nearest `package.json` `"type"` field or `.mjs`/`.cjs` extension. With `--firewall-only`, uses `securenow/firewall-only` instead (credentials-file firewall, no OpenTelemetry).
133
+
134
+ ### Authentication
135
+
136
+ ```bash
137
+ securenow login # friendly flow: admin auth + app runtime connection
138
+ securenow admin login # admin/control-plane CLI and MCP auth only
139
+ securenow admin login --token <JWT> # headless / CI admin auth
140
+ securenow app connect # app/runtime SDK connection only
141
+ securenow logout # clear admin auth; runtime app config remains
142
+ securenow logout --global # clear global admin auth only
143
+ securenow whoami # show admin auth and runtime app status separately
144
+ ```
145
+
146
+ ### Applications
147
+
148
+ ```bash
149
+ securenow apps # list all apps (default subcommand)
150
+ securenow apps list # same as above
151
+ securenow apps create <name> [--hosts h1,h2] [--instance <id>] # interactive instance picker
152
+ securenow apps info <id> # show app details
153
+ securenow apps delete <id> [--force] # delete an app
154
+ securenow apps default <app-key> # set default app for all commands
155
+ securenow apps discover [appId] [--domain example.com] # discover subdomains, add as apps
156
+ securenow apps scan [--yes] # scan all app domains for new subdomains
157
+ ```
158
+
159
+ ### API Key Management
160
+
161
+ Manage the runtime API key stored in runtime credentials. Since v8.0 the app runtime flow writes app-scoped `snk_live_...` keys to `.securenow/runtime.json` by default, so no env var is required for local dev.
162
+
163
+ ```bash
164
+ securenow api-key create --name "CLI runtime" # mint + save a current-app runtime key
165
+ securenow api-key create --app <key-or-id> # mint + save a runtime key scoped to another app
166
+ securenow api-key set snk_live_xxxxxxxxxx # save to project ./.securenow/ (default)
167
+ securenow api-key set snk_live_xxx --global # save to ~/.securenow/ instead
168
+ securenow api-key show # print the masked current key + its source
169
+ securenow api-key clear # remove just the API key (keeps session/app)
170
+ securenow api-key clear --global # same, but from the global file
171
+ securenow credentials runtime --env production # write .securenow/credentials.production.json for production secret-file deploys
172
+ ```
173
+
174
+ The key must start with `snk_live_`. `securenow app connect` writes the key automatically; use `api-key create` when you have admin auth but no runtime key yet, or `api-key set` when you already have a key from the dashboard. `api-key create` defaults to the current app in `.securenow/runtime.json`, resolves that app UUID to the server app id, creates a one-app `runtime_app` key with `traces:write`, `logs:write`, `firewall:read`, `blocklist:read`, and `allowlist:read`, then stores the one-time plaintext key as `apiKey`.
175
+
176
+ ### Init — Project Setup
177
+
178
+ ```bash
179
+ securenow init [--env local] [--key <API_KEY>]
180
+ ```
181
+
182
+ Auto-detects framework (Next.js, Nuxt, Express, Fastify, Koa, Hapi, Node) from `package.json`. Then:
183
+ - **Credentials**: ensures `.securenow/runtime.json` exists with secure defaults and explanations
184
+ - **Next.js**: creates `instrumentation.ts/js` with `securenow/nextjs` + `securenow/nextjs-auto-capture`, and adds `serverExternalPackages: ['securenow']` plus `outputFileTracingIncludes` when the config can be patched safely
185
+ - **Existing Next.js files**: prints a Codex/Claude-ready merge prompt when instrumentation or config already exists or is too custom to safely patch
186
+ - **Nuxt**: tells you to add `securenow/nuxt` to modules
187
+ - **Node/Express/etc.**: suggests adding `-r securenow/register` to start script
188
+ - Reuses `.securenow/runtime.json` written by login/app connect; production should mount/copy the tokenless runtime file generated by `securenow credentials runtime --env production`
189
+
190
+ ### Dashboard & Status
191
+
192
+ ```bash
193
+ securenow status [--app <key>] [--env local|production|all] # dashboard overview
194
+ securenow analytics [--app <key>] # response analytics
195
+ ```
196
+
197
+ ---
198
+
199
+ ### Traces
200
+
201
+ ```bash
202
+ securenow traces [--app <key>] [--env production] [--limit N] [--start ISO] [--end ISO]
203
+ securenow traces list --app my-app --env production --limit 50
204
+ securenow traces show <traceId> --env production # full trace detail with spans
205
+ securenow traces analyze <traceId> --env production # AI-powered trace analysis
206
+ ```
207
+
208
+ ### Logs
209
+
210
+ ```bash
211
+ securenow logs [--app <key>] [--env production] [--limit N] [--minutes M] [--level error|warn|info]
212
+ securenow logs list --app my-app --env production --minutes 30 --level error
213
+ securenow logs trace <traceId> --env production # logs correlated to a specific trace
214
+ ```
215
+
216
+ ### Notifications
217
+
218
+ ```bash
219
+ securenow notifications [--limit N] [--page P]
220
+ securenow notifications list --limit 20
221
+ securenow notifications read <id> # mark one as read
222
+ securenow notifications read-all # mark all as read
223
+ securenow notifications unread # unread count
224
+ ```
225
+
226
+ ### Human Actions — AI-Prepared Decision Queue
227
+
228
+ Use this for the same work shown in **Requires Human**: AI has already grouped alerts, fetched traces, built a report, and left a final Block IP or False Positive decision.
229
+
230
+ ```bash
231
+ securenow human # list human decisions, most urgent first
232
+ securenow human list --limit 20
233
+ securenow human show 1 # inspect row 1 with AI report, investigation steps, proofs, trace links
234
+ securenow human block 1 --yes --reason "AI evidence confirmed malicious"
235
+ securenow human fp 1 --yes --reason "Scoped false positive after evidence review"
236
+ securenow human action 1 --status rejected --yes --reason "Tuning guard is too broad"
237
+ securenow human prompt 1 # print a Codex/Claude MCP prompt for this row
238
+ securenow human work --limit 10 # list queue + print MCP runbook for deep queue work
239
+ ```
240
+
241
+ MCP parity:
242
+
243
+ - `securenow_human_actions_list`
244
+ - `securenow_notifications_get`
245
+ - `securenow_human_action_report`
246
+ - `securenow_human_action_block`
247
+ - `securenow_human_action_false_positive`
248
+ - `securenow_human_case_action_update`
249
+ - prompts: `investigate_human_action_row`, `work_human_actions`
250
+
251
+ Write tools still require `confirm:true` plus a reason. False positives should stay restrictive to the app, alert rule, path, method/status, user-agent, body pattern, or other exact evidence the AI report supports. Notification IP investigations can include `metadata.matchedSubdetectors`; prefer that exact field over inferring which subdetector fired from the title or sample body.
252
+
253
253
  ### Alerts
254
254
 
255
255
  Before authoring any alert SQL, load the contract shipped by the installed package and compare
@@ -271,385 +271,376 @@ its fields were observed and `alerts rules validate` succeeds. Otherwise label i
271
271
  `NEEDS_INSTRUMENTATION`, `NEEDS_BASELINE`, or `NEEDS_CUSTOMER_DECISION` as appropriate.
272
272
 
273
273
  ```bash
274
- securenow alerts # list alert rules (default)
275
- securenow alerts rules # list alert rules (columns: Status, Applications, Schedule)
276
- securenow alerts rules validate \ # dry-run a candidate query BEFORE creating any rule
277
- --sql @rule.sql --app <key> # no rule id needed — auto-hosts on an existing (system) rule
278
- securenow alerts rules create \ # create a custom detection rule from inline SQL
279
- --name "Auth: magic-link brute force" \
280
- --sql @rule.sql \ # SQL, @file, or - for stdin; scope apps with __USER_APP_KEYS__
281
- --apps key1,key2 \ # or --applications-all
282
- --severity high --schedule "*/15 * * * *" \
283
- --nlp "single IP flooding /api/auth/signin or /api/auth/callback"
284
- # create auto dry-runs + rolls back (deletes) on query failure; --no-validate to skip
285
- securenow alerts rules show <id> # one rule; JSON: --json
286
- securenow alerts rules set-sql <id> --sql @new.sql # replace a CUSTOM rule's SQL in place (alias: update <id> --sql)
287
- securenow alerts rules delete <id> --yes # delete a custom rule (system rules: disable instead)
288
- securenow alerts rules update <id> --applications-all # all current & future apps
289
- securenow alerts rules update <id> --apps key1,key2 # explicit app keys only
290
- securenow alerts rules test <id> --mode dry_run --wait # validate an existing rule's query
291
- securenow alerts rules dry-run-query <id> --sql @candidate.sql --app <key> --wait # candidate test against a specific host rule
292
- securenow alerts rules tune-query <id> --sql @candidate.sql --reason "Preserve exploit detector, remove benign broad match" --apply-globally --yes
293
- securenow alerts rules exclusions <id> list # embedded rule exclusions
294
- securenow alerts channels # list alert channels (Slack, email, etc.)
295
- securenow alerts history [--limit N] # past triggered alerts
296
- ```
297
-
298
- **Authoring loop that won't strand a broken rule:** `validate --sql @rule.sql --app <key>`
299
- (dry-run before anything exists) → `create …` (which itself dry-runs and auto-rolls-back on
300
- failure) → if you later need to fix it, `set-sql <id> --sql @rule.sql` (custom rules) or
301
- `delete <id>`. Detection `.sql` files may start with `--`/`/* */` comments. Custom-rule SQL is
302
- editable; **system**-rule SQL changes go through `tune-query … --apply-globally`. Pick the
303
- right tenant-scope column per table: logs (`signoz_logs.distributed_logs_v2`) use
304
- `resources_string['service.name'] IN (__USER_APP_KEYS__)`, traces
305
- (`signoz_traces.distributed_signoz_index_v3`) use `` `resource_string_service$$name` IN (__USER_APP_KEYS__) ``.
306
-
307
- `alerts rules create` flags: `--name` (required); one of `--sql <sql|@file|->` or `--query-mapping-id <id>`; one of `--apps k1,k2` or `--applications-all`; optional `--description`, `--nlp` (plain-English intent), `--category`, `--severity critical|high|medium|low`, `--schedule <cron>` (default `*/15 * * * *`), `--throttle-minutes N` / `--no-throttle`, `--execution-mode scheduled|instant|hybrid`, `--channel id1,id2` (defaults to your in-app SecureNow channel). Detection SQL must scope app keys via the `__USER_APP_KEYS__` placeholder and select an `ip` column for per-IP aggregation/remediation. Requires `alerts:write`.
308
-
309
- MCP parity for noisy alert-rule reviews:
310
-
311
- - `securenow_alert_rule_get`
312
- - `securenow_alert_rule_candidate_test` dry-runs a full candidate SQL query without saving it.
313
- - `securenow_alert_rule_test_result` polls the dry-run.
314
- - `securenow_alert_rule_query_update` updates the shared public query mapping behind a system rule for all customer copies. It is admin-only, requires `confirm:true`, `applyGlobally:true`, `reason`, and SQL that keeps `__USER_APP_KEYS__` tenant scoping.
315
- - `securenow_alert_rule_instant_update` patches Instant rule conditions/config with stale-write guards. Fetch the rule first, pass `expectedRuleVersion` plus `expectedCurrentInstantHash`, use operations such as `remove_condition` / `add_condition` / `update_condition`, and set `applyGlobally:true` for system rules. The API runs seeded before/after checks and returns benign samples removed plus attack samples still matching. If global tuning is denied, it returns a structured admin handoff with the exact patch and missing permission.
316
- - `securenow_alert_rule_exclusion_add` remains the last-resort customer-specific path; it supports restrictive conditions plus `matchMode` and should not be used to hide a generic system-rule bug.
317
-
318
- For system-rule tuning, dry-run the candidate SQL first for scheduled rules, or use `dryRun:true` on `securenow_alert_rule_instant_update` for Instant rules. Save only when the guard preserves attack detection. Good guards add exact exploit tokens, dangerous schemes, matched subdetectors, sensitive path/status evidence, malicious user agents, or repeat thresholds; bad guards simply suppress a noisy path.
319
-
320
- ---
321
-
322
- ### IP Intelligence
323
-
324
- ```bash
325
- securenow ip <ip-address> # lookup (geo, ASN, threat score, reputation)
326
- securenow ip lookup <ip-address> # same as above
327
- securenow ip traces <ip-address> --env production # traces originating from this IP
328
- ```
329
-
330
- ### Forensics — Natural Language Security Queries
331
-
332
- ```bash
333
- securenow forensics "show me all SQL injection attempts in the last 24h" --env production
334
- securenow forensics query "top 10 IPs by blocked requests" --app my-app --env production
335
- securenow forensics chat --app my-app --env production # interactive forensics chat session
336
- securenow forensics library # view saved/template queries
337
- ```
338
-
339
- ### API Map
340
-
341
- ```bash
342
- securenow api-map # list discovered API endpoints
343
- securenow api-map list # same
344
- securenow api-map stats # endpoint statistics
345
- ```
346
-
347
- ---
348
-
349
- ### Firewall
350
-
351
- ```bash
352
- securenow firewall # show status (default)
353
- securenow firewall status --app <key> --env production # app/env toggle, sync time, blocked count
354
- securenow firewall test-ip <ip> --app <key> --env local # check if IP would be blocked
355
- ```
356
-
357
- **Zero-config setup:** running `securenow app connect` enables the selected app's firewall toggle, auto-mints a runtime API key (scoped `traces:write + logs:write + firewall:read + blocklist:read + allowlist:read`), and writes it to `.securenow/runtime.json` after the app is selected. No `SECURENOW_API_KEY` env var needed. If the user already has a key, `securenow api-key set snk_live_...` achieves the same thing; if they only have admin auth, `securenow api-key create` mints and saves a fresh runtime key. See [the landing firewall page](https://securenow.ai/firewall) for an overview.
358
-
359
- ### Blocklist — Block Malicious IPs
360
-
361
- ```bash
362
- securenow blocklist # list blocked IPs
363
- securenow blocklist list
364
- securenow blocklist add <ip> --app <key> --env production --reason "Brute force"
365
- securenow blocklist add <ip> --route /admin* --mode prefix --method ALL --reason "Admin probing"
366
- securenow blocklist unblock <id> --reason "False alarm after review"
367
- securenow blocklist remove <id> # compatibility alias for unblock
368
- securenow blocklist list --status removed # audit retained unblocks
369
- securenow blocklist stats # block counts, top reasons
370
- ```
371
-
372
- Scoped blocks use the same model as rate limits: `--route`/`--path`/`--pattern`
373
- sets `pathPattern`, `--mode`/`--path-mode` chooses `prefix`, `exact`, or
374
- `regex`, and `--method` limits enforcement to one HTTP method or `ALL`.
375
-
376
- Unblock stops firewall enforcement but preserves the block report, history, and
377
- unblock audit fields. Reblocking the same IP later creates a fresh active block
378
- without erasing the previous investigation trail.
379
-
380
- MCP exposes legacy pending-block cleanup separately from current Requires Human
381
- work:
382
-
383
- - `securenow_blocklist_unblock`
384
- - `securenow_blocklist_remove` (compatibility alias for unblock)
385
- - `securenow_blocklist_pending_list`
386
- - `securenow_blocklist_pending_approve`
387
- - `securenow_blocklist_pending_reject`
388
- - `securenow_blocklist_pending_bulk_approve`
389
- - `securenow_blocklist_pending_bulk_reject`
390
- - prompt: `cleanup_legacy_pending_blocks`
391
-
392
- ### Rate Limits - Soft Remediation
393
-
394
- ```bash
395
- securenow ratelimit list --env production
396
- securenow ratelimit add 203.0.113.42 --route /api/login --limit 2 --window 1m --duration 24h
397
- securenow ratelimit parse "rate limit 203.0.113.42 on POST /api/login to 2 attempts per minute"
398
- securenow ratelimit from-text "rate limit /api/login for this IP to 2 attempts per minute for 24h" --yes
399
- securenow ratelimit test 203.0.113.42 --path /api/login --method POST
400
- ```
401
-
402
- MCP parity:
403
-
404
- - `securenow_rate_limit_parse`
405
- - `securenow_rate_limit_create_from_text`
406
-
407
- ### Automation Rules
408
-
409
- ```bash
410
- securenow automation # list blocklist automation rules
411
- securenow automation defaults --yes # ensure built-in default risk-score rules
412
- securenow automation show <id>
413
- securenow automation dry-run <id> --limit 500
414
- securenow automation execute <id> --yes
415
- ```
416
-
417
- Built-in default automation is enabled by default for all apps/environments and
418
- uses the canonical `riskScore`: 95-100 blocks for 7 days, 90-94 blocks for 72h,
419
- 85-89 blocks for 24h, and scores below 85 stay in investigation/review unless
420
- the customer adds a stricter custom rule. Raw SecureNow IPDB confidence remains
421
- supporting evidence, not the primary automation score.
422
-
423
- ### Allowlist — Restrict to Known IPs
424
-
425
- Dangerous production mode: IP Allowlist is deny-by-default. Once any active
426
- allowlist entry exists for an app/environment, only listed IPs can reach it and
427
- all other IPs are blocked. Do not use allowlist to mark an IP trusted, suppress
428
- false positives, or clean up investigations. Use `securenow trusted add` for
429
- known-safe monitors, office/VPN traffic, or trusted bypass cases.
430
-
431
- ```bash
432
- securenow allowlist # list allowed IPs
433
- securenow allowlist list
434
- securenow allowlist add <ip> --app <key> --env local --label "Office" --reason "Corporate VPN"
435
- securenow allowlist remove <id>
436
- securenow allowlist stats
437
- ```
438
-
439
- ### Trusted IPs
440
-
441
- Trusted IPs are the safe bypass/suppression mechanism for known infrastructure
442
- and do not enable deny-by-default allowlist mode.
443
-
444
- ```bash
445
- securenow trusted # list trusted IPs
446
- securenow trusted list
447
- securenow trusted add <ip> [--label "CloudFlare edge"]
448
- securenow trusted remove <id>
449
- ```
450
-
451
- ---
452
-
453
- ### False Positive Management
454
-
455
- The `fp` command manages exclusion rules that prevent known-safe traffic from triggering security alerts.
456
-
457
- ```bash
458
- securenow fp # list all exclusion rules
459
- securenow fp list
460
- securenow fp show <id> # rule details
461
- securenow fp delete <id> [--yes]
462
-
463
- # Create exclusion rules
464
- securenow fp create \
465
- --conditions '[{"field":"http.target","op":"starts_with","value":"/api/health"}]' \
466
- --match-mode all \
467
- --rule-scope any_rule \
468
- --reason "Health check endpoint"
469
-
470
- # Shorthand safe-value presets
471
- securenow fp create \
472
- --path /api/events \
473
- --method POST \
474
- --path-safe standard \
475
- --ua-safe standard \
476
- --headers-safe standard \
477
- --query-keys page,limit \
478
- --headers-keys host,content-type \
479
- --reason "Event webhook"
480
-
481
- # Edit an existing rule
482
- securenow fp edit <id> [--active true|false] [--conditions '[...]']
483
-
484
- # Test conditions against a request body
485
- securenow fp test-body '{"user":"admin"}' --conditions '[{"field":"body.user","op":"eq","value":"admin"}]'
486
- securenow fp test-body @request.json --conditions '[...]'
487
-
488
- # Dry-run conditions against the last 3 days of live traces
489
- securenow fp dry-run --conditions '[{"field":"http.target","op":"starts_with","value":"/api/webhook"}]'
490
-
491
- # AI-generate exclusion conditions from a description
492
- securenow fp ai-fill --description "Stripe webhook POST to /api/stripe/webhook" \
493
- --context '{"method":"POST","path":"/api/stripe/webhook"}'
494
-
495
- # Mark an IP as false positive on a specific notification
496
- securenow fp mark <notification-id> <ip> \
497
- [--conditions '[...]'] \
498
- [--reason "Known partner IP"] \
499
- [--rule-scope this_rule|specific_rules|all_existing|any_rule] \
500
- [--target-rules id1,id2]
501
- ```
502
-
503
- **Condition fields:** `http.target`, `http.method`, `http.url`, `http.user_agent`, `http.request.header.*`, `body.*`, `http.status_code`, `net.peer.ip`, and more.
504
-
505
- **Operators:** `eq`, `neq`, `contains`, `not_contains`, `starts_with`, `ends_with`, `regex`, `in`, `not_in`, `exists`, `not_exists`, `gt`, `lt`, `gte`, `lte`.
506
-
507
- **Match modes:** `all` (AND logic), `any` (OR logic).
508
-
509
- **Rule scopes:** `this_rule` (single alert rule), `specific_rules` (comma-separated IDs via `--target-rules`), `all_existing` (all current rules), `any_rule` (all current and future rules).
510
-
511
- **Safe-value presets:** `standard` or `strict`. These auto-generate conditions that whitelist common safe patterns for paths, query strings, user-agents, and headers.
512
-
513
- ---
514
-
515
- ### Instances
516
-
517
- ```bash
518
- securenow instances # list ClickHouse instances
519
- securenow instances list
520
- securenow instances test <id> # test connection
521
- ```
522
-
523
- ---
524
-
525
- ### Telemetry — Emit Logs and Spans From the Shell
526
-
527
- Mirrors the SDK's `getLogger()` and tracing APIs. Useful for cron jobs, shell scripts, and CI pipelines that need to push events into SecureNow without booting the full OTel SDK.
528
-
529
- ```bash
530
- # Send a structured log record to the OTLP collector
531
- securenow log send "Deployment completed" --level info --attrs version=1.2.3,service=api
532
- securenow log send "Backup failed" --level error --attrs host=db-01
533
-
534
- # Emit a test span to verify the collector accepts OTLP traffic
535
- securenow test-span
536
- securenow test-span "ci.smoke-test" # custom span name
537
- ```
538
-
539
- Both commands use the default SecureNow ingestion gateway plus optional advanced `config.otel.*` overrides from `.securenow/runtime.json` or legacy runtime credentials, and return non-zero on HTTP errors so CI/cron can detect failures.
540
-
274
+ securenow alerts # list alert rules (default)
275
+ securenow alerts rules # list alert rules (columns: Status, Applications, Schedule)
276
+ securenow alerts rules validate \ # dry-run a candidate query BEFORE creating any rule
277
+ --sql @rule.sql --app <key> # no rule id needed — auto-hosts on an existing (system) rule
278
+ securenow alerts rules create \ # create a custom detection rule from inline SQL
279
+ --name "Auth: magic-link brute force" \
280
+ --sql @rule.sql \ # SQL, @file, or - for stdin; scope apps with __USER_APP_KEYS__
281
+ --apps key1,key2 \ # or --applications-all
282
+ --severity high --schedule "*/15 * * * *" \
283
+ --nlp "single IP flooding /api/auth/signin or /api/auth/callback"
284
+ # create auto dry-runs + rolls back (deletes) on query failure; --no-validate to skip
285
+ securenow alerts rules show <id> # one rule; JSON: --json
286
+ securenow alerts rules set-sql <id> --sql @new.sql # replace a CUSTOM rule's SQL in place (alias: update <id> --sql)
287
+ securenow alerts rules delete <id> --yes # delete a custom rule (system rules: disable instead)
288
+ securenow alerts rules update <id> --applications-all # all current & future apps
289
+ securenow alerts rules update <id> --apps key1,key2 # explicit app keys only
290
+ securenow alerts rules test <id> --mode dry_run --wait # validate an existing rule's query
291
+ securenow alerts rules dry-run-query <id> --sql @candidate.sql --app <key> --wait # candidate test against a specific host rule
292
+ securenow alerts rules tune-query <id> --sql @candidate.sql --reason "Preserve exploit detector, remove benign broad match" --apply-globally --yes
293
+ securenow alerts rules exclusions <id> list # embedded rule exclusions
294
+ securenow alerts channels # list alert channels (Slack, email, etc.)
295
+ securenow alerts history [--limit N] # past triggered alerts
296
+ ```
297
+
298
+ **Authoring loop that won't strand a broken rule:** `validate --sql @rule.sql --app <key>`
299
+ (dry-run before anything exists) → `create …` (which itself dry-runs and auto-rolls-back on
300
+ failure) → if you later need to fix it, `set-sql <id> --sql @rule.sql` (custom rules) or
301
+ `delete <id>`. Detection `.sql` files may start with `--`/`/* */` comments. Custom-rule SQL is
302
+ editable; **system**-rule SQL changes go through `tune-query … --apply-globally`. Pick the
303
+ right tenant-scope column per table: logs (`signoz_logs.distributed_logs_v2`) use
304
+ `resources_string['service.name'] IN (__USER_APP_KEYS__)`, traces
305
+ (`signoz_traces.distributed_signoz_index_v3`) use `` `resource_string_service$$name` IN (__USER_APP_KEYS__) ``.
306
+
307
+ `alerts rules create` flags: `--name` (required); one of `--sql <sql|@file|->` or `--query-mapping-id <id>`; one of `--apps k1,k2` or `--applications-all`; optional `--description`, `--nlp` (plain-English intent), `--category`, `--severity critical|high|medium|low`, `--schedule <cron>` (default `*/15 * * * *`), `--throttle-minutes N` / `--no-throttle`, `--execution-mode scheduled|instant|hybrid`, `--channel id1,id2` (defaults to your in-app SecureNow channel). Detection SQL must scope app keys via the `__USER_APP_KEYS__` placeholder and select an `ip` column for per-IP aggregation/remediation. Requires `alerts:write`.
308
+
309
+ MCP parity for noisy alert-rule reviews:
310
+
311
+ - `securenow_alert_rule_get`
312
+ - `securenow_alert_rule_candidate_test` dry-runs a full candidate SQL query without saving it.
313
+ - `securenow_alert_rule_test_result` polls the dry-run.
314
+ - `securenow_alert_rule_query_update` updates the shared public query mapping behind a system rule for all customer copies. It is admin-only, requires `confirm:true`, `applyGlobally:true`, `reason`, and SQL that keeps `__USER_APP_KEYS__` tenant scoping.
315
+ - `securenow_alert_rule_instant_update` patches Instant rule conditions/config with stale-write guards. Fetch the rule first, pass `expectedRuleVersion` plus `expectedCurrentInstantHash`, use operations such as `remove_condition` / `add_condition` / `update_condition`, and set `applyGlobally:true` for system rules. The API runs seeded before/after checks and returns benign samples removed plus attack samples still matching. If global tuning is denied, it returns a structured admin handoff with the exact patch and missing permission.
316
+ - `securenow_alert_rule_exclusion_add` remains the last-resort customer-specific path; it supports restrictive conditions plus `matchMode` and should not be used to hide a generic system-rule bug.
317
+
318
+ For system-rule tuning, dry-run the candidate SQL first for scheduled rules, or use `dryRun:true` on `securenow_alert_rule_instant_update` for Instant rules. Save only when the guard preserves attack detection. Good guards add exact exploit tokens, dangerous schemes, matched subdetectors, sensitive path/status evidence, malicious user agents, or repeat thresholds; bad guards simply suppress a noisy path.
319
+
320
+ ---
321
+
322
+ ### IP Intelligence
323
+
324
+ ```bash
325
+ securenow ip <ip-address> # lookup (geo, ASN, threat score, reputation)
326
+ securenow ip lookup <ip-address> # same as above
327
+ securenow ip traces <ip-address> --env production # traces originating from this IP
328
+ ```
329
+
330
+ ### Forensics — Natural Language Security Queries
331
+
332
+ ```bash
333
+ securenow forensics "show me all SQL injection attempts in the last 24h" --env production
334
+ securenow forensics query "top 10 IPs by blocked requests" --app my-app --env production
335
+ securenow forensics chat --app my-app --env production # interactive forensics chat session
336
+ securenow forensics library # view saved/template queries
337
+ ```
338
+
339
+ ---
340
+
341
+ ### Firewall
342
+
343
+ ```bash
344
+ securenow firewall # show status (default)
345
+ securenow firewall status --app <key> --env production # app/env toggle, sync time, blocked count
346
+ securenow firewall test-ip <ip> --app <key> --env local # check if IP would be blocked
347
+ ```
348
+
349
+ **Zero-config setup:** running `securenow app connect` enables the selected app's firewall toggle, auto-mints a runtime API key (scoped `traces:write + logs:write + firewall:read + blocklist:read + allowlist:read`), and writes it to `.securenow/runtime.json` after the app is selected. No `SECURENOW_API_KEY` env var needed. If the user already has a key, `securenow api-key set snk_live_...` achieves the same thing; if they only have admin auth, `securenow api-key create` mints and saves a fresh runtime key. See [the landing firewall page](https://securenow.ai/firewall) for an overview.
350
+
351
+ ### Blocklist — Block Malicious IPs
352
+
353
+ ```bash
354
+ securenow blocklist # list blocked IPs
355
+ securenow blocklist list
356
+ securenow blocklist add <ip> --app <key> --env production --reason "Brute force"
357
+ securenow blocklist add <ip> --route /admin* --mode prefix --method ALL --reason "Admin probing"
358
+ securenow blocklist unblock <id> --reason "False alarm after review"
359
+ securenow blocklist remove <id> # compatibility alias for unblock
360
+ securenow blocklist list --status removed # audit retained unblocks
361
+ securenow blocklist stats # block counts, top reasons
362
+ ```
363
+
364
+ Scoped blocks use the same model as rate limits: `--route`/`--path`/`--pattern`
365
+ sets `pathPattern`, `--mode`/`--path-mode` chooses `prefix`, `exact`, or
366
+ `regex`, and `--method` limits enforcement to one HTTP method or `ALL`.
367
+
368
+ Unblock stops firewall enforcement but preserves the block report, history, and
369
+ unblock audit fields. Reblocking the same IP later creates a fresh active block
370
+ without erasing the previous investigation trail.
371
+
372
+ MCP exposes legacy pending-block cleanup separately from current Requires Human
373
+ work:
374
+
375
+ - `securenow_blocklist_unblock`
376
+ - `securenow_blocklist_remove` (compatibility alias for unblock)
377
+ - `securenow_blocklist_pending_list`
378
+ - `securenow_blocklist_pending_approve`
379
+ - `securenow_blocklist_pending_reject`
380
+ - `securenow_blocklist_pending_bulk_approve`
381
+ - `securenow_blocklist_pending_bulk_reject`
382
+ - prompt: `cleanup_legacy_pending_blocks`
383
+
384
+ ### Rate Limits - Soft Remediation
385
+
386
+ ```bash
387
+ securenow ratelimit list --env production
388
+ securenow ratelimit add 203.0.113.42 --route /api/login --limit 2 --window 1m --duration 24h
389
+ securenow ratelimit parse "rate limit 203.0.113.42 on POST /api/login to 2 attempts per minute"
390
+ securenow ratelimit from-text "rate limit /api/login for this IP to 2 attempts per minute for 24h" --yes
391
+ securenow ratelimit test 203.0.113.42 --path /api/login --method POST
392
+ ```
393
+
394
+ MCP parity:
395
+
396
+ - `securenow_rate_limit_parse`
397
+ - `securenow_rate_limit_create_from_text`
398
+
399
+ ### Automation Rules
400
+
401
+ ```bash
402
+ securenow automation # list blocklist automation rules
403
+ securenow automation defaults --yes # ensure built-in default risk-score rules
404
+ securenow automation show <id>
405
+ securenow automation dry-run <id> --limit 500
406
+ securenow automation execute <id> --yes
407
+ ```
408
+
409
+ Built-in default automation is enabled by default for all apps/environments and
410
+ uses the canonical `riskScore`: 95-100 blocks for 7 days, 90-94 blocks for 72h,
411
+ 85-89 blocks for 24h, and scores below 85 stay in investigation/review unless
412
+ the customer adds a stricter custom rule. Raw SecureNow IPDB confidence remains
413
+ supporting evidence, not the primary automation score.
414
+
415
+ ### Allowlist — Restrict to Known IPs
416
+
417
+ Dangerous production mode: IP Allowlist is deny-by-default. Once any active
418
+ allowlist entry exists for an app/environment, only listed IPs can reach it and
419
+ all other IPs are blocked. Do not use allowlist to mark an IP trusted, suppress
420
+ false positives, or clean up investigations. Use `securenow trusted add` for
421
+ known-safe monitors, office/VPN traffic, or trusted bypass cases.
422
+
423
+ ```bash
424
+ securenow allowlist # list allowed IPs
425
+ securenow allowlist list
426
+ securenow allowlist add <ip> --app <key> --env local --label "Office" --reason "Corporate VPN"
427
+ securenow allowlist remove <id>
428
+ securenow allowlist stats
429
+ ```
430
+
431
+ ### Trusted IPs
432
+
433
+ Trusted IPs are the safe bypass/suppression mechanism for known infrastructure
434
+ and do not enable deny-by-default allowlist mode.
435
+
436
+ ```bash
437
+ securenow trusted # list trusted IPs
438
+ securenow trusted list
439
+ securenow trusted add <ip> [--label "CloudFlare edge"]
440
+ securenow trusted remove <id>
441
+ ```
442
+
443
+ ---
444
+
445
+ ### False Positive Management
446
+
447
+ The `fp` command manages exclusion rules that prevent known-safe traffic from triggering security alerts.
448
+
449
+ ```bash
450
+ securenow fp # list all exclusion rules
451
+ securenow fp list
452
+ securenow fp show <id> # rule details
453
+ securenow fp delete <id> [--yes]
454
+
455
+ # Create exclusion rules
456
+ securenow fp create \
457
+ --conditions '[{"field":"path","operator":"starts_with","value":"/api/health"}]' \
458
+ --match-mode all \
459
+ --rule-scope any_rule \
460
+ --reason "Health check endpoint"
461
+
462
+ # Shorthand safe-value presets
463
+ securenow fp create \
464
+ --path /api/events \
465
+ --method POST \
466
+ --path-safe standard \
467
+ --ua-safe standard \
468
+ --headers-safe standard \
469
+ --query-keys page,limit \
470
+ --headers-keys host,content-type \
471
+ --reason "Event webhook"
472
+
473
+ # Edit an existing rule
474
+ securenow fp edit <id> [--active true|false] [--conditions '[...]']
475
+
476
+ # Test conditions against a request body
477
+ securenow fp test-body '{"user":"admin"}' --conditions '[{"field":"request_body","operator":"contains","value":"\"user\":\"admin\""}]'
478
+ securenow fp test-body @request.json --conditions '[...]'
479
+
480
+ # Dry-run conditions against the last 3 days of live traces
481
+ securenow fp dry-run --conditions '[{"field":"path","operator":"starts_with","value":"/api/webhook"}]'
482
+
483
+ # AI-generate exclusion conditions from a description
484
+ securenow fp ai-fill --description "Stripe webhook POST to /api/stripe/webhook" \
485
+ --context '{"method":"POST","path":"/api/stripe/webhook"}'
486
+
487
+ # Mark an IP as false positive on a specific notification
488
+ securenow fp mark <notification-id> <ip> \
489
+ [--conditions '[...]'] \
490
+ [--reason "Known partner IP"] \
491
+ [--rule-scope this_rule|specific_rules|all_existing|any_rule] \
492
+ [--target-rules id1,id2]
493
+ ```
494
+
495
+ **Condition shape:** `{"field": ..., "operator": ..., "value": ...}` (the key is `operator`, not `op`).
496
+
497
+ **Condition fields:** `path`, `method`, `user_agent`, `status_code`, `request_body`, `request_headers`.
498
+
499
+ **Operators:** `equals`, `not_equals`, `contains`, `not_contains`, `starts_with`, `ends_with`, `regex`, `in`, `not_in`, plus structural checks — `path_safe_values`, `query_safe_values`, `query_has_only_keys`, `ua_safe_values`, `headers_safe_values`, `headers_has_only_keys`, `body_safe_values`, `body_is_format`, `body_has_only_fields`, `json_has_only_keys`, `json_safe_values`, `json_valid`, `json_max_depth`, `json_schema_match`. Prefer the `*_safe_values` checks over `contains`: they only exclude a request whose value is clean.
500
+
501
+ **Match modes:** `all` (AND logic), `any` (OR logic).
502
+
503
+ **Rule scopes:** `this_rule` (single alert rule — only via `fp mark`; for a rule-only exclusion without a notification use `securenow alerts rules exclusions <rule-id> add --conditions '[...]'`), `specific_rules` (comma-separated IDs via `--target-rules`), `all_existing` (all current rules), `any_rule` (all current and future rules; the `fp create` default).
504
+
505
+ **Safe-value presets:** `standard` or `strict`. These auto-generate conditions that whitelist common safe patterns for paths, query strings, user-agents, and headers.
506
+
507
+ ---
508
+
509
+ ### Instances
510
+
511
+ ```bash
512
+ securenow instances # list ClickHouse instances
513
+ securenow instances list
514
+ securenow instances test <id> # test connection
515
+ ```
516
+
517
+ ---
518
+
519
+ ### Telemetry — Emit Logs and Spans From the Shell
520
+
521
+ Mirrors the SDK's `getLogger()` and tracing APIs. Useful for cron jobs, shell scripts, and CI pipelines that need to push events into SecureNow without booting the full OTel SDK.
522
+
523
+ ```bash
524
+ # Send a structured log record to the OTLP collector
525
+ securenow log send "Deployment completed" --level info --attrs version=1.2.3,service=api
526
+ securenow log send "Backup failed" --level error --attrs host=db-01
527
+
528
+ # Emit a test span to verify the collector accepts OTLP traffic
529
+ securenow test-span
530
+ securenow test-span "ci.smoke-test" # custom span name
531
+ ```
532
+
533
+ Both commands use the default SecureNow ingestion gateway plus optional advanced `config.otel.*` overrides from `.securenow/runtime.json` or legacy runtime credentials, and return non-zero on HTTP errors so CI/cron can detect failures.
534
+
541
535
  ### Utilities — Redaction, CIDR, Diagnostics
542
536
 
543
- The `redact` command also hides OTP credentials named `code`, `oneTimeCode`, `verificationCode`, and `passcode` (case/separator variants included), while preserving `status_code` and `error_code`. SDK capture uses the same defaults.
544
-
545
- These mirror the SDK exports (`redactSensitiveData`, `createMatcher`, `parseCidr`) so agents can validate behavior without writing Node.
546
-
547
- ```bash
548
- # Redact sensitive fields (password, token, card, ssn, etc.)
549
- securenow redact '{"user":"alice","password":"s3cret","card":"4242"}'
550
- securenow redact @request.json --fields internal_id,sessionHash
551
-
552
- # CIDR operations — match an IP against a list, or parse a range
553
- securenow cidr match 10.0.0.5 10.0.0.0/24,192.168.0.0/16
554
- securenow cidr parse 10.0.0.0/24 # network, broadcast, mask, size
555
-
556
- # Show resolved config (service name, endpoints, credentials, firewall layers)
557
- securenow env # human-readable
558
- securenow env --json # pipe to jq
559
-
560
- # End-to-end diagnostic: probe OTLP + API endpoints, check config
561
- securenow doctor # exits 0 if healthy, 1 otherwise
562
- securenow doctor --json
563
- ```
564
-
565
- The `redact` command accepts a JSON string or `@path/to/file.json` and layers your `--fields` flag on top of `DEFAULT_SENSITIVE_FIELDS`. Exit code from `cidr match` is `0` if the IP matches the list, `2` otherwise — scriptable.
566
-
567
- ---
568
-
569
- ## Workflow Examples for Agentic AI
570
-
571
- ### Investigate a Security Alert
572
-
573
- ```bash
574
- securenow notifications list --limit 5 --json
575
- # IMPORTANT: parse the ipInvestigations array for each notification — see statuses below
576
- securenow ip <attacker-ip> --json
577
- securenow ip traces <attacker-ip> --json
578
- securenow traces show <trace-id> --json
579
- securenow traces analyze <trace-id> --json
580
- # Decision: block the IP
581
- securenow blocklist add <attacker-ip> --reason "Automated: SQL injection detected"
582
- ```
583
-
584
- #### Notification IP Investigation Statuses
585
-
586
- Each notification contains an `ipInvestigations` array. **Every IP has its own `status` field** that you MUST check before taking action or raising flags. Do not rely only on top-level notification fields — always cross-reference each IP's individual investigation status.
587
-
588
- | Status | Meaning | Action |
589
- |--------|---------|--------|
590
- | `open` | Still needs review — no determination yet | Investigate: run `securenow ip <ip>`, check traces, decide to block or dismiss |
591
- | `false_positive` | Trusted/dismissed by exclusion rule, verified bot, or trusted IP list | **Skip** — greyed out in UI, no action needed |
592
- | `blocked` | Already on the user's blocklist | **Skip** — already handled |
593
- | `clean` | Pipeline analyzed and cleared as benign | **Skip** — verified safe |
594
-
595
- **Critical workflow rule:** When investigating notifications, iterate `ipInvestigations[]` and **only flag or act on IPs with `status: "open"`**. IPs marked `false_positive`, `blocked`, or `clean` have already been triaged — do not re-flag them.
596
-
597
- ### Triage and Suppress a False Positive
598
-
599
- ```bash
600
- securenow notifications list --json
601
- # Identify a false positive notification
602
- securenow fp ai-fill --description "Stripe webhook calls to /api/stripe/webhook"
603
- # Review the suggested conditions, then create the rule
604
- securenow fp create --conditions '<ai-suggested-conditions>' --rule-scope any_rule --reason "Stripe webhook"
605
- # Or directly mark the notification's IP as FP
606
- securenow fp mark <notification-id> <ip> --rule-scope this_rule --reason "Known Stripe IP"
607
- ```
608
-
609
- ### Onboard a New Application
610
-
611
- ```bash
612
- securenow apps create my-new-app --hosts api.example.com,app.example.com
613
- securenow apps default my-new-app
614
- securenow login
615
- securenow init
616
- securenow run src/index.js
617
- securenow status --json
618
- ```
619
-
620
- ### Security Posture Check
621
-
622
- ```bash
623
- securenow status --json
624
- securenow firewall status --json
625
- securenow blocklist stats --json
626
- securenow api-map stats --json
627
- securenow forensics "summarize all attacks in the last 7 days"
628
- ```
629
-
630
- ### Discover Attack Surface
631
-
632
- ```bash
633
- securenow apps discover --domain example.com
634
- securenow apps scan --yes
635
- securenow api-map list --json
636
- securenow api-map stats --json
637
- ```
638
-
639
- ---
640
-
641
- ## Output Parsing
642
-
643
- All commands support `--json` for structured output. When piping to other tools or parsing programmatically, always use `--json`. Table output is the default for human readability.
644
-
645
- ## Error Handling
646
-
647
- | Exit code / Error | Meaning | Recovery |
648
- |------------------|---------|----------|
649
- | `Session expired` | Admin JWT expired | `securenow admin login` (or `admin login --global` for shared admin auth) |
650
- | `Not logged in` | No admin token found | `securenow admin login`; runtime `.securenow/runtime.json` is unrelated |
651
- | `Access denied (403)` | Insufficient plan or permissions | Upgrade plan or check user role |
652
- | `Cannot connect` | API unreachable | Check `securenow config get apiUrl` or network |
653
- | `Unknown command` | Typo or unrecognized command | `securenow help` |
654
-
655
- SecureNow-specific environment overrides are intentionally unsupported for troubleshooting; use explicit CLI config files and normal terminal logs.
537
+ The `redact` command also hides OTP credentials named `code`, `oneTimeCode`, `verificationCode`, and `passcode` (case/separator variants included), while preserving `status_code` and `error_code`. SDK capture uses the same defaults.
538
+
539
+ These mirror the SDK exports (`redactSensitiveData`, `createMatcher`, `parseCidr`) so agents can validate behavior without writing Node.
540
+
541
+ ```bash
542
+ # Redact sensitive fields (password, token, card, ssn, etc.)
543
+ securenow redact '{"user":"alice","password":"s3cret","card":"4242"}'
544
+ securenow redact @request.json --fields internal_id,sessionHash
545
+
546
+ # CIDR operations — match an IP against a list, or parse a range
547
+ securenow cidr match 10.0.0.5 10.0.0.0/24,192.168.0.0/16
548
+ securenow cidr parse 10.0.0.0/24 # network, broadcast, mask, size
549
+
550
+ # Show resolved config (service name, endpoints, credentials, firewall layers)
551
+ securenow env # human-readable
552
+ securenow env --json # pipe to jq
553
+
554
+ # End-to-end diagnostic: probe OTLP + API endpoints, check config
555
+ securenow doctor # exits 0 if healthy, 1 otherwise
556
+ securenow doctor --json
557
+ ```
558
+
559
+ The `redact` command accepts a JSON string or `@path/to/file.json` and layers your `--fields` flag on top of `DEFAULT_SENSITIVE_FIELDS`. Exit code from `cidr match` is `0` if the IP matches the list, `2` otherwise — scriptable.
560
+
561
+ ---
562
+
563
+ ## Workflow Examples for Agentic AI
564
+
565
+ ### Investigate a Security Alert
566
+
567
+ ```bash
568
+ securenow notifications list --limit 5 --json
569
+ # IMPORTANT: parse the ipInvestigations array for each notification — see statuses below
570
+ securenow ip <attacker-ip> --json
571
+ securenow ip traces <attacker-ip> --json
572
+ securenow traces show <trace-id> --json
573
+ securenow traces analyze <trace-id> --json
574
+ # Decision: block the IP
575
+ securenow blocklist add <attacker-ip> --reason "Automated: SQL injection detected"
576
+ ```
577
+
578
+ #### Notification IP Investigation Statuses
579
+
580
+ Each notification contains an `ipInvestigations` array. **Every IP has its own `status` field** that you MUST check before taking action or raising flags. Do not rely only on top-level notification fields — always cross-reference each IP's individual investigation status.
581
+
582
+ | Status | Meaning | Action |
583
+ |--------|---------|--------|
584
+ | `open` | Still needs review — no determination yet | Investigate: run `securenow ip <ip>`, check traces, decide to block or dismiss |
585
+ | `false_positive` | Trusted/dismissed by exclusion rule, verified bot, or trusted IP list | **Skip** — greyed out in UI, no action needed |
586
+ | `blocked` | Already on the user's blocklist | **Skip** — already handled |
587
+ | `clean` | Pipeline analyzed and cleared as benign | **Skip** — verified safe |
588
+
589
+ **Critical workflow rule:** When investigating notifications, iterate `ipInvestigations[]` and **only flag or act on IPs with `status: "open"`**. IPs marked `false_positive`, `blocked`, or `clean` have already been triaged — do not re-flag them.
590
+
591
+ ### Triage and Suppress a False Positive
592
+
593
+ ```bash
594
+ securenow notifications list --json
595
+ # Identify a false positive notification
596
+ securenow fp ai-fill --description "Stripe webhook calls to /api/stripe/webhook"
597
+ # Review the suggested conditions, then create the rule
598
+ securenow fp create --conditions '<ai-suggested-conditions>' --rule-scope any_rule --reason "Stripe webhook"
599
+ # Or directly mark the notification's IP as FP
600
+ securenow fp mark <notification-id> <ip> --rule-scope this_rule --reason "Known Stripe IP"
601
+ ```
602
+
603
+ ### Onboard a New Application
604
+
605
+ ```bash
606
+ securenow apps create my-new-app --hosts api.example.com,app.example.com
607
+ securenow apps default my-new-app
608
+ securenow login
609
+ securenow init
610
+ securenow run src/index.js
611
+ securenow status --json
612
+ ```
613
+
614
+ ### Security Posture Check
615
+
616
+ ```bash
617
+ securenow status --json
618
+ securenow firewall status --json
619
+ securenow blocklist stats --json
620
+ securenow forensics "summarize all attacks in the last 7 days"
621
+ ```
622
+
623
+ ### Discover Attack Surface
624
+
625
+ ```bash
626
+ securenow apps discover --domain example.com
627
+ securenow apps scan --yes
628
+ ```
629
+
630
+ ---
631
+
632
+ ## Output Parsing
633
+
634
+ All commands support `--json` for structured output. When piping to other tools or parsing programmatically, always use `--json`. Table output is the default for human readability.
635
+
636
+ ## Error Handling
637
+
638
+ | Exit code / Error | Meaning | Recovery |
639
+ |------------------|---------|----------|
640
+ | `Session expired` | Admin JWT expired | `securenow admin login` (or `admin login --global` for shared admin auth) |
641
+ | `Not logged in` | No admin token found | `securenow admin login`; runtime `.securenow/runtime.json` is unrelated |
642
+ | `Access denied (403)` | Insufficient plan or permissions | Upgrade plan or check user role |
643
+ | `Cannot connect` | API unreachable | Check `securenow config get apiUrl` or network |
644
+ | `Unknown command` | Typo or unrecognized command | `securenow help` |
645
+
646
+ SecureNow-specific environment overrides are intentionally unsupported for troubleshooting; use explicit CLI config files and normal terminal logs.