securenow 6.0.2 → 6.1.0

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.
Files changed (87) hide show
  1. package/CONSUMING-APPS-GUIDE.md +455 -0
  2. package/NPM_README.md +2029 -0
  3. package/README.md +297 -40
  4. package/SKILL-API.md +634 -0
  5. package/SKILL-CLI.md +454 -0
  6. package/cidr.js +83 -0
  7. package/cli/apps.js +585 -0
  8. package/cli/auth.js +280 -0
  9. package/cli/client.js +115 -0
  10. package/cli/config.js +173 -0
  11. package/cli/diagnostics.js +387 -0
  12. package/cli/firewall.js +100 -0
  13. package/cli/fp.js +638 -0
  14. package/cli/init.js +201 -0
  15. package/cli/monitor.js +440 -0
  16. package/cli/run.js +148 -0
  17. package/cli/security.js +980 -0
  18. package/cli/ui.js +386 -0
  19. package/cli/utils.js +127 -0
  20. package/cli.js +466 -455
  21. package/console-instrumentation.js +147 -136
  22. package/docs/ALL-FRAMEWORKS-QUICKSTART.md +1377 -455
  23. package/docs/API-KEYS-GUIDE.md +233 -0
  24. package/docs/ARCHITECTURE.md +3 -3
  25. package/docs/AUTO-BODY-CAPTURE.md +1 -1
  26. package/docs/AUTO-SETUP-SUMMARY.md +331 -0
  27. package/docs/AUTO-SETUP.md +4 -4
  28. package/docs/AUTOMATIC-IP-CAPTURE.md +5 -5
  29. package/docs/BODY-CAPTURE-FIX.md +261 -0
  30. package/docs/BODY-CAPTURE-QUICKSTART.md +2 -2
  31. package/docs/CHANGELOG-NEXTJS.md +1 -35
  32. package/docs/COMPLETION-REPORT.md +408 -0
  33. package/docs/CUSTOMER-GUIDE.md +16 -16
  34. package/docs/EASIEST-SETUP.md +5 -5
  35. package/docs/ENVIRONMENT-VARIABLES.md +880 -652
  36. package/docs/EXPRESS-BODY-CAPTURE.md +13 -12
  37. package/docs/EXPRESS-SETUP-GUIDE.md +719 -720
  38. package/docs/FINAL-SOLUTION.md +335 -0
  39. package/docs/FIREWALL-GUIDE.md +426 -0
  40. package/docs/IMPLEMENTATION-SUMMARY.md +410 -0
  41. package/docs/INDEX.md +22 -4
  42. package/docs/LOGGING-GUIDE.md +701 -708
  43. package/docs/LOGGING-QUICKSTART.md +234 -255
  44. package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +323 -0
  45. package/docs/NEXTJS-BODY-CAPTURE.md +2 -2
  46. package/docs/NEXTJS-GUIDE.md +14 -14
  47. package/docs/NEXTJS-QUICKSTART.md +1 -1
  48. package/docs/NEXTJS-SETUP-COMPLETE.md +795 -0
  49. package/docs/NEXTJS-WRAPPER-APPROACH.md +1 -1
  50. package/docs/NUXT-GUIDE.md +166 -0
  51. package/docs/QUICKSTART-BODY-CAPTURE.md +2 -2
  52. package/docs/REDACTION-EXAMPLES.md +1 -1
  53. package/docs/REQUEST-BODY-CAPTURE.md +19 -10
  54. package/docs/SOLUTION-SUMMARY.md +312 -0
  55. package/docs/VERCEL-OTEL-MIGRATION.md +3 -3
  56. package/examples/README.md +6 -6
  57. package/examples/instrumentation-with-auto-capture.ts +1 -1
  58. package/examples/nextjs-env-example.txt +2 -2
  59. package/examples/nextjs-instrumentation.js +1 -1
  60. package/examples/nextjs-instrumentation.ts +1 -1
  61. package/examples/nextjs-with-logging-example.md +6 -6
  62. package/examples/nextjs-with-options.ts +1 -1
  63. package/examples/test-nextjs-setup.js +1 -1
  64. package/firewall-cloud.js +212 -0
  65. package/firewall-iptables.js +139 -0
  66. package/firewall-only.js +38 -0
  67. package/firewall-tcp.js +74 -0
  68. package/firewall.js +720 -0
  69. package/free-trial-banner.js +174 -0
  70. package/nextjs-auto-capture.js +199 -207
  71. package/nextjs-middleware.js +186 -181
  72. package/nextjs-webpack-config.js +88 -53
  73. package/nextjs-wrapper.js +158 -158
  74. package/nextjs.d.ts +1 -1
  75. package/nextjs.js +639 -647
  76. package/nuxt-server-plugin.mjs +423 -0
  77. package/nuxt.d.ts +60 -0
  78. package/nuxt.mjs +75 -0
  79. package/package.json +186 -164
  80. package/postinstall.js +6 -6
  81. package/register.d.ts +1 -1
  82. package/register.js +39 -4
  83. package/resolve-ip.js +77 -0
  84. package/tracing.d.ts +2 -1
  85. package/tracing.js +295 -34
  86. package/web-vite.mjs +239 -156
  87. package/LICENSE +0 -15
