securenow 7.7.14 → 7.7.15
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 +65 -121
- package/README.md +19 -24
- package/SKILL-API.md +490 -489
- package/SKILL-CLI.md +8 -8
- package/app-config.js +99 -42
- package/cli/apps.js +589 -597
- package/cli/auth.js +1 -3
- package/cli/config.js +37 -9
- package/cli/credentials.js +1 -1
- package/cli/diagnostics.js +10 -6
- package/cli/init.js +1 -0
- package/free-trial-banner.js +2 -2
- package/mcp/catalog.js +2 -2
- package/nextjs.d.ts +67 -63
- package/nextjs.js +48 -42
- package/nuxt-server-plugin.mjs +6 -11
- package/nuxt.d.ts +42 -38
- package/nuxt.mjs +1 -1
- package/package.json +1 -1
- package/tracing.d.ts +2 -1
- package/tracing.js +31 -47
- package/web-vite.mjs +102 -15
package/SKILL-API.md
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
# SecureNow SDK
|
|
2
|
-
|
|
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`
|
|
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.
|
|
6
|
-
|
|
1
|
+
# SecureNow SDK — Agent Skill
|
|
2
|
+
|
|
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
|
+
|
|
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
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. Alert-rule operators can inspect notifications, read exact `metadata.matchedSubdetectors`, dry-run candidate SQL with `securenow_alert_rule_candidate_test`, and apply global system-rule query fixes with `securenow_alert_rule_query_update` when evidence is clear.
|
|
8
8
|
|
|
9
9
|
**Noisy alert-rule reviews:** prefer fixing a generic system-rule detector over creating customer-specific false positives. Dry-run candidate SQL first, preserve tenant scoping with `__USER_APP_KEYS__`, keep exploit-specific indicators, then save the shared query mapping only with an audit reason and explicit confirmation.
|
|
10
|
-
|
|
11
|
-
## Installation
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install securenow@latest
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Install This Skill in Cursor
|
|
18
|
-
|
|
19
|
-
Save this file as `.cursor/skills/securenow-api/SKILL.md` in your project. Your AI agent will auto-discover it whenever you ask about integrating securenow, configuring tracing, setting up the firewall, or instrumenting any framework.
|
|
20
|
-
|
|
21
|
-
## Quick Start
|
|
22
|
-
|
|
23
|
-
### 1. Install, Login, And Init
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm install securenow@latest
|
|
27
|
-
node -p "require('./node_modules/securenow/package.json').version"
|
|
28
|
-
npx securenow version
|
|
29
|
-
npx securenow login
|
|
30
|
-
npx securenow init
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Use `securenow@7.5.1` or newer. Start authentication with `npx securenow login`; do not manually open auth URLs, because the CLI generates the callback/state values. The login flow lets the user pick or create an app, enables the app firewall by default, writes `.securenow/credentials.json`, and `init` scaffolds the framework integration.
|
|
34
|
-
|
|
35
|
-
### 2. Run With Instrumentation
|
|
36
|
-
|
|
37
|
-
**Option A
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
npx securenow run src/index.js
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Option B
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
node -r securenow/register src/index.js
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Option C
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
npx securenow init
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
That's it. Traces, logs, request body capture, multipart metadata capture, and firewall enforcement are on by default. No code changes for Express, Fastify, NestJS, Koa, Hapi, and raw Node.
|
|
56
|
-
|
|
57
|
-
### 3. Firewall Is Enabled by Default
|
|
58
|
-
|
|
59
|
-
Since v7.5.1, the browser login flow connects the firewall automatically after
|
|
60
|
-
the user picks or creates an app. The firewall key lives in your credentials
|
|
61
|
-
file
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
npx securenow login # pick/create app; firewall key is minted automatically
|
|
65
|
-
# or, if you already have one:
|
|
66
|
-
npx securenow api-key set snk_live_abc123...
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Both paths write the key to `.securenow/credentials.json` (
|
|
70
|
-
|
|
71
|
-
The firewall syncs your blocklist and enforces it on every request
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install securenow@latest
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Install This Skill in Cursor
|
|
18
|
+
|
|
19
|
+
Save this file as `.cursor/skills/securenow-api/SKILL.md` in your project. Your AI agent will auto-discover it whenever you ask about integrating securenow, configuring tracing, setting up the firewall, or instrumenting any framework.
|
|
20
|
+
|
|
21
|
+
## Quick Start — Any Node.js Framework
|
|
22
|
+
|
|
23
|
+
### 1. Install, Login, And Init
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install securenow@latest
|
|
27
|
+
node -p "require('./node_modules/securenow/package.json').version"
|
|
28
|
+
npx securenow version
|
|
29
|
+
npx securenow login
|
|
30
|
+
npx securenow init
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Use `securenow@7.5.1` or newer. Start authentication with `npx securenow login`; do not manually open auth URLs, because the CLI generates the callback/state values. The login flow lets the user pick or create an app, enables the app firewall by default, writes `.securenow/credentials.json`, and `init` scaffolds the framework integration.
|
|
34
|
+
|
|
35
|
+
### 2. Run With Instrumentation
|
|
36
|
+
|
|
37
|
+
**Option A — CLI (recommended):**
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx securenow run src/index.js
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Option B — Node preload flag:**
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
node -r securenow/register src/index.js
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Option C — Auto-setup for Next.js:**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx securenow init
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
That's it. Traces, logs, request body capture, multipart metadata capture, and firewall enforcement are on by default. No code changes for Express, Fastify, NestJS, Koa, Hapi, and raw Node.
|
|
56
|
+
|
|
57
|
+
### 3. Firewall Is Enabled by Default
|
|
58
|
+
|
|
59
|
+
Since v7.5.1, the browser login flow connects the firewall automatically after
|
|
60
|
+
the user picks or creates an app. The firewall key lives in your credentials
|
|
61
|
+
file — no env var required:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx securenow login # pick/create app; firewall key is minted automatically
|
|
65
|
+
# or, if you already have one:
|
|
66
|
+
npx securenow api-key set snk_live_abc123...
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Both paths write the key to `.securenow/credentials.json` (gitignored via credential-file patterns, not a whole-directory `.securenow/` ignore) and the firewall activates on next start. For production, run `npx securenow credentials runtime --env production` and mount/copy the tokenless file as `.securenow/credentials.json`.
|
|
70
|
+
|
|
71
|
+
The firewall syncs your blocklist and enforces it on every request — zero code changes.
|
|
72
72
|
|
|
73
73
|
Blocklist unblocks are audit-preserving: dashboard/API/CLI/MCP unblock actions
|
|
74
74
|
mark the active block as `removed`, invalidate firewall sync, clear expiry to
|
|
@@ -76,9 +76,10 @@ avoid TTL deletion, and retain block reports/history for future review or
|
|
|
76
76
|
reblock context.
|
|
77
77
|
|
|
78
78
|
For near-realtime propagation after a block/unblock, set
|
|
79
|
-
`
|
|
80
|
-
polls `/firewall/sync` with ETag/304, so
|
|
81
|
-
`
|
|
79
|
+
`config.firewall.versionCheckInterval` to `1` or `2` in the protected app's
|
|
80
|
+
`.securenow/credentials.json`. The SDK polls `/firewall/sync` with ETag/304, so
|
|
81
|
+
unchanged checks are lightweight; keep `config.firewall.syncInterval` high as a
|
|
82
|
+
safety-net full refresh.
|
|
82
83
|
|
|
83
84
|
Default automation is active for new and existing customers. The API
|
|
84
85
|
idempotently provisions risk-score rules for all apps/environments:
|
|
@@ -87,52 +88,52 @@ Run `securenow automation defaults --yes` or the API backfill script when an
|
|
|
87
88
|
operator needs to ensure those defaults immediately.
|
|
88
89
|
|
|
89
90
|
---
|
|
90
|
-
|
|
91
|
-
## Import Map
|
|
92
|
-
|
|
93
|
-
| Import | Purpose | Type |
|
|
94
|
-
|--------|---------|------|
|
|
95
|
-
| `securenow` / `securenow/register` | Auto-register tracing + firewall (side-effect) | Preload (`-r`) |
|
|
96
|
-
| `securenow/tracing` | Core OTel SDK; exports `getLogger()`, `isLoggingEnabled()` | CJS |
|
|
97
|
-
| `securenow/nextjs` | Next.js instrumentation; exports `registerSecureNow(options?)` | CJS |
|
|
98
|
-
| `securenow/nextjs-webpack-config` | Next.js config wrapper; exports `withSecureNow()`, `getSecureNowWebpackConfig()`, `EXTERNAL_PACKAGES` | CJS |
|
|
99
|
-
| `securenow/nextjs-middleware` | Edge middleware body capture; exports `middleware()`, `redactSensitiveData()`, `DEFAULT_SENSITIVE_FIELDS` | CJS |
|
|
100
|
-
| `securenow/nextjs-wrapper` | Route handler wrappers; exports `withSecureNow()`, `withSecureNowAsync()`, `captureRequestBody()`, `redactSensitiveData()` | CJS |
|
|
101
|
-
| `securenow/nextjs-auto-capture` | Auto-patch Next request for body capture; exports `patchNextRequest()`, `safeBodyCapture()`, `redactSensitiveData()`, `isBodyCaptureEnabled()` | CJS |
|
|
91
|
+
|
|
92
|
+
## Import Map
|
|
93
|
+
|
|
94
|
+
| Import | Purpose | Type |
|
|
95
|
+
|--------|---------|------|
|
|
96
|
+
| `securenow` / `securenow/register` | Auto-register tracing + firewall (side-effect) | Preload (`-r`) |
|
|
97
|
+
| `securenow/tracing` | Core OTel SDK; exports `getLogger()`, `isLoggingEnabled()` | CJS |
|
|
98
|
+
| `securenow/nextjs` | Next.js instrumentation; exports `registerSecureNow(options?)` | CJS |
|
|
99
|
+
| `securenow/nextjs-webpack-config` | Next.js config wrapper; exports `withSecureNow()`, `getSecureNowWebpackConfig()`, `EXTERNAL_PACKAGES` | CJS |
|
|
100
|
+
| `securenow/nextjs-middleware` | Edge middleware body capture; exports `middleware()`, `redactSensitiveData()`, `DEFAULT_SENSITIVE_FIELDS` | CJS |
|
|
101
|
+
| `securenow/nextjs-wrapper` | Route handler wrappers; exports `withSecureNow()`, `withSecureNowAsync()`, `captureRequestBody()`, `redactSensitiveData()` | CJS |
|
|
102
|
+
| `securenow/nextjs-auto-capture` | Auto-patch Next request for body capture; exports `patchNextRequest()`, `safeBodyCapture()`, `redactSensitiveData()`, `isBodyCaptureEnabled()` | CJS |
|
|
102
103
|
| `securenow/nuxt` | Nuxt 3 module (add to `modules` array) | ESM |
|
|
103
104
|
| `securenow/firewall` | Standalone firewall; exports `init()`, `shutdown()`, `getStats()`, `getMatcher()`, `getAllowlistMatcher()` | CJS |
|
|
104
105
|
| `securenow/rate-limits` | Rate-limit remediation API helper; exports `parseRateLimitText()`, `createRateLimitFromText()`, `createRateLimit()`, `listRateLimits()` | CJS |
|
|
105
106
|
| `securenow/firewall-only` | Preload: dotenv + firewall only, no tracing | Preload (`-r`) |
|
|
106
|
-
| `securenow/cidr` | CIDR utilities; exports `createMatcher()`, `ipToInt()`, `parseCidr()`, `matchesCidr()` | CJS |
|
|
107
|
-
| `securenow/resolve-ip` | IP resolution; exports `resolveClientIp()`, `resolveSocketIp()`, `isFromTrustedProxy()` | CJS |
|
|
108
|
-
| `securenow/console-instrumentation` | Console
|
|
109
|
-
| `securenow/web-vite` | Browser OTel (document load, fetch, XHR, user interaction); default export `startSecurenowWeb()` | ESM |
|
|
110
|
-
| `securenow/register-vite` | CJS bridge for Vite preload | CJS |
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Framework Integration Guides
|
|
115
|
-
|
|
116
|
-
### Express / Fastify / NestJS / Koa / Hapi / Raw Node
|
|
117
|
-
|
|
118
|
-
No code changes. Use the preload:
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
node -r securenow/register app.js
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Or with the CLI:
|
|
125
|
-
|
|
126
|
-
```bash
|
|
127
|
-
npx securenow run app.js
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
**PM2:**
|
|
131
|
-
|
|
132
|
-
```javascript
|
|
133
|
-
// ecosystem.config.cjs
|
|
134
|
-
module.exports = {
|
|
135
|
-
apps: [{
|
|
107
|
+
| `securenow/cidr` | CIDR utilities; exports `createMatcher()`, `ipToInt()`, `parseCidr()`, `matchesCidr()` | CJS |
|
|
108
|
+
| `securenow/resolve-ip` | IP resolution; exports `resolveClientIp()`, `resolveSocketIp()`, `isFromTrustedProxy()` | CJS |
|
|
109
|
+
| `securenow/console-instrumentation` | Console→OTLP bridge; exports `originalConsole`, `restoreConsole()` | CJS |
|
|
110
|
+
| `securenow/web-vite` | Browser OTel (document load, fetch, XHR, user interaction); default export `startSecurenowWeb()` | ESM |
|
|
111
|
+
| `securenow/register-vite` | CJS bridge for Vite preload | CJS |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Framework Integration Guides
|
|
116
|
+
|
|
117
|
+
### Express / Fastify / NestJS / Koa / Hapi / Raw Node
|
|
118
|
+
|
|
119
|
+
No code changes. Use the preload:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
node -r securenow/register app.js
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Or with the CLI:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npx securenow run app.js
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**PM2:**
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
// ecosystem.config.cjs
|
|
135
|
+
module.exports = {
|
|
136
|
+
apps: [{
|
|
136
137
|
name: 'my-app',
|
|
137
138
|
script: './app.js',
|
|
138
139
|
instances: 4,
|
|
@@ -141,16 +142,16 @@ module.exports = {
|
|
|
141
142
|
}],
|
|
142
143
|
};
|
|
143
144
|
```
|
|
144
|
-
|
|
145
|
-
**Docker:**
|
|
146
|
-
|
|
145
|
+
|
|
146
|
+
**Docker:**
|
|
147
|
+
|
|
147
148
|
```dockerfile
|
|
148
149
|
COPY .securenow/credentials.json ./.securenow/credentials.json
|
|
149
150
|
CMD ["node", "-r", "securenow/register", "app.js"]
|
|
150
151
|
```
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
154
155
|
### Next.js
|
|
155
156
|
|
|
156
157
|
Run `npx securenow init` first. It creates the straightforward integration below when files are missing, and prints a Codex/Claude-ready merge prompt when existing files need careful edits.
|
|
@@ -182,13 +183,13 @@ export async function register() {
|
|
|
182
183
|
await import(/* webpackIgnore: true */ 'securenow/nextjs-auto-capture');
|
|
183
184
|
}
|
|
184
185
|
```
|
|
185
|
-
|
|
186
|
-
`registerSecureNow(options?)` accepts:
|
|
187
|
-
|
|
186
|
+
|
|
187
|
+
`registerSecureNow(options?)` accepts:
|
|
188
|
+
|
|
188
189
|
```typescript
|
|
189
190
|
interface RegisterOptions {
|
|
190
191
|
serviceName?: string; // override credentials app key/name
|
|
191
|
-
endpoint?: string; //
|
|
192
|
+
endpoint?: string; // advanced OTLP endpoint override
|
|
192
193
|
noUuid?: boolean; // override credentials config.runtime.noUuid
|
|
193
194
|
captureBody?: boolean; // override credentials config.capture.body
|
|
194
195
|
}
|
|
@@ -203,7 +204,7 @@ On Vercel it uses `@vercel/otel`; self-hosted uses vanilla `@opentelemetry/sdk-n
|
|
|
203
204
|
"app": {
|
|
204
205
|
"key": "<uuid>",
|
|
205
206
|
"name": "my-nextjs-app",
|
|
206
|
-
"instance": "https://
|
|
207
|
+
"instance": "https://ingest.securenow.ai"
|
|
207
208
|
},
|
|
208
209
|
"config": {
|
|
209
210
|
"logging": { "enabled": true },
|
|
@@ -214,13 +215,13 @@ On Vercel it uses `@vercel/otel`; self-hosted uses vanilla `@opentelemetry/sdk-n
|
|
|
214
215
|
```
|
|
215
216
|
|
|
216
217
|
Local development and production do not need `.env.local`; `npx securenow login` and `npx securenow init` keep `.securenow/credentials.json` filled and gitignored. For production, run `npx securenow credentials runtime --env production` and mount/copy the generated JSON as `.securenow/credentials.json`.
|
|
217
|
-
|
|
218
|
-
#### Next.js Body Capture
|
|
219
|
-
|
|
220
|
-
**Option A
|
|
221
|
-
|
|
222
|
-
Add to your `instrumentation.ts`:
|
|
223
|
-
|
|
218
|
+
|
|
219
|
+
#### Next.js Body Capture
|
|
220
|
+
|
|
221
|
+
**Option A — Auto-capture (recommended):**
|
|
222
|
+
|
|
223
|
+
Add to your `instrumentation.ts`:
|
|
224
|
+
|
|
224
225
|
```typescript
|
|
225
226
|
export async function register() {
|
|
226
227
|
if (process.env.NEXT_RUNTIME !== 'nodejs') return;
|
|
@@ -231,42 +232,42 @@ export async function register() {
|
|
|
231
232
|
await import(/* webpackIgnore: true */ 'securenow/nextjs-auto-capture');
|
|
232
233
|
}
|
|
233
234
|
```
|
|
234
|
-
|
|
235
|
-
**Option B
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
// middleware.ts
|
|
239
|
-
export { middleware } from 'securenow/nextjs-middleware';
|
|
240
|
-
export const config = { matcher: ['/api/:path*'] };
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
**Option C
|
|
244
|
-
|
|
245
|
-
```typescript
|
|
246
|
-
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
247
|
-
|
|
248
|
-
export const POST = withSecureNow(async (req) => {
|
|
249
|
-
// handler
|
|
250
|
-
});
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
#### Next.js with `securenow init`
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
npx securenow login
|
|
257
|
-
npx securenow init
|
|
258
|
-
```
|
|
259
|
-
|
|
235
|
+
|
|
236
|
+
**Option B — Middleware:**
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// middleware.ts
|
|
240
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
241
|
+
export const config = { matcher: ['/api/:path*'] };
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Option C — Per-route wrapper:**
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
248
|
+
|
|
249
|
+
export const POST = withSecureNow(async (req) => {
|
|
250
|
+
// handler
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
#### Next.js with `securenow init`
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
npx securenow login
|
|
258
|
+
npx securenow init
|
|
259
|
+
```
|
|
260
|
+
|
|
260
261
|
Auto-detects Next.js, creates `instrumentation.ts`, adds `serverExternalPackages: ['securenow']` plus `outputFileTracingIncludes` when safe, and reuses the app, instance, firewall key, and secure defaults in `.securenow/credentials.json`. If files already exist, it prints an agent-ready prompt with the exact edits to propose.
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
### Nuxt 3
|
|
265
|
-
|
|
266
|
-
**`nuxt.config.ts`:**
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
export default defineNuxtConfig({
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### Nuxt 3
|
|
266
|
+
|
|
267
|
+
**`nuxt.config.ts`:**
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
export default defineNuxtConfig({
|
|
270
271
|
modules: ['securenow/nuxt'],
|
|
271
272
|
securenow: {
|
|
272
273
|
// optional overrides (defaults come from .securenow/credentials.json)
|
|
@@ -275,60 +276,60 @@ export default defineNuxtConfig({
|
|
|
275
276
|
```
|
|
276
277
|
|
|
277
278
|
The Nuxt module auto-configures Nitro externals, runtime config, and a server plugin that sets up OTel tracing + logging + firewall. Local and production app identity, firewall key, and secure defaults come from `.securenow/credentials.json`.
|
|
278
|
-
|
|
279
|
-
---
|
|
280
|
-
|
|
281
|
-
### Vite / Browser
|
|
282
|
-
|
|
283
|
-
```javascript
|
|
284
|
-
import startSecurenowWeb from 'securenow/web-vite';
|
|
285
|
-
|
|
286
|
-
startSecurenowWeb({
|
|
287
|
-
serviceName: 'my-frontend',
|
|
288
|
-
endpoint: 'https://
|
|
289
|
-
});
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
Instruments document load, fetch, XMLHttpRequest, and user interactions with browser-side OpenTelemetry.
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
|
-
## Firewall
|
|
297
|
-
|
|
298
|
-
The firewall auto-activates once an API key is resolvable and the app firewall toggle is on. Since **v7.5.1**, `npx securenow login` enables the selected app firewall by default and writes the scoped key to `.securenow/credentials.json`; `securenow api-key set` can still write/rotate the key later. Production should use the tokenless file generated by `securenow credentials runtime --env production`. Resolution order: project `./.securenow/credentials.json` -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global `~/.securenow/credentials.json` -> global named runtime credentials in the same fixed order; legacy env
|
|
299
|
-
|
|
300
|
-
```
|
|
301
|
-
Layer 4: Cloud/Edge WAF
|
|
302
|
-
Layer 3: OS Firewall
|
|
303
|
-
Layer 2: TCP Socket
|
|
304
|
-
Layer 1: HTTP Handler
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### Activate
|
|
308
|
-
|
|
309
|
-
```bash
|
|
310
|
-
# Zero-config (recommended)
|
|
311
|
-
npx securenow login # pick/create app; firewall connects automatically
|
|
312
|
-
# or, if you already have a key:
|
|
313
|
-
npx securenow api-key set snk_live_abc123...
|
|
314
|
-
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### Vite / Browser
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
import startSecurenowWeb from 'securenow/web-vite';
|
|
286
|
+
|
|
287
|
+
startSecurenowWeb({
|
|
288
|
+
serviceName: 'my-frontend',
|
|
289
|
+
endpoint: 'https://ingest.securenow.ai',
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Instruments document load, fetch, XMLHttpRequest, and user interactions with browser-side OpenTelemetry.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Firewall — Multi-Layer IP Blocking
|
|
298
|
+
|
|
299
|
+
The firewall auto-activates once an API key is resolvable and the app firewall toggle is on. Since **v7.5.1**, `npx securenow login` enables the selected app firewall by default and writes the scoped key to `.securenow/credentials.json`; `securenow api-key set` can still write/rotate the key later. Production should use the tokenless file generated by `securenow credentials runtime --env production`. Resolution order: project `./.securenow/credentials.json` -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global `~/.securenow/credentials.json` -> global named runtime credentials in the same fixed order. Runtime config is credentials-json based; legacy env fallback is disabled unless `SECURENOW_ENABLE_LEGACY_ENV=1` is explicitly set for an old deployment.
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
Layer 4: Cloud/Edge WAF → blocked at CDN (Cloudflare, AWS WAF, GCP Cloud Armor)
|
|
303
|
+
Layer 3: OS Firewall → kernel-level DROP (iptables/nftables)
|
|
304
|
+
Layer 2: TCP Socket → socket.destroy() before HTTP parsing
|
|
305
|
+
Layer 1: HTTP Handler → 403 JSON response (always active)
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Activate
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Zero-config (recommended) — writes the key to .securenow/credentials.json
|
|
312
|
+
npx securenow login # pick/create app; firewall connects automatically
|
|
313
|
+
# or, if you already have a key:
|
|
314
|
+
npx securenow api-key set snk_live_abc123...
|
|
315
|
+
|
|
315
316
|
# Production runtime file:
|
|
316
317
|
npx securenow credentials runtime --env production
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### Firewall-Only Mode (No Tracing Overhead)
|
|
320
|
-
|
|
321
|
-
```bash
|
|
322
|
-
node -r securenow/firewall-only app.js
|
|
323
|
-
|
|
324
|
-
# Or via the CLI (same effect)
|
|
325
|
-
securenow run --firewall-only app.js
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
Loads only dotenv + firewall. No OpenTelemetry, no tracing, no external packages needed.
|
|
329
|
-
|
|
330
|
-
### Programmatic Firewall API
|
|
331
|
-
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Firewall-Only Mode (No Tracing Overhead)
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
node -r securenow/firewall-only app.js
|
|
324
|
+
|
|
325
|
+
# Or via the CLI (same effect)
|
|
326
|
+
securenow run --firewall-only app.js
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Loads only dotenv + firewall. No OpenTelemetry, no tracing, no external packages needed.
|
|
330
|
+
|
|
331
|
+
### Programmatic Firewall API
|
|
332
|
+
|
|
332
333
|
```javascript
|
|
333
334
|
const firewall = require('securenow/firewall');
|
|
334
335
|
const appConfig = require('securenow/app-config');
|
|
@@ -338,260 +339,260 @@ await firewall.init({
|
|
|
338
339
|
apiUrl: 'https://api.securenow.ai',
|
|
339
340
|
syncInterval: 3600, // safety-net full sync every hour
|
|
340
341
|
versionCheckInterval: 10, // lightweight ETag check every 10s
|
|
341
|
-
failMode: 'open', // 'open' or 'closed'
|
|
342
|
-
statusCode: 403,
|
|
343
|
-
log: true,
|
|
344
|
-
tcp: false,
|
|
345
|
-
iptables: false,
|
|
346
|
-
cloud: null, // 'cloudflare' | 'aws' | 'gcp'
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
const stats = firewall.getStats();
|
|
350
|
-
const matcher = firewall.getMatcher(); // (ip) => boolean
|
|
351
|
-
const allowMatcher = firewall.getAllowlistMatcher();
|
|
352
|
-
|
|
353
|
-
await firewall.shutdown();
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### Cloud WAF Providers
|
|
357
|
-
|
|
358
|
-
**Cloudflare:**
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
**
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
342
|
+
failMode: 'open', // 'open' or 'closed'
|
|
343
|
+
statusCode: 403,
|
|
344
|
+
log: true,
|
|
345
|
+
tcp: false,
|
|
346
|
+
iptables: false,
|
|
347
|
+
cloud: null, // 'cloudflare' | 'aws' | 'gcp'
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
const stats = firewall.getStats();
|
|
351
|
+
const matcher = firewall.getMatcher(); // (ip) => boolean
|
|
352
|
+
const allowMatcher = firewall.getAllowlistMatcher();
|
|
353
|
+
|
|
354
|
+
await firewall.shutdown();
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Cloud WAF Providers
|
|
358
|
+
|
|
359
|
+
**Cloudflare:**
|
|
360
|
+
```json
|
|
361
|
+
{
|
|
362
|
+
"config": {
|
|
363
|
+
"firewall": {
|
|
364
|
+
"cloud": "cloudflare",
|
|
365
|
+
"cloudflare": {
|
|
366
|
+
"apiToken": "your-token",
|
|
367
|
+
"accountId": "your-account-id"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**AWS WAF:**
|
|
375
|
+
```json
|
|
376
|
+
{
|
|
377
|
+
"config": {
|
|
378
|
+
"firewall": {
|
|
379
|
+
"cloud": "aws",
|
|
380
|
+
"aws": {
|
|
381
|
+
"wafIpSetId": "your-ip-set-id",
|
|
382
|
+
"wafIpSetName": "your-ip-set-name",
|
|
383
|
+
"wafScope": "REGIONAL"
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
AWS authentication should use the standard AWS credential chain outside the
|
|
390
|
+
SecureNow SDK config.
|
|
391
|
+
Requires peer dep: `npm install @aws-sdk/client-wafv2`
|
|
392
|
+
|
|
393
|
+
**GCP Cloud Armor:**
|
|
394
|
+
```json
|
|
395
|
+
{
|
|
396
|
+
"config": {
|
|
397
|
+
"firewall": {
|
|
398
|
+
"cloud": "gcp",
|
|
399
|
+
"gcp": {
|
|
400
|
+
"projectId": "your-project",
|
|
401
|
+
"securityPolicy": "your-policy-name"
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
Requires peer dep: `npm install @google-cloud/compute`
|
|
408
|
+
|
|
409
|
+
**Dry-run (log only, no actual WAF changes):**
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"config": {
|
|
413
|
+
"firewall": {
|
|
414
|
+
"cloudDryRun": true
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Logging
|
|
423
|
+
|
|
424
|
+
Logging is enabled by default (`config.logging.enabled: true`). Logs are exported to your OTLP collector alongside traces.
|
|
425
|
+
|
|
426
|
+
### Get a Logger
|
|
427
|
+
|
|
428
|
+
```javascript
|
|
429
|
+
const { getLogger } = require('securenow/tracing');
|
|
430
|
+
|
|
431
|
+
const logger = getLogger('my-module', '1.0.0');
|
|
432
|
+
if (logger) {
|
|
433
|
+
logger.emit({ body: 'User login succeeded', severityText: 'INFO', attributes: { userId: '123' } });
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**CLI equivalent** (for shell scripts, cron, CI):
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
securenow log send "User login succeeded" --level info --attrs userId=123
|
|
441
|
+
securenow test-span "ci.smoke-test" # emit a span without booting the SDK
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Console Instrumentation
|
|
445
|
+
|
|
446
|
+
When tracing is active, `console.log/warn/error` are automatically patched to emit OTLP log records correlated with the active trace span. To access the original console:
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
const { originalConsole, restoreConsole } = require('securenow/console-instrumentation');
|
|
450
|
+
originalConsole.log('This bypasses OTLP');
|
|
451
|
+
restoreConsole(); // undo the patch
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## IP Resolution Utilities
|
|
457
|
+
|
|
458
|
+
```javascript
|
|
459
|
+
const { resolveClientIp, resolveSocketIp, isFromTrustedProxy } = require('securenow/resolve-ip');
|
|
460
|
+
|
|
461
|
+
// From an HTTP request (respects X-Forwarded-For from trusted proxies)
|
|
462
|
+
const clientIp = resolveClientIp(req);
|
|
463
|
+
|
|
464
|
+
// Direct socket IP
|
|
465
|
+
const socketIp = resolveSocketIp(req);
|
|
466
|
+
|
|
467
|
+
// Check if request comes from a trusted proxy
|
|
468
|
+
const trusted = isFromTrustedProxy(req);
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### CIDR Matching
|
|
472
|
+
|
|
473
|
+
```javascript
|
|
474
|
+
const { createMatcher, ipToInt, parseCidr, matchesCidr } = require('securenow/cidr');
|
|
475
|
+
|
|
476
|
+
const isBlocked = createMatcher(['10.0.0.0/8', '192.168.1.0/24']);
|
|
477
|
+
isBlocked('10.0.0.5'); // true
|
|
478
|
+
isBlocked('8.8.8.8'); // false
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**CLI equivalent:**
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
securenow cidr match 10.0.0.5 10.0.0.0/8,192.168.1.0/24 # exit 0 = match, 2 = miss
|
|
485
|
+
securenow cidr parse 10.0.0.0/8 # network/broadcast/mask/size
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## Sensitive Data Redaction
|
|
491
|
+
|
|
492
|
+
Available from multiple entry points (`securenow/nextjs-middleware`, `securenow/nextjs-wrapper`, `securenow/nextjs-auto-capture`):
|
|
493
|
+
|
|
494
|
+
```javascript
|
|
495
|
+
const { redactSensitiveData, DEFAULT_SENSITIVE_FIELDS } = require('securenow/nextjs-middleware');
|
|
496
|
+
|
|
497
|
+
const safe = redactSensitiveData({ username: 'alice', password: 's3cret', token: 'abc' });
|
|
498
|
+
// { username: 'alice', password: '[REDACTED]', token: '[REDACTED]' }
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**Auto-redacted fields:** `password`, `passwd`, `pwd`, `secret`, `token`, `api_key`, `apikey`, `access_token`, `auth`, `credentials`, `mysql_pwd`, `stripeToken`, `card`, `cardnumber`, `ccv`, `cvc`, `cvv`, `ssn`, `pin`.
|
|
502
|
+
|
|
503
|
+
Add custom fields via `config.capture.sensitiveFields` in `.securenow/credentials.json`.
|
|
504
|
+
|
|
505
|
+
**CLI equivalent** (for piping, scripts, debugging what a payload looks like post-redaction):
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
securenow redact '{"user":"alice","password":"s3cret"}'
|
|
509
|
+
securenow redact @request.json --fields internal_id,sessionHash
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
480
514
|
## Credentials Configuration
|
|
481
515
|
|
|
482
|
-
Local development and production use `.securenow/credentials.json`. Every setting below lives under `app` or `config`; `npx securenow credentials runtime --env production` creates a tokenless production file with the same structure. Since v7.7.2, the SDK also accepts named runtime files such as `.securenow/credentials.production.json` when the canonical `credentials.json` file is absent. Filename lookup is deterministic and does not read environment variables.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
|
487
|
-
|
|
488
|
-
| `
|
|
489
|
-
| `
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
|
494
|
-
|
|
495
|
-
| `
|
|
496
|
-
| `
|
|
497
|
-
| `
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
|
502
|
-
|
|
503
|
-
| `
|
|
504
|
-
| `
|
|
505
|
-
| `
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
### Behavior
|
|
509
|
-
|
|
510
|
-
| Variable | Description | Default |
|
|
511
|
-
|----------|-------------|---------|
|
|
512
|
-
| `SECURENOW_LOGGING_ENABLED` | Enable OTLP log export | `1` |
|
|
513
|
-
| `SECURENOW_CAPTURE_BODY` | Capture HTTP request bodies | `1` |
|
|
514
|
-
| `SECURENOW_MAX_BODY_SIZE` | Max body size in bytes | `10240` |
|
|
515
|
-
| `SECURENOW_CAPTURE_MULTIPART` | Capture multipart/form-data (streaming, metadata only) | `1` |
|
|
516
|
-
| `SECURENOW_SENSITIVE_FIELDS` | Comma-separated extra fields to redact | — |
|
|
517
|
-
| `SECURENOW_DISABLE_INSTRUMENTATIONS` | Comma-separated packages to skip (e.g. `fs,dns`) | — |
|
|
518
|
-
| `SECURENOW_TEST_SPAN` | `1` to emit a test span on startup | `0` |
|
|
519
|
-
| `SECURENOW_HIDE_BANNER` | `1` to suppress free-trial upgrade banner | `0` |
|
|
520
|
-
| `OTEL_LOG_LEVEL` | SDK diagnostic override: `error`, `warn`, `info`, `debug`, or `none` | `error` |
|
|
521
|
-
| `SECURENOW_ENVIRONMENT` / `SECURENOW_DEPLOYMENT_ENVIRONMENT` / `NODE_ENV` | Legacy fallback for `config.runtime.deploymentEnvironment` | `production` |
|
|
522
|
-
|
|
523
|
-
### Firewall
|
|
524
|
-
|
|
525
|
-
| Variable | Description | Default |
|
|
526
|
-
|----------|-------------|---------|
|
|
527
|
-
| `SECURENOW_API_KEY` | Legacy env override for the `apiKey` field (`snk_live_...`). Since v7.5.1, login writes the scoped firewall key to `.securenow/credentials.json`. | - |
|
|
528
|
-
| `SECURENOW_API_URL` | SecureNow API base URL | `https://api.securenow.ai` |
|
|
529
|
-
| `SECURENOW_FIREWALL_VERSION_INTERVAL` | Seconds between lightweight ETag checks | `10` |
|
|
530
|
-
| `SECURENOW_FIREWALL_SYNC_INTERVAL` | Safety-net full blocklist refresh interval in seconds | `3600` |
|
|
531
|
-
| `SECURENOW_FIREWALL_FAIL_MODE` | `open` (allow all when unavailable) or `closed` | `open` |
|
|
532
|
-
| `SECURENOW_FIREWALL_STATUS_CODE` | HTTP status for blocked requests | `403` |
|
|
533
|
-
| `SECURENOW_FIREWALL_LOG` | Log blocked requests | `1` |
|
|
534
|
-
| `SECURENOW_FIREWALL_TCP` | Enable Layer 2 TCP blocking | `0` |
|
|
535
|
-
| `SECURENOW_FIREWALL_IPTABLES` | Enable Layer 3 iptables/nftables | `0` |
|
|
536
|
-
| `SECURENOW_FIREWALL_CLOUD` | Cloud WAF: `cloudflare`, `aws`, or `gcp` | — |
|
|
537
|
-
| `SECURENOW_FIREWALL_CLOUD_DRY_RUN` | `1` to log cloud pushes without applying | `0` |
|
|
538
|
-
| `SECURENOW_TRUSTED_PROXIES` | Comma-separated trusted proxy IPs | — |
|
|
539
|
-
|
|
516
|
+
Local development and production use `.securenow/credentials.json`. Every setting below lives under `app` or `config`; `npx securenow credentials runtime --env production` creates a tokenless production file with the same structure. Since v7.7.2, the SDK also accepts named runtime files such as `.securenow/credentials.production.json` when the canonical `credentials.json` file is absent. Filename lookup is deterministic and does not read environment variables. Legacy env fallback is disabled unless `SECURENOW_ENABLE_LEGACY_ENV=1` is explicitly set.
|
|
517
|
+
|
|
518
|
+
| Credentials path | Purpose |
|
|
519
|
+
|---|---|
|
|
520
|
+
| `app.key` | App routing UUID. The SecureNow ingestion gateway routes telemetry by this key |
|
|
521
|
+
| `app.name` | Human-readable app label |
|
|
522
|
+
| `apiKey` | Scoped firewall key (`snk_live_...`) |
|
|
523
|
+
| `config.otel.endpoint` | Optional OTLP base endpoint override |
|
|
524
|
+
| `config.otel.tracesEndpoint` | Optional full traces endpoint |
|
|
525
|
+
| `config.otel.logsEndpoint` | Optional full logs endpoint |
|
|
526
|
+
| `config.otel.headers` | Extra OTLP headers as JSON object |
|
|
527
|
+
| `config.otel.logLevel` | SDK diagnostics: `error`, `warn`, `info`, `debug`, or `none` |
|
|
528
|
+
| `config.otel.disableInstrumentations` | OTel instrumentation package names to skip |
|
|
529
|
+
| `config.logging.enabled` | Enable/disable OTLP log export |
|
|
530
|
+
| `config.capture.body` | Capture HTTP request bodies |
|
|
531
|
+
| `config.capture.maxBodySize` | Max body size in bytes |
|
|
532
|
+
| `config.capture.multipart` | Capture multipart metadata, never file content |
|
|
533
|
+
| `config.capture.sensitiveFields` | Extra redaction field fragments |
|
|
534
|
+
| `config.runtime.deploymentEnvironment` | Sent as `deployment.environment` |
|
|
535
|
+
| `config.runtime.noUuid` | Use exact app key as service name without UUID suffix |
|
|
536
|
+
| `config.runtime.strict` | Exit clustered workers when no app identity resolves |
|
|
537
|
+
| `config.runtime.testSpan` | Emit a startup test span |
|
|
538
|
+
| `config.runtime.hideBanner` | Suppress the free-trial upgrade banner |
|
|
539
|
+
| `config.firewall.*` | Local firewall behavior, API URL, intervals, cloud WAF, and trusted proxy settings |
|
|
540
|
+
|
|
540
541
|
**Resilience:** The firewall SDK includes a circuit breaker (opens after 5 consecutive errors, 2-min cooldown), in-flight request guards (prevents overlapping requests), 429 Retry-After support, and exponential backoff on both lightweight ETag checks and initial sync retries.
|
|
541
|
-
|
|
542
|
-
### Cloud WAF Provider Variables
|
|
543
|
-
|
|
544
|
-
| Provider | Variables |
|
|
545
|
-
|----------|-----------|
|
|
546
|
-
| Cloudflare | `
|
|
547
|
-
| AWS WAF | `
|
|
548
|
-
| GCP | `
|
|
549
|
-
|
|
550
|
-
### Priority Order
|
|
551
|
-
|
|
552
|
-
**Service name:** credentials `app.key` > credentials `app.name` >
|
|
553
|
-
|
|
554
|
-
**Endpoint:** credentials `config.otel.tracesEndpoint` / `config.otel.endpoint`
|
|
555
|
-
|
|
556
|
-
---
|
|
557
|
-
|
|
558
|
-
## Recipes for Agentic AI
|
|
559
|
-
|
|
560
|
-
### Add Observability to an Existing Express App
|
|
561
|
-
|
|
562
|
-
```bash
|
|
542
|
+
|
|
543
|
+
### Cloud WAF Provider Variables
|
|
544
|
+
|
|
545
|
+
| Provider | Variables |
|
|
546
|
+
|----------|-----------|
|
|
547
|
+
| Cloudflare | `config.firewall.cloudflare.apiToken`, `config.firewall.cloudflare.accountId` |
|
|
548
|
+
| AWS WAF | `config.firewall.aws.wafIpSetId`, `config.firewall.aws.wafIpSetName`, `config.firewall.aws.wafScope` |
|
|
549
|
+
| GCP | `config.firewall.gcp.projectId`, `config.firewall.gcp.securityPolicy` |
|
|
550
|
+
|
|
551
|
+
### Priority Order
|
|
552
|
+
|
|
553
|
+
**Service name:** credentials `app.key` > credentials `app.name` > package name
|
|
554
|
+
|
|
555
|
+
**Endpoint:** credentials `config.otel.tracesEndpoint` / `config.otel.endpoint` > default SecureNow ingestion gateway `https://ingest.securenow.ai`
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Recipes for Agentic AI
|
|
560
|
+
|
|
561
|
+
### Add Observability to an Existing Express App
|
|
562
|
+
|
|
563
|
+
```bash
|
|
563
564
|
npm install securenow@latest
|
|
564
565
|
npx securenow login
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
No `.env` is needed. `npx securenow login` writes app identity,
|
|
568
|
-
|
|
569
|
-
Update `package.json`:
|
|
570
|
-
```json
|
|
571
|
-
{ "scripts": { "start": "node -r securenow/register src/index.js" } }
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
No code changes to the application needed.
|
|
575
|
-
|
|
576
|
-
### Add Observability + Firewall to a Next.js App
|
|
577
|
-
|
|
578
|
-
```bash
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
No `.env` is needed. `npx securenow login` writes app identity, firewall key, and secure defaults to `.securenow/credentials.json`; the SDK uses the default SecureNow ingestion gateway and the gateway routes by `app.key`. `npx securenow init` makes sure the file has explanations and is gitignored without ignoring the whole `.securenow/` directory.
|
|
569
|
+
|
|
570
|
+
Update `package.json`:
|
|
571
|
+
```json
|
|
572
|
+
{ "scripts": { "start": "node -r securenow/register src/index.js" } }
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
No code changes to the application needed.
|
|
576
|
+
|
|
577
|
+
### Add Observability + Firewall to a Next.js App
|
|
578
|
+
|
|
579
|
+
```bash
|
|
579
580
|
npm install securenow@latest
|
|
580
581
|
npx securenow login # pick/create app; firewall key is minted automatically
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
`securenow login` enables the selected app's firewall toggle and writes session, app, and firewall key to `.securenow/credentials.json` (
|
|
584
|
-
|
|
585
|
-
### Enable Firewall With Zero Tracing Overhead
|
|
586
|
-
|
|
587
|
-
For apps that only need IP blocking:
|
|
588
|
-
|
|
589
|
-
```bash
|
|
590
|
-
node -r securenow/firewall-only app.js
|
|
591
|
-
```
|
|
592
|
-
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
`securenow login` enables the selected app's firewall toggle and writes session, app, and firewall key to `.securenow/credentials.json` (gitignored via credential-file patterns, not a whole-directory `.securenow/` ignore). Traces, logs, request body capture, multipart metadata capture, and firewall enforcement are enabled by default. Then run `npx securenow init`; it creates `instrumentation.ts`, patches `next.config.*` when safe, or prints exact Codex/Claude merge instructions for existing files.
|
|
585
|
+
|
|
586
|
+
### Enable Firewall With Zero Tracing Overhead
|
|
587
|
+
|
|
588
|
+
For apps that only need IP blocking:
|
|
589
|
+
|
|
590
|
+
```bash
|
|
591
|
+
node -r securenow/firewall-only app.js
|
|
592
|
+
```
|
|
593
|
+
|
|
593
594
|
Make sure an API key is resolvable by running `npx securenow login` first. If you already have a key, `securenow api-key set snk_live_...` writes the creds file. For production, run `npx securenow credentials runtime --env production` and mount/copy it as `.securenow/credentials.json`.
|
|
594
|
-
|
|
595
|
+
|
|
595
596
|
### Production Hardened Configuration
|
|
596
597
|
|
|
597
598
|
```json
|
|
@@ -611,22 +612,22 @@ Make sure an API key is resolvable by running `npx securenow login` first. If yo
|
|
|
611
612
|
}
|
|
612
613
|
}
|
|
613
614
|
```
|
|
614
|
-
|
|
615
|
-
### Instrument a Docker Container
|
|
616
|
-
|
|
617
|
-
```dockerfile
|
|
618
|
-
FROM node:20-slim
|
|
619
|
-
WORKDIR /app
|
|
620
|
-
COPY package*.json ./
|
|
621
|
-
RUN npm ci --omit=dev
|
|
615
|
+
|
|
616
|
+
### Instrument a Docker Container
|
|
617
|
+
|
|
618
|
+
```dockerfile
|
|
619
|
+
FROM node:20-slim
|
|
620
|
+
WORKDIR /app
|
|
621
|
+
COPY package*.json ./
|
|
622
|
+
RUN npm ci --omit=dev
|
|
622
623
|
COPY . .
|
|
623
624
|
# Mount/copy secret file at runtime as /app/.securenow/credentials.json.
|
|
624
625
|
|
|
625
626
|
CMD ["node", "-r", "securenow/register", "src/index.js"]
|
|
626
627
|
```
|
|
627
|
-
|
|
628
|
-
### Kubernetes with Separate Trace/Log Collectors
|
|
629
|
-
|
|
628
|
+
|
|
629
|
+
### Kubernetes with Separate Trace/Log Collectors
|
|
630
|
+
|
|
630
631
|
```json
|
|
631
632
|
{
|
|
632
633
|
"app": { "key": "k8s-service", "name": "k8s-service" },
|
|
@@ -640,26 +641,26 @@ CMD ["node", "-r", "securenow/register", "src/index.js"]
|
|
|
640
641
|
}
|
|
641
642
|
}
|
|
642
643
|
```
|
|
643
|
-
|
|
644
|
-
---
|
|
645
|
-
|
|
646
|
-
## Verification
|
|
647
|
-
|
|
648
|
-
On startup, securenow logs its configuration:
|
|
649
|
-
|
|
650
|
-
```
|
|
651
|
-
[securenow] app.key="my-app"
|
|
652
|
-
[securenow] OTel SDK started
|
|
653
|
-
[securenow] Logging: ENABLED
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
## Verification
|
|
648
|
+
|
|
649
|
+
On startup, securenow logs its configuration:
|
|
650
|
+
|
|
651
|
+
```
|
|
652
|
+
[securenow] app.key="my-app" → service.name=my-app
|
|
653
|
+
[securenow] OTel SDK started → https://collector:4318/v1/traces
|
|
654
|
+
[securenow] Logging: ENABLED → https://collector:4318/v1/logs
|
|
654
655
|
[securenow] Request body capture: ENABLED (max: 10240 bytes)
|
|
655
656
|
[securenow] Firewall: ENABLED
|
|
656
657
|
[securenow] Firewall: synced 142 blocked IPs
|
|
657
658
|
```
|
|
658
659
|
|
|
659
660
|
Set `config.otel.logLevel` to `debug`, or temporarily run with `OTEL_LOG_LEVEL=debug`, and run `securenow doctor --json` to troubleshoot connectivity, duplicate OpenTelemetry API packages, and provider registration issues.
|
|
660
|
-
|
|
661
|
-
**CLI equivalent** (works without booting the SDK
|
|
662
|
-
|
|
661
|
+
|
|
662
|
+
**CLI equivalent** (works without booting the SDK — useful when the app won't start):
|
|
663
|
+
|
|
663
664
|
```bash
|
|
664
665
|
securenow env # show resolved app key, endpoints, and credentials fields
|
|
665
666
|
securenow doctor # probe OTLP + API endpoints, exits 1 on failure
|