securenow 7.4.0 → 7.5.1
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/NPM_README.md +40 -24
- package/README.md +22 -6
- package/SKILL-API.md +19 -16
- package/SKILL-CLI.md +16 -5
- package/cli/diagnostics.js +21 -2
- package/cli/init.js +94 -51
- package/cli/ui.js +22 -12
- package/cli.js +14 -9
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +21 -18
- package/docs/API-KEYS-GUIDE.md +2 -2
- package/docs/ENVIRONMENT-VARIABLES.md +10 -9
- package/docs/FIREWALL-GUIDE.md +5 -4
- package/docs/MCP-GUIDE.md +50 -0
- package/mcp/catalog.js +770 -0
- package/mcp/server.js +238 -0
- package/nextjs-auto-capture.d.ts +1 -1
- package/package.json +10 -2
package/NPM_README.md
CHANGED
|
@@ -23,6 +23,7 @@ OpenTelemetry instrumentation library for Node.js, Next.js, and Nuxt application
|
|
|
23
23
|
- [Installation](#installation)
|
|
24
24
|
- [Quick Start](#quick-start)
|
|
25
25
|
- [CLI -- Command Line Interface](#cli--command-line-interface)
|
|
26
|
+
- [MCP for Codex and Claude](#mcp-for-codex-and-claude)
|
|
26
27
|
- [Framework-Specific Setup](#framework-specific-setup)
|
|
27
28
|
- [Express.js](#expressjs)
|
|
28
29
|
- [Next.js](#nextjs)
|
|
@@ -59,13 +60,13 @@ yarn add securenow
|
|
|
59
60
|
|
|
60
61
|
### 1. Automatic Setup (Recommended)
|
|
61
62
|
|
|
62
|
-
Run login — it's a browser flow that picks an app and
|
|
63
|
+
Run login — it's a browser flow that picks or creates an app and connects the firewall automatically:
|
|
63
64
|
|
|
64
65
|
```bash
|
|
65
66
|
npx securenow login
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
During the browser step
|
|
69
|
+
During the browser step, the dashboard enables the selected app's firewall toggle, mints an API key (scoped `firewall:read + blocklist:read + allowlist:read`), and the CLI writes it into `.securenow/credentials.json`. Traces, logs, POST body capture, multipart metadata capture, and firewall protection are enabled by default. No env vars, no copy-pasting keys.
|
|
69
70
|
|
|
70
71
|
For framework scaffolding (Next.js `instrumentation.ts`, etc.) use:
|
|
71
72
|
|
|
@@ -153,9 +154,8 @@ The `securenow` CLI gives you full access to the SecureNow platform from the ter
|
|
|
153
154
|
|
|
154
155
|
```bash
|
|
155
156
|
# Log in (opens browser for OAuth + app picker)
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
# in .securenow/credentials.json automatically (no env var needed).
|
|
157
|
+
# The browser flow mints and stores the firewall API key automatically in
|
|
158
|
+
# .securenow/credentials.json (no env var needed).
|
|
159
159
|
npx securenow login
|
|
160
160
|
|
|
161
161
|
# Or use a token for CI/headless environments
|
|
@@ -185,6 +185,21 @@ npx securenow init --key snk_live_abc123...
|
|
|
185
185
|
|
|
186
186
|
For Next.js projects, `init` creates `instrumentation.ts` (or `.js` if no TypeScript) and tells you how to update `next.config.js` with `withSecureNow()`. For Nuxt, it suggests adding `securenow/nuxt` to your modules. For Express/Node, it shows the `-r securenow/register` flag.
|
|
187
187
|
|
|
188
|
+
### MCP for Codex and Claude
|
|
189
|
+
|
|
190
|
+
SecureNow includes a local stdio MCP server that uses the same credentials and API client as the CLI:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npx securenow login
|
|
194
|
+
codex mcp add securenow -- npx securenow mcp
|
|
195
|
+
# or
|
|
196
|
+
npx -p securenow securenow-mcp
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The MCP surface exposes tools for applications, traces, logs, firewall, IP intelligence, forensics, notifications, blocklist, allowlist, trusted IPs, and docs-backed prompts/resources. Write actions require `confirm:true` and a reason.
|
|
200
|
+
|
|
201
|
+
For hosted clients, SecureNow can expose the same surface at `https://api.securenow.ai/mcp`. The hosted endpoint uses the same API authentication and scope checks as the rest of SecureNow.
|
|
202
|
+
|
|
188
203
|
### Managing Applications
|
|
189
204
|
|
|
190
205
|
```bash
|
|
@@ -626,7 +641,7 @@ fastify.listen({ port: 3000 }, (err) => {
|
|
|
626
641
|
});
|
|
627
642
|
```
|
|
628
643
|
|
|
629
|
-
> **
|
|
644
|
+
> **Default:** Traces, logs, POST body capture, multipart metadata capture, and firewall protection are on. If a specific Fastify version or plugin stack reports request-stream conflicts, set `SECURENOW_CAPTURE_BODY=0` as a local override.
|
|
630
645
|
|
|
631
646
|
---
|
|
632
647
|
|
|
@@ -749,7 +764,7 @@ const init = async () => {
|
|
|
749
764
|
init().catch((err) => { console.error(err); process.exit(1); });
|
|
750
765
|
```
|
|
751
766
|
|
|
752
|
-
> **
|
|
767
|
+
> **Default:** Traces, logs, POST body capture, multipart metadata capture, and firewall protection are on. If a specific Hapi version or payload plugin reports request-stream conflicts, set `SECURENOW_CAPTURE_BODY=0` as a local override.
|
|
753
768
|
|
|
754
769
|
---
|
|
755
770
|
|
|
@@ -893,7 +908,7 @@ serve({ fetch: app.fetch, port: 3000 }, () => console.log('Hono running on port
|
|
|
893
908
|
node -r securenow/register app.mjs
|
|
894
909
|
```
|
|
895
910
|
|
|
896
|
-
> **
|
|
911
|
+
> **Default:** Traces, logs, POST body capture, multipart metadata capture, and firewall protection are on. For Hono ESM apps, keep using the `node -r securenow/register app.mjs` preload instead of adding `require('securenow/register')` inside `.mjs` files.
|
|
897
912
|
|
|
898
913
|
---
|
|
899
914
|
|
|
@@ -1079,14 +1094,14 @@ The Nuxt server plugin (v5.13.0+) initializes the firewall independently from Op
|
|
|
1079
1094
|
| Framework | Traces | Logs | Body Capture | Firewall | Notes |
|
|
1080
1095
|
|-----------|--------|------|--------------|----------|-------|
|
|
1081
1096
|
| Express | Yes | Yes | Yes | Yes | Fully compatible |
|
|
1082
|
-
| Fastify | Yes | Yes |
|
|
1097
|
+
| Fastify | Yes | Yes | Yes | Yes | Default on; use `SECURENOW_CAPTURE_BODY=0` only for local stream conflicts |
|
|
1083
1098
|
| Koa | Yes | Yes | Yes | Yes | Needs `koa-bodyparser` |
|
|
1084
1099
|
| NestJS | Yes | Yes | Yes | Yes | Use `-r ts-node/register` |
|
|
1085
|
-
| Hapi | Yes | Yes |
|
|
1100
|
+
| Hapi | Yes | Yes | Yes | Yes | Default on; use `SECURENOW_CAPTURE_BODY=0` only for local stream conflicts |
|
|
1086
1101
|
| h3 | Yes | Yes | Yes | Yes | Uses `toNodeListener()` |
|
|
1087
1102
|
| Polka | Yes | Yes | Yes | Yes | Needs manual body parser |
|
|
1088
1103
|
| Micro/HTTP | Yes | Yes | Yes | Yes | Full control |
|
|
1089
|
-
| Hono | Yes | Yes |
|
|
1104
|
+
| Hono | Yes | Yes | Yes | Yes | Use ESM `-r` preload |
|
|
1090
1105
|
| Feathers | Yes | Yes | Yes | Yes | Uses Express transport |
|
|
1091
1106
|
| Next.js | Yes | Yes | Yes | Yes | Use `instrumentation.ts` + `withSecureNow()` |
|
|
1092
1107
|
| Nuxt 3 | Yes | Yes | Yes | Yes | Use `securenow/nuxt` module |
|
|
@@ -1097,12 +1112,12 @@ The Nuxt server plugin (v5.13.0+) initializes the firewall independently from Op
|
|
|
1097
1112
|
|
|
1098
1113
|
SecureNow can automatically block IPs from your blocklist at the application layer. No code changes -- just provide an API key (via `securenow login`, the `api-key` CLI, or env var) and the firewall activates.
|
|
1099
1114
|
|
|
1100
|
-
###
|
|
1115
|
+
### Firewall Is Enabled by Default
|
|
1101
1116
|
|
|
1102
1117
|
Pick whichever fits your environment:
|
|
1103
1118
|
|
|
1104
1119
|
```bash
|
|
1105
|
-
# (a) Zero-config (v7.
|
|
1120
|
+
# (a) Zero-config (v7.4+): login picks/creates an app and connects the firewall.
|
|
1106
1121
|
# Key is minted and written to .securenow/credentials.json automatically.
|
|
1107
1122
|
npx securenow login
|
|
1108
1123
|
|
|
@@ -1237,16 +1252,16 @@ See the [Firewall Guide](./docs/FIREWALL-GUIDE.md) for the full reference.
|
|
|
1237
1252
|
|
|
1238
1253
|
| Variable | Description | Default |
|
|
1239
1254
|
|----------|-------------|---------|
|
|
1240
|
-
| `SECURENOW_LOGGING_ENABLED` | Enable automatic logging to OTLP backend. Set to `
|
|
1255
|
+
| `SECURENOW_LOGGING_ENABLED` | Enable automatic logging to OTLP backend. Set to `0` to disable. | `1` |
|
|
1241
1256
|
|
|
1242
1257
|
#### Request Body Capture
|
|
1243
1258
|
|
|
1244
1259
|
| Variable | Description | Default |
|
|
1245
1260
|
|----------|-------------|---------|
|
|
1246
|
-
| `SECURENOW_CAPTURE_BODY` |
|
|
1261
|
+
| `SECURENOW_CAPTURE_BODY` | Capture request bodies in traces. Set to `0` to disable. | `1` |
|
|
1247
1262
|
| `SECURENOW_MAX_BODY_SIZE` | Maximum body size to capture in bytes. Bodies larger than this are truncated. | `10240` (10KB) |
|
|
1248
1263
|
| `SECURENOW_SENSITIVE_FIELDS` | Comma-separated list of additional field names to redact. | - |
|
|
1249
|
-
| `SECURENOW_CAPTURE_MULTIPART` |
|
|
1264
|
+
| `SECURENOW_CAPTURE_MULTIPART` | Capture multipart/form-data metadata. Streams through the request to extract text field values and file metadata (name, filename, content-type, size) without buffering file content. Set to `0` to disable. | `1` |
|
|
1250
1265
|
|
|
1251
1266
|
**Default sensitive fields (auto-redacted):** `password`, `passwd`, `pwd`, `secret`, `token`, `api_key`, `apikey`, `access_token`, `auth`, `credentials`, `mysql_pwd`, `stripeToken`, `card`, `cardnumber`, `ccv`, `cvc`, `cvv`, `ssn`, `pin`
|
|
1252
1267
|
|
|
@@ -1384,13 +1399,13 @@ node app.js
|
|
|
1384
1399
|
|
|
1385
1400
|
## Request Body Capture
|
|
1386
1401
|
|
|
1387
|
-
SecureNow
|
|
1402
|
+
SecureNow captures HTTP request bodies in traces by default, with sensitive fields automatically redacted. Set `SECURENOW_CAPTURE_BODY=0` only when you need a local opt-out.
|
|
1388
1403
|
|
|
1389
|
-
###
|
|
1404
|
+
### Body Capture Defaults
|
|
1390
1405
|
|
|
1391
1406
|
```bash
|
|
1392
|
-
export SECURENOW_CAPTURE_BODY=1
|
|
1393
1407
|
export SECURENOW_MAX_BODY_SIZE=10240 # 10KB (optional)
|
|
1408
|
+
# export SECURENOW_CAPTURE_BODY=0 # optional opt-out
|
|
1394
1409
|
```
|
|
1395
1410
|
|
|
1396
1411
|
### Supported Content Types
|
|
@@ -1398,11 +1413,11 @@ export SECURENOW_MAX_BODY_SIZE=10240 # 10KB (optional)
|
|
|
1398
1413
|
- `application/json`
|
|
1399
1414
|
- `application/x-www-form-urlencoded`
|
|
1400
1415
|
- `application/graphql`
|
|
1401
|
-
- `multipart/form-data` (
|
|
1416
|
+
- `multipart/form-data` (metadata capture is on unless `SECURENOW_CAPTURE_MULTIPART=0`)
|
|
1402
1417
|
|
|
1403
1418
|
### Multipart Body Capture (v5.8.0+)
|
|
1404
1419
|
|
|
1405
|
-
|
|
1420
|
+
Multipart/form-data metadata capture is enabled by default. Set `SECURENOW_CAPTURE_MULTIPART=0` to disable it. Uses a streaming parser that never buffers file content -- memory stays at ~few KB regardless of upload size.
|
|
1406
1421
|
|
|
1407
1422
|
**What gets captured:**
|
|
1408
1423
|
- **Text fields** -- field name and value (up to 1000 chars), with sensitive fields auto-redacted
|
|
@@ -1731,10 +1746,11 @@ curl http://localhost:4318/v1/logs
|
|
|
1731
1746
|
|
|
1732
1747
|
### Request Body Not Captured
|
|
1733
1748
|
|
|
1734
|
-
**Check 1:
|
|
1749
|
+
**Check 1: Make sure body capture was not explicitly disabled**
|
|
1735
1750
|
|
|
1736
1751
|
```bash
|
|
1737
|
-
|
|
1752
|
+
echo $SECURENOW_CAPTURE_BODY
|
|
1753
|
+
# Should be empty, 1, or true. Remove SECURENOW_CAPTURE_BODY=0 to re-enable defaults.
|
|
1738
1754
|
```
|
|
1739
1755
|
|
|
1740
1756
|
**Check 2: Verify content type**
|
|
@@ -1915,7 +1931,7 @@ const dbLogger = getLogger('database', '1.0.0');
|
|
|
1915
1931
|
const apiLogger = getLogger('api', '1.0.0');
|
|
1916
1932
|
```
|
|
1917
1933
|
|
|
1918
|
-
### 6.
|
|
1934
|
+
### 6. Disable Body Capture Outside Development
|
|
1919
1935
|
|
|
1920
1936
|
```bash
|
|
1921
1937
|
# .env.development
|
package/README.md
CHANGED
|
@@ -12,9 +12,9 @@ Zero-config OpenTelemetry for Node.js, Next.js, and Nuxt — traces, logs, body
|
|
|
12
12
|
# 1. Install
|
|
13
13
|
npm install securenow
|
|
14
14
|
|
|
15
|
-
# 2. Pick (or create) your app in the browser
|
|
16
|
-
# Since v7.
|
|
17
|
-
#
|
|
15
|
+
# 2. Pick (or create) your app in the browser - writes .securenow/ locally.
|
|
16
|
+
# Since v7.4.0, the browser step enables the app firewall and stores
|
|
17
|
+
# a scoped firewall API key in the same file - no env vars.
|
|
18
18
|
npx securenow login
|
|
19
19
|
|
|
20
20
|
# 3. Start your app — one flag is all it takes
|
|
@@ -137,7 +137,7 @@ Resolution order (first non-empty wins):
|
|
|
137
137
|
|
|
138
138
|
```bash
|
|
139
139
|
# Setup
|
|
140
|
-
npx securenow login # browser auth + app picker + firewall
|
|
140
|
+
npx securenow login # browser auth + app picker + firewall enabled by default
|
|
141
141
|
npx securenow login --global # save to ~/.securenow/ instead
|
|
142
142
|
npx securenow login --token <TOKEN> # headless (CI)
|
|
143
143
|
npx securenow init # scaffold Next.js instrumentation files
|
|
@@ -168,6 +168,21 @@ Full reference: run `npx securenow help` or see [CLI Reference](#cli-reference)
|
|
|
168
168
|
|
|
169
169
|
---
|
|
170
170
|
|
|
171
|
+
## MCP for Codex and Claude
|
|
172
|
+
|
|
173
|
+
SecureNow ships a local stdio MCP server for agent clients:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
npx securenow login
|
|
177
|
+
codex mcp add securenow -- npx securenow mcp
|
|
178
|
+
# or run directly:
|
|
179
|
+
npx -p securenow securenow-mcp
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The MCP server reuses the same project-local `.securenow/credentials.json` as the CLI and SDK. It exposes tools for apps, traces, logs, firewall, IP intelligence, forensics, blocklist/allowlist/trusted IPs, plus resources for the bundled SecureNow docs and setup prompts.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
171
186
|
## Environment variables (optional)
|
|
172
187
|
|
|
173
188
|
Only set these if you want to override the zero-config defaults.
|
|
@@ -178,7 +193,7 @@ Only set these if you want to override the zero-config defaults.
|
|
|
178
193
|
| `SECURENOW_INSTANCE` | `https://freetrial.securenow.ai:4318` | OTLP collector endpoint |
|
|
179
194
|
| `SECURENOW_API_KEY` | from credentials file | Enables firewall + collector routing |
|
|
180
195
|
| `SECURENOW_LOGGING_ENABLED` | `1` (on) | Forward `console.*` as OTLP logs. Set to `0` to disable. |
|
|
181
|
-
| `SECURENOW_CAPTURE_BODY` | `1` (on) | Capture JSON / form request bodies. Set to `0` for
|
|
196
|
+
| `SECURENOW_CAPTURE_BODY` | `1` (on) | Capture JSON / form request bodies. Set to `0` only for a local stream conflict. |
|
|
182
197
|
| `SECURENOW_CAPTURE_MULTIPART` | `1` (on) | Capture multipart metadata (not content). |
|
|
183
198
|
| `SECURENOW_MAX_BODY_SIZE` | `10240` | Max bytes captured per body. |
|
|
184
199
|
| `SECURENOW_SENSITIVE_FIELDS` | `password,token,authorization,...` | Extra fields to redact (comma-separated). |
|
|
@@ -218,6 +233,7 @@ HTTP/HTTPS · GraphQL · gRPC · and many more via [@opentelemetry/auto-instrume
|
|
|
218
233
|
### Complete Guides
|
|
219
234
|
- [Firewall](./docs/FIREWALL-GUIDE.md)
|
|
220
235
|
- [API Keys](./docs/API-KEYS-GUIDE.md)
|
|
236
|
+
- [MCP](./docs/MCP-GUIDE.md)
|
|
221
237
|
- [Next.js Complete](./docs/NEXTJS-GUIDE.md)
|
|
222
238
|
- [Nuxt 3 Complete](./docs/NUXT-GUIDE.md)
|
|
223
239
|
- [Logging Complete](./docs/LOGGING-GUIDE.md)
|
|
@@ -244,7 +260,7 @@ After install, the `securenow` CLI is available via `npx securenow` or globally
|
|
|
244
260
|
|
|
245
261
|
| Command | Description |
|
|
246
262
|
|---|---|
|
|
247
|
-
| `securenow login` | Browser auth + pick app
|
|
263
|
+
| `securenow login` | Browser auth + pick app; firewall key is minted automatically (writes ./.securenow/ by default) |
|
|
248
264
|
| `securenow login --global` | Save to ~/.securenow/ instead |
|
|
249
265
|
| `securenow login --token <TOKEN>` | Headless (CI/servers) |
|
|
250
266
|
| `securenow logout` | Clear project-local credentials |
|
package/SKILL-API.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Instrument any Node.js application with OpenTelemetry tracing, structured logging, request body capture, and a multi-layer IP firewall. Supports Express, Fastify, NestJS, Koa, Hapi, Next.js, Nuxt 3, Vite (browser), and raw `http.createServer` — with zero code changes for most setups.
|
|
4
4
|
|
|
5
|
-
**CLI parity:** every capability exposed below (redaction, CIDR matching, log/span emission, firewall preload, config inspection) has an equivalent `securenow` CLI command. See [SKILL-CLI.md](./SKILL-CLI.md) for the terminal surface.
|
|
5
|
+
**CLI parity:** every capability exposed below (redaction, CIDR matching, log/span emission, firewall preload, config inspection) has an equivalent `securenow` CLI command. See [SKILL-CLI.md](./SKILL-CLI.md) for the terminal surface.
|
|
6
|
+
|
|
7
|
+
**MCP parity (v7.5+):** `npx securenow mcp` starts a local stdio MCP server for Codex, Claude, and other MCP clients. It reuses the same `.securenow/credentials.json` file as the CLI/SDK and exposes SecureNow tools, bundled docs resources, and setup prompts to agents.
|
|
6
8
|
|
|
7
9
|
## Installation
|
|
8
10
|
|
|
@@ -46,17 +48,19 @@ npx securenow init --key snk_live_...
|
|
|
46
48
|
|
|
47
49
|
That's it. Traces and logs flow to your OTLP collector. No code changes for Express, Fastify, NestJS, Koa, Hapi, and raw Node.
|
|
48
50
|
|
|
49
|
-
### 3.
|
|
51
|
+
### 3. Firewall Is Enabled by Default
|
|
50
52
|
|
|
51
|
-
Since v7.
|
|
53
|
+
Since v7.4.0, the browser login flow connects the firewall automatically after
|
|
54
|
+
the user picks or creates an app. The firewall key lives in your credentials
|
|
55
|
+
file — no env var required:
|
|
52
56
|
|
|
53
57
|
```bash
|
|
54
|
-
npx securenow login # pick app
|
|
55
|
-
# or, if you already have one:
|
|
56
|
-
npx securenow api-key set snk_live_abc123...
|
|
58
|
+
npx securenow login # pick/create app; firewall key is minted automatically
|
|
59
|
+
# or, if you already have one:
|
|
60
|
+
npx securenow api-key set snk_live_abc123...
|
|
57
61
|
```
|
|
58
62
|
|
|
59
|
-
Both paths write the key to `.securenow/credentials.json` (auto-gitignored) and the firewall activates on next start. Setting `SECURENOW_API_KEY=snk_live_...` in the environment still works and takes precedence.
|
|
63
|
+
Both paths write the key to `.securenow/credentials.json` (auto-gitignored) and the firewall activates on next start. Setting `SECURENOW_API_KEY=snk_live_...` in the environment still works and takes precedence.
|
|
60
64
|
|
|
61
65
|
The firewall syncs your blocklist and enforces it on every request — zero code changes.
|
|
62
66
|
|
|
@@ -263,7 +267,7 @@ Instruments document load, fetch, XMLHttpRequest, and user interactions with bro
|
|
|
263
267
|
|
|
264
268
|
## Firewall — Multi-Layer IP Blocking
|
|
265
269
|
|
|
266
|
-
The firewall auto-activates once an API key is resolvable. Since **v7.
|
|
270
|
+
The firewall auto-activates once an API key is resolvable and the app firewall toggle is on. Since **v7.4.0**, `npx securenow login` enables the selected app firewall and writes the key to `.securenow/credentials.json`; `securenow api-key set` can still write/rotate the key later. The `SECURENOW_API_KEY` env var is optional. Resolution order: env (must start with `snk_live_`) → project `./.securenow/credentials.json` → global `~/.securenow/credentials.json`.
|
|
267
271
|
|
|
268
272
|
```
|
|
269
273
|
Layer 4: Cloud/Edge WAF → blocked at CDN (Cloudflare, AWS WAF, GCP Cloud Armor)
|
|
@@ -275,8 +279,8 @@ Layer 1: HTTP Handler → 403 JSON response (always active)
|
|
|
275
279
|
### Activate
|
|
276
280
|
|
|
277
281
|
```bash
|
|
278
|
-
# Zero-config (recommended) — writes the key to .securenow/credentials.json
|
|
279
|
-
npx securenow login # pick app
|
|
282
|
+
# Zero-config (recommended) — writes the key to .securenow/credentials.json
|
|
283
|
+
npx securenow login # pick/create app; firewall connects automatically
|
|
280
284
|
# or, if you already have a key:
|
|
281
285
|
npx securenow api-key set snk_live_abc123...
|
|
282
286
|
|
|
@@ -478,9 +482,9 @@ securenow redact @request.json --fields internal_id,sessionHash
|
|
|
478
482
|
| Variable | Description | Default |
|
|
479
483
|
|----------|-------------|---------|
|
|
480
484
|
| `SECURENOW_LOGGING_ENABLED` | Enable OTLP log export | `1` |
|
|
481
|
-
| `SECURENOW_CAPTURE_BODY` | Capture HTTP request bodies | `
|
|
485
|
+
| `SECURENOW_CAPTURE_BODY` | Capture HTTP request bodies | `1` |
|
|
482
486
|
| `SECURENOW_MAX_BODY_SIZE` | Max body size in bytes | `10240` |
|
|
483
|
-
| `SECURENOW_CAPTURE_MULTIPART` | Capture multipart/form-data (streaming, metadata only) | `
|
|
487
|
+
| `SECURENOW_CAPTURE_MULTIPART` | Capture multipart/form-data (streaming, metadata only) | `1` |
|
|
484
488
|
| `SECURENOW_SENSITIVE_FIELDS` | Comma-separated extra fields to redact | — |
|
|
485
489
|
| `SECURENOW_DISABLE_INSTRUMENTATIONS` | Comma-separated packages to skip (e.g. `fs,dns`) | — |
|
|
486
490
|
| `SECURENOW_TEST_SPAN` | `1` to emit a test span on startup | `0` |
|
|
@@ -551,16 +555,15 @@ No code changes to the application needed.
|
|
|
551
555
|
|
|
552
556
|
```bash
|
|
553
557
|
npm install securenow
|
|
554
|
-
npx securenow login # pick app
|
|
558
|
+
npx securenow login # pick/create app; firewall key is minted automatically
|
|
555
559
|
```
|
|
556
560
|
|
|
557
|
-
`securenow login` writes session, app, and firewall key to `.securenow/credentials.json` (auto-gitignored). The `init` command still works for manual setup — it creates `instrumentation.ts` and suggests `next.config` changes. Most users only need this `.env.local`:
|
|
561
|
+
`securenow login` enables the selected app's firewall toggle and writes session, app, and firewall key to `.securenow/credentials.json` (auto-gitignored). Traces, logs, request body capture, multipart metadata capture, and firewall enforcement are enabled by default. The `init` command still works for manual setup — it creates `instrumentation.ts` and suggests `next.config` changes. Most users only need this `.env.local`:
|
|
558
562
|
|
|
559
563
|
```
|
|
560
564
|
SECURENOW_APPID=my-nextjs-app
|
|
561
565
|
SECURENOW_INSTANCE=https://your-collector:4318
|
|
562
|
-
|
|
563
|
-
# SECURENOW_API_KEY=snk_live_... (otherwise lives in .securenow/credentials.json)
|
|
566
|
+
# SECURENOW_API_KEY=snk_live_... (otherwise lives in .securenow/credentials.json)
|
|
564
567
|
```
|
|
565
568
|
|
|
566
569
|
### Enable Firewall With Zero Tracing Overhead
|
package/SKILL-CLI.md
CHANGED
|
@@ -13,7 +13,18 @@ npm install securenow
|
|
|
13
13
|
npx securenow <command>
|
|
14
14
|
```
|
|
15
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.
|
|
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 (v7.5+):** 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 reuses `.securenow/credentials.json` and exposes apps, traces, logs, firewall, IP intelligence, forensics, notifications, remediation tools, bundled docs resources, and setup prompts. Write tools require `confirm:true` plus a reason.
|
|
17
28
|
|
|
18
29
|
### Authenticate
|
|
19
30
|
|
|
@@ -24,9 +35,9 @@ securenow login --token <JWT> # headless / CI login (get token from dashboard
|
|
|
24
35
|
securenow whoami # verify session (shows email, app, auth source)
|
|
25
36
|
```
|
|
26
37
|
|
|
27
|
-
**Zero-config flow (v7+):** the browser step lets the user pick (or create) an app. The CLI stores the app's **key (UUID)**, **name**, and **instance URL** in `.securenow/credentials.json`. The SDK reads this file at boot and sends traces/logs to the right app bucket — **no env vars required for local dev**.
|
|
28
|
-
|
|
29
|
-
**
|
|
38
|
+
**Zero-config flow (v7+):** the browser step lets the user pick (or create) an app. The CLI stores the app's **key (UUID)**, **name**, and **instance URL** in `.securenow/credentials.json`. The SDK reads this file at boot and sends traces/logs to the right app bucket — **no env vars required for local dev**.
|
|
39
|
+
|
|
40
|
+
**Default-on security (v7.4+):** after picking or creating the app, `securenow login` turns on that app's firewall toggle, mints an API key with `firewall:read + blocklist:read + allowlist:read` scopes, and writes it into `.securenow/credentials.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 login, use `securenow api-key set snk_live_...` (see [API Key Management](#api-key-management) below).
|
|
30
41
|
|
|
31
42
|
Credentials resolve in order: `SECURENOW_TOKEN` env var → project `.securenow/credentials.json` → global `~/.securenow/credentials.json`.
|
|
32
43
|
|
|
@@ -245,7 +256,7 @@ securenow firewall status # layers, sync time, blocked count,
|
|
|
245
256
|
securenow firewall test-ip <ip> # check if IP would be blocked
|
|
246
257
|
```
|
|
247
258
|
|
|
248
|
-
**Zero-config setup (v7.
|
|
259
|
+
**Zero-config setup (v7.4+):** running `securenow login` enables the selected app's firewall toggle, auto-mints an API key (scoped `firewall:read + blocklist:read + allowlist:read`), and writes it to the credentials file 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. See [the landing firewall page](https://securenow.ai/firewall) for an overview.
|
|
249
260
|
|
|
250
261
|
### Blocklist — Block Malicious IPs
|
|
251
262
|
|
package/cli/diagnostics.js
CHANGED
|
@@ -39,6 +39,7 @@ function resolvedConfig() {
|
|
|
39
39
|
const apiUrl = config.getApiUrl();
|
|
40
40
|
const loggingEnabled = !/^(0|false)$/i.test(String(process.env.SECURENOW_LOGGING_ENABLED ?? ''));
|
|
41
41
|
const captureBody = !/^(0|false)$/i.test(String(process.env.SECURENOW_CAPTURE_BODY ?? ''));
|
|
42
|
+
const captureMultipart = !/^(0|false)$/i.test(String(process.env.SECURENOW_CAPTURE_MULTIPART ?? ''));
|
|
42
43
|
const firewallEnabled =
|
|
43
44
|
!!apiKey && process.env.SECURENOW_FIREWALL_ENABLED !== '0';
|
|
44
45
|
|
|
@@ -52,6 +53,7 @@ function resolvedConfig() {
|
|
|
52
53
|
apiUrl,
|
|
53
54
|
loggingEnabled,
|
|
54
55
|
captureBody,
|
|
56
|
+
captureMultipart,
|
|
55
57
|
firewallEnabled,
|
|
56
58
|
firewallLayers: {
|
|
57
59
|
http: firewallEnabled,
|
|
@@ -62,6 +64,21 @@ function resolvedConfig() {
|
|
|
62
64
|
};
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
function maskSecret(value) {
|
|
68
|
+
if (!value) return '';
|
|
69
|
+
const text = String(value);
|
|
70
|
+
if (text.length <= 12) return '***';
|
|
71
|
+
return `${text.slice(0, 12)}...${text.slice(-4)}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function redactConfig(cfg) {
|
|
75
|
+
return {
|
|
76
|
+
...cfg,
|
|
77
|
+
headers: cfg.headers ? '***' : '',
|
|
78
|
+
apiKey: cfg.apiKey ? maskSecret(cfg.apiKey) : '',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
function parseHeaders(str) {
|
|
66
83
|
const out = {};
|
|
67
84
|
if (!str) return out;
|
|
@@ -305,6 +322,7 @@ function env(_args, flags) {
|
|
|
305
322
|
SECURENOW_API_URL: cfg.apiUrl,
|
|
306
323
|
SECURENOW_LOGGING_ENABLED: cfg.loggingEnabled ? '1' : '0',
|
|
307
324
|
SECURENOW_CAPTURE_BODY: cfg.captureBody ? '1' : '0',
|
|
325
|
+
SECURENOW_CAPTURE_MULTIPART: cfg.captureMultipart ? '1' : '0',
|
|
308
326
|
SECURENOW_NO_UUID: process.env.SECURENOW_NO_UUID || `(auto: ${require('../app-config').resolveNoUuid() ? '1' : '0'})`,
|
|
309
327
|
SECURENOW_FIREWALL_TCP: process.env.SECURENOW_FIREWALL_TCP || '0',
|
|
310
328
|
SECURENOW_FIREWALL_IPTABLES: process.env.SECURENOW_FIREWALL_IPTABLES || '0',
|
|
@@ -313,7 +331,7 @@ function env(_args, flags) {
|
|
|
313
331
|
};
|
|
314
332
|
|
|
315
333
|
if (flags.json) {
|
|
316
|
-
ui.json({ resolved: cfg, env: vars });
|
|
334
|
+
ui.json({ resolved: redactConfig(cfg), env: vars });
|
|
317
335
|
return;
|
|
318
336
|
}
|
|
319
337
|
|
|
@@ -324,6 +342,7 @@ function env(_args, flags) {
|
|
|
324
342
|
['Logs endpoint', cfg.logsEndpoint],
|
|
325
343
|
['Logging', cfg.loggingEnabled ? ui.c.green('enabled') : ui.c.dim('disabled')],
|
|
326
344
|
['Body capture', cfg.captureBody ? ui.c.green('enabled') : ui.c.dim('disabled')],
|
|
345
|
+
['Multipart capture', cfg.captureMultipart ? ui.c.green('enabled') : ui.c.dim('disabled')],
|
|
327
346
|
['Firewall', cfg.firewallEnabled ? ui.c.green('enabled') : ui.c.dim('disabled (no API key)')],
|
|
328
347
|
]);
|
|
329
348
|
|
|
@@ -377,7 +396,7 @@ async function doctor(_args, flags) {
|
|
|
377
396
|
const ok = checks.every((c) => c.ok);
|
|
378
397
|
|
|
379
398
|
if (flags.json) {
|
|
380
|
-
ui.json({ ok, resolved: cfg, checks, warnings });
|
|
399
|
+
ui.json({ ok, resolved: redactConfig(cfg), checks, warnings });
|
|
381
400
|
process.exit(ok ? 0 : 1);
|
|
382
401
|
}
|
|
383
402
|
|
package/cli/init.js
CHANGED
|
@@ -1,24 +1,52 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const ui = require('./ui');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const ui = require('./ui');
|
|
6
|
+
const config = require('./config');
|
|
7
|
+
|
|
8
|
+
const DEFAULT_ENV = {
|
|
9
|
+
SECURENOW_LOGGING_ENABLED: '1',
|
|
10
|
+
SECURENOW_CAPTURE_BODY: '1',
|
|
11
|
+
SECURENOW_CAPTURE_MULTIPART: '1',
|
|
12
|
+
SECURENOW_FIREWALL_ENABLED: '1',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const INSTRUMENTATION_JS = `import { createRequire } from 'node:module';
|
|
16
|
+
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
|
|
19
|
+
export async function register() {
|
|
20
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return;
|
|
21
|
+
|
|
22
|
+
process.env.SECURENOW_LOGGING_ENABLED ??= '1';
|
|
23
|
+
process.env.SECURENOW_CAPTURE_BODY ??= '1';
|
|
24
|
+
process.env.SECURENOW_CAPTURE_MULTIPART ??= '1';
|
|
25
|
+
process.env.SECURENOW_FIREWALL_ENABLED ??= '1';
|
|
26
|
+
|
|
27
|
+
const { registerSecureNow } = require('securenow/nextjs');
|
|
28
|
+
registerSecureNow({ captureBody: true });
|
|
29
|
+
require('securenow/nextjs-auto-capture');
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
const INSTRUMENTATION_TS = `import { createRequire } from 'node:module';
|
|
34
|
+
|
|
35
|
+
const require = createRequire(import.meta.url);
|
|
36
|
+
|
|
37
|
+
export async function register() {
|
|
38
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return;
|
|
39
|
+
|
|
40
|
+
process.env.SECURENOW_LOGGING_ENABLED ??= '1';
|
|
41
|
+
process.env.SECURENOW_CAPTURE_BODY ??= '1';
|
|
42
|
+
process.env.SECURENOW_CAPTURE_MULTIPART ??= '1';
|
|
43
|
+
process.env.SECURENOW_FIREWALL_ENABLED ??= '1';
|
|
44
|
+
|
|
45
|
+
const { registerSecureNow } = require('securenow/nextjs');
|
|
46
|
+
registerSecureNow({ captureBody: true });
|
|
47
|
+
require('securenow/nextjs-auto-capture');
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
22
50
|
|
|
23
51
|
function detectProject(dir) {
|
|
24
52
|
const pkgPath = path.join(dir, 'package.json');
|
|
@@ -165,37 +193,52 @@ function initNode(dir, project) {
|
|
|
165
193
|
}
|
|
166
194
|
}
|
|
167
195
|
|
|
168
|
-
function initEnv(dir, flags) {
|
|
169
|
-
const envFiles = ['.env', '.env.local'];
|
|
170
|
-
let envPath = null;
|
|
171
|
-
|
|
172
|
-
for (const f of envFiles) {
|
|
173
|
-
const p = path.join(dir, f);
|
|
174
|
-
if (fs.existsSync(p)) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
196
|
+
function initEnv(dir, flags) {
|
|
197
|
+
const envFiles = ['.env', '.env.local'];
|
|
198
|
+
let envPath = null;
|
|
199
|
+
|
|
200
|
+
for (const f of envFiles) {
|
|
201
|
+
const p = path.join(dir, f);
|
|
202
|
+
if (fs.existsSync(p)) {
|
|
203
|
+
envPath = p;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!envPath) envPath = path.join(dir, '.env.local');
|
|
209
|
+
|
|
210
|
+
const existing = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf8') : '';
|
|
211
|
+
const additions = [];
|
|
212
|
+
for (const [key, value] of Object.entries(DEFAULT_ENV)) {
|
|
213
|
+
if (!hasEnvKey(existing, key)) additions.push(`${key}=${value}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const explicitApiKey = flags.key || flags['api-key'] || '';
|
|
217
|
+
const hasApiKey = hasEnvKey(existing, 'SECURENOW_API_KEY');
|
|
218
|
+
if (explicitApiKey && !hasApiKey) additions.push(`SECURENOW_API_KEY=${explicitApiKey}`);
|
|
219
|
+
|
|
220
|
+
if (additions.length > 0) {
|
|
221
|
+
const sep = existing && !existing.endsWith('\n') ? '\n' : '';
|
|
222
|
+
fs.appendFileSync(envPath, `${sep}${additions.join('\n')}\n`, 'utf8');
|
|
223
|
+
ui.success(`Updated ${path.basename(envPath)} with SecureNow defaults`);
|
|
224
|
+
} else {
|
|
225
|
+
ui.info(`${path.basename(envPath)} already contains SecureNow defaults`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (hasApiKey || explicitApiKey) {
|
|
229
|
+
ui.info(`SECURENOW_API_KEY is set in ${path.basename(envPath)}`);
|
|
230
|
+
} else if (config.getApiKey()) {
|
|
231
|
+
ui.info('Using firewall API key from project .securenow/credentials.json');
|
|
232
|
+
} else {
|
|
233
|
+
ui.warn(`Add your API key to ${path.basename(envPath)}:`);
|
|
234
|
+
console.log('');
|
|
235
|
+
console.log(' SECURENOW_API_KEY=snk_live_...');
|
|
236
|
+
console.log('');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function hasEnvKey(content, key) {
|
|
241
|
+
return new RegExp(`^\\s*${key}\\s*=`, 'm').test(content || '');
|
|
242
|
+
}
|
|
200
243
|
|
|
201
244
|
module.exports = { init };
|