package/SKILL-API.md ADDED
@@ -0,0 +1,634 @@
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
+ ## Installation
8
+
9
+ ```bash
10
+ npm install securenow
11
+ ```
12
+
13
+ ### Install This Skill in Cursor
14
+
15
+ 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.
16
+
17
+ ## Quick Start — Any Node.js Framework
18
+
19
+ ### 1. Set Environment Variables
20
+
21
+ ```bash
22
+ # .env or .env.local
23
+ SECURENOW_APPID=my-app
24
+ SECURENOW_INSTANCE=https://your-collector:4318
25
+ ```
26
+
27
+ ### 2. Run With Instrumentation
28
+
29
+ **Option A — CLI (recommended):**
30
+
31
+ ```bash
32
+ npx securenow run src/index.js
33
+ ```
34
+
35
+ **Option B — Node preload flag:**
36
+
37
+ ```bash
38
+ node -r securenow/register src/index.js
39
+ ```
40
+
41
+ **Option C — Auto-setup for Next.js:**
42
+
43
+ ```bash
44
+ npx securenow init --key snk_live_...
45
+ ```
46
+
47
+ That's it. Traces and logs flow to your OTLP collector. No code changes for Express, Fastify, NestJS, Koa, Hapi, and raw Node.
48
+
49
+ ### 3. Enable the Firewall (Optional)
50
+
51
+ Add one more env var to auto-activate IP blocking:
52
+
53
+ ```bash
54
+ SECURENOW_API_KEY=snk_live_abc123...
55
+ ```
56
+
57
+ The firewall syncs your blocklist and enforces it on every request — zero code changes.
58
+
59
+ ---
60
+
61
+ ## Import Map
62
+
63
+ | Import | Purpose | Type |
64
+ |--------|---------|------|
65
+ | `securenow` / `securenow/register` | Auto-register tracing + firewall (side-effect) | Preload (`-r`) |
66
+ | `securenow/tracing` | Core OTel SDK; exports `getLogger()`, `isLoggingEnabled()` | CJS |
67
+ | `securenow/nextjs` | Next.js instrumentation; exports `registerSecureNow(options?)` | CJS |
68
+ | `securenow/nextjs-webpack-config` | Next.js config wrapper; exports `withSecureNow()`, `getSecureNowWebpackConfig()`, `EXTERNAL_PACKAGES` | CJS |
69
+ | `securenow/nextjs-middleware` | Edge middleware body capture; exports `middleware()`, `redactSensitiveData()`, `DEFAULT_SENSITIVE_FIELDS` | CJS |
70
+ | `securenow/nextjs-wrapper` | Route handler wrappers; exports `withSecureNow()`, `withSecureNowAsync()`, `captureRequestBody()`, `redactSensitiveData()` | CJS |
71
+ | `securenow/nextjs-auto-capture` | Auto-patch Next request for body capture; exports `patchNextRequest()`, `safeBodyCapture()`, `redactSensitiveData()`, `isBodyCaptureEnabled()` | CJS |
72
+ | `securenow/nuxt` | Nuxt 3 module (add to `modules` array) | ESM |
73
+ | `securenow/firewall` | Standalone firewall; exports `init()`, `shutdown()`, `getStats()`, `getMatcher()`, `getAllowlistMatcher()` | CJS |
74
+ | `securenow/firewall-only` | Preload: dotenv + firewall only, no tracing | Preload (`-r`) |
75
+ | `securenow/cidr` | CIDR utilities; exports `createMatcher()`, `ipToInt()`, `parseCidr()`, `matchesCidr()` | CJS |
76
+ | `securenow/resolve-ip` | IP resolution; exports `resolveClientIp()`, `resolveSocketIp()`, `isFromTrustedProxy()` | CJS |
77
+ | `securenow/console-instrumentation` | Console→OTLP bridge; exports `originalConsole`, `restoreConsole()` | CJS |
78
+ | `securenow/web-vite` | Browser OTel (document load, fetch, XHR, user interaction); default export `startSecurenowWeb()` | ESM |
79
+ | `securenow/register-vite` | CJS bridge for Vite preload | CJS |
80
+
81
+ ---
82
+
83
+ ## Framework Integration Guides
84
+
85
+ ### Express / Fastify / NestJS / Koa / Hapi / Raw Node
86
+
87
+ No code changes. Use the preload:
88
+
89
+ ```bash
90
+ node -r securenow/register app.js
91
+ ```
92
+
93
+ Or with the CLI:
94
+
95
+ ```bash
96
+ npx securenow run app.js
97
+ ```
98
+
99
+ **PM2:**
100
+
101
+ ```javascript
102
+ // ecosystem.config.cjs
103
+ module.exports = {
104
+ apps: [{
105
+ name: 'my-app',
106
+ script: './app.js',
107
+ instances: 4,
108
+ node_args: '-r securenow/register',
109
+ env: {
110
+ SECURENOW_APPID: 'my-app',
111
+ SECURENOW_INSTANCE: 'https://your-collector:4318',
112
+ SECURENOW_NO_UUID: '1',
113
+ },
114
+ }],
115
+ };
116
+ ```
117
+
118
+ **Docker:**
119
+
120
+ ```dockerfile
121
+ ENV SECURENOW_APPID=my-app
122
+ ENV SECURENOW_INSTANCE=https://your-collector:4318
123
+ CMD ["node", "-r", "securenow/register", "app.js"]
124
+ ```
125
+
126
+ ---
127
+
128
+ ### Next.js
129
+
130
+ Three files to touch:
131
+
132
+ **1. `next.config.js`** (or `.mjs` / `.ts`):
133
+
134
+ ```javascript
135
+ const { withSecureNow } = require('securenow/nextjs-webpack-config');
136
+
137
+ module.exports = withSecureNow({
138
+ // your existing config
139
+ });
140
+ ```
141
+
142
+ `withSecureNow()` auto-detects Next.js version:
143
+ - **>=15**: sets `serverExternalPackages`
144
+ - **<15**: sets `experimental.serverComponentsExternalPackages` + `experimental.instrumentationHook` + webpack ignore rules
145
+
146
+ **2. `instrumentation.ts`** (or `.js`, can be in `src/`):
147
+
148
+ ```typescript
149
+ export async function register() {
150
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
151
+ const { registerSecureNow } = require('securenow/nextjs');
152
+ registerSecureNow();
153
+ }
154
+ }
155
+ ```
156
+
157
+ `registerSecureNow(options?)` accepts:
158
+
159
+ ```typescript
160
+ interface RegisterOptions {
161
+ serviceName?: string; // override SECURENOW_APPID
162
+ endpoint?: string; // override SECURENOW_INSTANCE
163
+ noUuid?: boolean; // override SECURENOW_NO_UUID
164
+ captureBody?: boolean; // override SECURENOW_CAPTURE_BODY
165
+ }
166
+ ```
167
+
168
+ On Vercel it uses `@vercel/otel`; self-hosted uses vanilla `@opentelemetry/sdk-node`.
169
+
170
+ **3. `.env.local`:**
171
+
172
+ ```bash
173
+ SECURENOW_APPID=my-nextjs-app
174
+ SECURENOW_INSTANCE=https://your-collector:4318
175
+ ```
176
+
177
+ #### Next.js Body Capture
178
+
179
+ **Option A — Auto-capture (recommended):**
180
+
181
+ Add to your `instrumentation.ts`:
182
+
183
+ ```typescript
184
+ export async function register() {
185
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
186
+ const { registerSecureNow } = require('securenow/nextjs');
187
+ registerSecureNow({ captureBody: true });
188
+ require('securenow/nextjs-auto-capture');
189
+ }
190
+ }
191
+ ```
192
+
193
+ **Option B — Middleware:**
194
+
195
+ ```typescript
196
+ // middleware.ts
197
+ export { middleware } from 'securenow/nextjs-middleware';
198
+ export const config = { matcher: ['/api/:path*'] };
199
+ ```
200
+
201
+ **Option C — Per-route wrapper:**
202
+
203
+ ```typescript
204
+ import { withSecureNow } from 'securenow/nextjs-wrapper';
205
+
206
+ export const POST = withSecureNow(async (req) => {
207
+ // handler
208
+ });
209
+ ```
210
+
211
+ #### Next.js with `securenow init`
212
+
213
+ ```bash
214
+ npx securenow init --key snk_live_abc123...
215
+ ```
216
+
217
+ Auto-detects Next.js, creates `instrumentation.ts`, suggests `next.config` changes, writes API key to `.env.local`.
218
+
219
+ ---
220
+
221
+ ### Nuxt 3
222
+
223
+ **`nuxt.config.ts`:**
224
+
225
+ ```typescript
226
+ export default defineNuxtConfig({
227
+ modules: ['securenow/nuxt'],
228
+ securenow: {
229
+ // optional overrides (defaults come from env vars)
230
+ },
231
+ });
232
+ ```
233
+
234
+ **`.env`:**
235
+
236
+ ```bash
237
+ SECURENOW_APPID=my-nuxt-app
238
+ SECURENOW_INSTANCE=https://your-collector:4318
239
+ ```
240
+
241
+ The Nuxt module auto-configures Nitro externals, runtime config, and a server plugin that sets up OTel tracing + logging + firewall.
242
+
243
+ ---
244
+
245
+ ### Vite / Browser
246
+
247
+ ```javascript
248
+ import startSecurenowWeb from 'securenow/web-vite';
249
+
250
+ startSecurenowWeb({
251
+ serviceName: 'my-frontend',
252
+ endpoint: 'https://your-collector:4318',
253
+ });
254
+ ```
255
+
256
+ Instruments document load, fetch, XMLHttpRequest, and user interactions with browser-side OpenTelemetry.
257
+
258
+ ---
259
+
260
+ ## Firewall — Multi-Layer IP Blocking
261
+
262
+ The firewall auto-activates when `SECURENOW_API_KEY` is set. It syncs your blocklist from the SecureNow API and enforces it across up to four layers:
263
+
264
+ ```
265
+ Layer 4: Cloud/Edge WAF → blocked at CDN (Cloudflare, AWS WAF, GCP Cloud Armor)
266
+ Layer 3: OS Firewall → kernel-level DROP (iptables/nftables)
267
+ Layer 2: TCP Socket → socket.destroy() before HTTP parsing
268
+ Layer 1: HTTP Handler → 403 JSON response (always active)
269
+ ```
270
+
271
+ ### Activate
272
+
273
+ ```bash
274
+ # .env
275
+ SECURENOW_API_KEY=snk_live_abc123... # auto-activates Layer 1
276
+ SECURENOW_FIREWALL_TCP=1 # opt-in Layer 2
277
+ SECURENOW_FIREWALL_IPTABLES=1 # opt-in Layer 3 (Linux, needs root)
278
+ SECURENOW_FIREWALL_CLOUD=cloudflare # opt-in Layer 4
279
+ ```
280
+
281
+ ### Firewall-Only Mode (No Tracing Overhead)
282
+
283
+ ```bash
284
+ node -r securenow/firewall-only app.js
285
+
286
+ # Or via the CLI (same effect)
287
+ securenow run --firewall-only app.js
288
+ ```
289
+
290
+ Loads only dotenv + firewall. No OpenTelemetry, no tracing, no external packages needed.
291
+
292
+ ### Programmatic Firewall API
293
+
294
+ ```javascript
295
+ const firewall = require('securenow/firewall');
296
+
297
+ await firewall.init({
298
+ apiKey: process.env.SECURENOW_API_KEY,
299
+ apiUrl: 'https://api.securenow.ai',
300
+ syncInterval: 300, // full sync every 5 min
301
+ versionCheckInterval: 10, // lightweight version check every 10s
302
+ failMode: 'open', // 'open' or 'closed'
303
+ statusCode: 403,
304
+ log: true,
305
+ tcp: false,
306
+ iptables: false,
307
+ cloud: null, // 'cloudflare' | 'aws' | 'gcp'
308
+ });
309
+
310
+ const stats = firewall.getStats();
311
+ const matcher = firewall.getMatcher(); // (ip) => boolean
312
+ const allowMatcher = firewall.getAllowlistMatcher();
313
+
314
+ await firewall.shutdown();
315
+ ```
316
+
317
+ ### Cloud WAF Providers
318
+
319
+ **Cloudflare:**
320
+ ```bash
321
+ SECURENOW_FIREWALL_CLOUD=cloudflare
322
+ CLOUDFLARE_API_TOKEN=your-token
323
+ CLOUDFLARE_ACCOUNT_ID=your-account-id
324
+ ```
325
+
326
+ **AWS WAF:**
327
+ ```bash
328
+ SECURENOW_FIREWALL_CLOUD=aws
329
+ AWS_WAF_IP_SET_ID=your-ip-set-id
330
+ # + standard AWS credentials (env, profile, or IAM role)
331
+ ```
332
+ Requires peer dep: `npm install @aws-sdk/client-wafv2`
333
+
334
+ **GCP Cloud Armor:**
335
+ ```bash
336
+ SECURENOW_FIREWALL_CLOUD=gcp
337
+ GCP_PROJECT_ID=your-project
338
+ GCP_SECURITY_POLICY=your-policy-name
339
+ ```
340
+ Requires peer dep: `npm install @google-cloud/compute`
341
+
342
+ **Dry-run (log only, no actual WAF changes):**
343
+ ```bash
344
+ SECURENOW_FIREWALL_CLOUD_DRY_RUN=1
345
+ ```
346
+
347
+ ---
348
+
349
+ ## Logging
350
+
351
+ Logging is enabled by default (`SECURENOW_LOGGING_ENABLED=1`). Logs are exported to your OTLP collector alongside traces.
352
+
353
+ ### Get a Logger
354
+
355
+ ```javascript
356
+ const { getLogger } = require('securenow/tracing');
357
+
358
+ const logger = getLogger('my-module', '1.0.0');
359
+ if (logger) {
360
+ logger.emit({ body: 'User login succeeded', severityText: 'INFO', attributes: { userId: '123' } });
361
+ }
362
+ ```
363
+
364
+ **CLI equivalent** (for shell scripts, cron, CI):
365
+
366
+ ```bash
367
+ securenow log send "User login succeeded" --level info --attrs userId=123
368
+ securenow test-span "ci.smoke-test" # emit a span without booting the SDK
369
+ ```
370
+
371
+ ### Console Instrumentation
372
+
373
+ 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:
374
+
375
+ ```javascript
376
+ const { originalConsole, restoreConsole } = require('securenow/console-instrumentation');
377
+ originalConsole.log('This bypasses OTLP');
378
+ restoreConsole(); // undo the patch
379
+ ```
380
+
381
+ ---
382
+
383
+ ## IP Resolution Utilities
384
+
385
+ ```javascript
386
+ const { resolveClientIp, resolveSocketIp, isFromTrustedProxy } = require('securenow/resolve-ip');
387
+
388
+ // From an HTTP request (respects X-Forwarded-For from trusted proxies)
389
+ const clientIp = resolveClientIp(req);
390
+
391
+ // Direct socket IP
392
+ const socketIp = resolveSocketIp(req);
393
+
394
+ // Check if request comes from a trusted proxy
395
+ const trusted = isFromTrustedProxy(req);
396
+ ```
397
+
398
+ ### CIDR Matching
399
+
400
+ ```javascript
401
+ const { createMatcher, ipToInt, parseCidr, matchesCidr } = require('securenow/cidr');
402
+
403
+ const isBlocked = createMatcher(['10.0.0.0/8', '192.168.1.0/24']);
404
+ isBlocked('10.0.0.5'); // true
405
+ isBlocked('8.8.8.8'); // false
406
+ ```
407
+
408
+ **CLI equivalent:**
409
+
410
+ ```bash
411
+ securenow cidr match 10.0.0.5 10.0.0.0/8,192.168.1.0/24 # exit 0 = match, 2 = miss
412
+ securenow cidr parse 10.0.0.0/8 # network/broadcast/mask/size
413
+ ```
414
+
415
+ ---
416
+
417
+ ## Sensitive Data Redaction
418
+
419
+ Available from multiple entry points (`securenow/nextjs-middleware`, `securenow/nextjs-wrapper`, `securenow/nextjs-auto-capture`):
420
+
421
+ ```javascript
422
+ const { redactSensitiveData, DEFAULT_SENSITIVE_FIELDS } = require('securenow/nextjs-middleware');
423
+
424
+ const safe = redactSensitiveData({ username: 'alice', password: 's3cret', token: 'abc' });
425
+ // { username: 'alice', password: '[REDACTED]', token: '[REDACTED]' }
426
+ ```
427
+
428
+ **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`.
429
+
430
+ Add custom fields via `SECURENOW_SENSITIVE_FIELDS=field1,field2`.
431
+
432
+ **CLI equivalent** (for piping, scripts, debugging what a payload looks like post-redaction):
433
+
434
+ ```bash
435
+ securenow redact '{"user":"alice","password":"s3cret"}'
436
+ securenow redact @request.json --fields internal_id,sessionHash
437
+ ```
438
+
439
+ ---
440
+
441
+ ## Environment Variables — Complete Reference
442
+
443
+ ### Required
444
+
445
+ | Variable | Description | Default |
446
+ |----------|-------------|---------|
447
+ | `SECURENOW_APPID` | Service name / app identifier | *(auto-generated with UUID)* |
448
+ | `SECURENOW_INSTANCE` | OTLP collector base URL | `https://freetrial.securenow.ai:4318` |
449
+
450
+ ### Service Naming
451
+
452
+ | Variable | Description | Default |
453
+ |----------|-------------|---------|
454
+ | `OTEL_SERVICE_NAME` | OpenTelemetry standard; overrides `SECURENOW_APPID` | — |
455
+ | `SECURENOW_NO_UUID` | `1` to use exact app ID without UUID suffix | `0` |
456
+ | `SECURENOW_STRICT` | `1` to exit if APPID missing in PM2 cluster | `0` |
457
+
458
+ ### OTLP Connection
459
+
460
+ | Variable | Description | Default |
461
+ |----------|-------------|---------|
462
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | Standard OTel endpoint; overrides `SECURENOW_INSTANCE` | — |
463
+ | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Override traces endpoint specifically | `{instance}/v1/traces` |
464
+ | `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | Override logs endpoint specifically | `{instance}/v1/logs` |
465
+ | `OTEL_EXPORTER_OTLP_HEADERS` | Comma-separated `key=value` headers for OTLP requests | — |
466
+
467
+ ### Behavior
468
+
469
+ | Variable | Description | Default |
470
+ |----------|-------------|---------|
471
+ | `SECURENOW_LOGGING_ENABLED` | Enable OTLP log export | `1` |
472
+ | `SECURENOW_CAPTURE_BODY` | Capture HTTP request bodies | `0` |
473
+ | `SECURENOW_MAX_BODY_SIZE` | Max body size in bytes | `10240` |
474
+ | `SECURENOW_CAPTURE_MULTIPART` | Capture multipart/form-data (streaming, metadata only) | `0` |
475
+ | `SECURENOW_SENSITIVE_FIELDS` | Comma-separated extra fields to redact | — |
476
+ | `SECURENOW_DISABLE_INSTRUMENTATIONS` | Comma-separated packages to skip (e.g. `fs,dns`) | — |
477
+ | `SECURENOW_TEST_SPAN` | `1` to emit a test span on startup | `0` |
478
+ | `SECURENOW_HIDE_BANNER` | `1` to suppress free-trial upgrade banner | `0` |
479
+ | `OTEL_LOG_LEVEL` | SDK log level: `none`, `error`, `warn`, `info`, `debug` | `none` |
480
+ | `NODE_ENV` | Sent as `deployment.environment` attribute | `production` |
481
+
482
+ ### Firewall
483
+
484
+ | Variable | Description | Default |
485
+ |----------|-------------|---------|
486
+ | `SECURENOW_API_KEY` | API key (`snk_live_...`); activates firewall when set | — |
487
+ | `SECURENOW_API_URL` | SecureNow API base URL | `https://api.securenow.ai` |
488
+ | `SECURENOW_FIREWALL_ENABLED` | Master kill-switch (`0` to disable) | `1` |
489
+ | `SECURENOW_FIREWALL_VERSION_INTERVAL` | Seconds between lightweight version checks | `10` |
490
+ | `SECURENOW_FIREWALL_SYNC_INTERVAL` | Full blocklist refresh interval in seconds | `300` |
491
+ | `SECURENOW_FIREWALL_FAIL_MODE` | `open` (allow all when unavailable) or `closed` | `open` |
492
+ | `SECURENOW_FIREWALL_STATUS_CODE` | HTTP status for blocked requests | `403` |
493
+ | `SECURENOW_FIREWALL_LOG` | Log blocked requests | `1` |
494
+ | `SECURENOW_FIREWALL_TCP` | Enable Layer 2 TCP blocking | `0` |
495
+ | `SECURENOW_FIREWALL_IPTABLES` | Enable Layer 3 iptables/nftables | `0` |
496
+ | `SECURENOW_FIREWALL_CLOUD` | Cloud WAF: `cloudflare`, `aws`, or `gcp` | — |
497
+ | `SECURENOW_FIREWALL_CLOUD_DRY_RUN` | `1` to log cloud pushes without applying | `0` |
498
+ | `SECURENOW_TRUSTED_PROXIES` | Comma-separated trusted proxy IPs | — |
499
+
500
+ **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 version checks and initial sync retries.
501
+
502
+ ### Cloud WAF Provider Variables
503
+
504
+ | Provider | Variables |
505
+ |----------|-----------|
506
+ | Cloudflare | `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID` |
507
+ | AWS WAF | `AWS_WAF_IP_SET_ID`, `AWS_WAF_IP_SET_NAME`, `AWS_WAF_SCOPE` |
508
+ | GCP | `GCP_PROJECT_ID`, `GCP_SECURITY_POLICY` |
509
+
510
+ ### Priority Order
511
+
512
+ **Service name:** `OTEL_SERVICE_NAME` > `SECURENOW_APPID` > auto-generated
513
+
514
+ **Endpoint:** `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` > `OTEL_EXPORTER_OTLP_ENDPOINT` > `SECURENOW_INSTANCE` > `https://freetrial.securenow.ai:4318`
515
+
516
+ ---
517
+
518
+ ## Recipes for Agentic AI
519
+
520
+ ### Add Observability to an Existing Express App
521
+
522
+ ```bash
523
+ npm install securenow
524
+ ```
525
+
526
+ Create `.env`:
527
+ ```
528
+ SECURENOW_APPID=my-express-api
529
+ SECURENOW_INSTANCE=https://your-collector:4318
530
+ SECURENOW_LOGGING_ENABLED=1
531
+ SECURENOW_CAPTURE_BODY=1
532
+ ```
533
+
534
+ Update `package.json`:
535
+ ```json
536
+ { "scripts": { "start": "node -r securenow/register src/index.js" } }
537
+ ```
538
+
539
+ No code changes to the application needed.
540
+
541
+ ### Add Observability + Firewall to a Next.js App
542
+
543
+ ```bash
544
+ npm install securenow
545
+ npx securenow init --key snk_live_abc123...
546
+ ```
547
+
548
+ The `init` command creates `instrumentation.ts` and suggests `next.config` changes. Then set env vars in `.env.local`:
549
+
550
+ ```
551
+ SECURENOW_APPID=my-nextjs-app
552
+ SECURENOW_INSTANCE=https://your-collector:4318
553
+ SECURENOW_API_KEY=snk_live_abc123...
554
+ SECURENOW_CAPTURE_BODY=1
555
+ ```
556
+
557
+ ### Enable Firewall With Zero Tracing Overhead
558
+
559
+ For apps that only need IP blocking:
560
+
561
+ ```bash
562
+ node -r securenow/firewall-only app.js
563
+ ```
564
+
565
+ Set `SECURENOW_API_KEY` in the environment. No other configuration needed.
566
+
567
+ ### Production Hardened Configuration
568
+
569
+ ```bash
570
+ SECURENOW_APPID=prod-api
571
+ SECURENOW_INSTANCE=https://collector.prod.internal:4318
572
+ SECURENOW_NO_UUID=1
573
+ SECURENOW_STRICT=1
574
+ SECURENOW_LOGGING_ENABLED=1
575
+ SECURENOW_CAPTURE_BODY=0
576
+ SECURENOW_API_KEY=snk_live_abc123...
577
+ SECURENOW_FIREWALL_TCP=1
578
+ SECURENOW_FIREWALL_SYNC_INTERVAL=30
579
+ SECURENOW_FIREWALL_FAIL_MODE=open
580
+ OTEL_LOG_LEVEL=error
581
+ NODE_ENV=production
582
+ ```
583
+
584
+ ### Instrument a Docker Container
585
+
586
+ ```dockerfile
587
+ FROM node:20-slim
588
+ WORKDIR /app
589
+ COPY package*.json ./
590
+ RUN npm ci --omit=dev
591
+ COPY . .
592
+
593
+ ENV SECURENOW_APPID=my-service
594
+ ENV SECURENOW_INSTANCE=http://otel-collector:4318
595
+ ENV SECURENOW_NO_UUID=1
596
+ ENV SECURENOW_API_KEY=snk_live_abc123...
597
+
598
+ CMD ["node", "-r", "securenow/register", "src/index.js"]
599
+ ```
600
+
601
+ ### Kubernetes with Separate Trace/Log Collectors
602
+
603
+ ```bash
604
+ SECURENOW_APPID=k8s-service
605
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://tempo:4318/v1/traces
606
+ OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://loki:4318/v1/logs
607
+ SECURENOW_LOGGING_ENABLED=1
608
+ SECURENOW_NO_UUID=1
609
+ ```
610
+
611
+ ---
612
+
613
+ ## Verification
614
+
615
+ On startup, securenow logs its configuration:
616
+
617
+ ```
618
+ [securenow] pid=12345 SECURENOW_APPID="my-app" → service.name=my-app
619
+ [securenow] OTel SDK started → https://collector:4318/v1/traces
620
+ [securenow] Logging: ENABLED → https://collector:4318/v1/logs
621
+ [securenow] Request body capture: ENABLED (max: 10240 bytes)
622
+ [securenow] Firewall: ENABLED
623
+ [securenow] Firewall: synced 142 blocked IPs
624
+ ```
625
+
626
+ Use `OTEL_LOG_LEVEL=debug` and `SECURENOW_TEST_SPAN=1` to troubleshoot connectivity issues.
627
+
628
+ **CLI equivalent** (works without booting the SDK — useful when the app won't start):
629
+
630
+ ```bash
631
+ securenow env # show resolved service name, endpoints, env vars
632
+ securenow doctor # probe OTLP + API endpoints, exits 1 on failure
633
+ securenow test-span # send a real span to the collector
634
+ ```