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.
- package/CONSUMING-APPS-GUIDE.md +455 -0
- package/NPM_README.md +2029 -0
- package/README.md +297 -40
- package/SKILL-API.md +634 -0
- package/SKILL-CLI.md +454 -0
- package/cidr.js +83 -0
- package/cli/apps.js +585 -0
- package/cli/auth.js +280 -0
- package/cli/client.js +115 -0
- package/cli/config.js +173 -0
- package/cli/diagnostics.js +387 -0
- package/cli/firewall.js +100 -0
- package/cli/fp.js +638 -0
- package/cli/init.js +201 -0
- package/cli/monitor.js +440 -0
- package/cli/run.js +148 -0
- package/cli/security.js +980 -0
- package/cli/ui.js +386 -0
- package/cli/utils.js +127 -0
- package/cli.js +466 -455
- package/console-instrumentation.js +147 -136
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +1377 -455
- package/docs/API-KEYS-GUIDE.md +233 -0
- package/docs/ARCHITECTURE.md +3 -3
- package/docs/AUTO-BODY-CAPTURE.md +1 -1
- package/docs/AUTO-SETUP-SUMMARY.md +331 -0
- package/docs/AUTO-SETUP.md +4 -4
- package/docs/AUTOMATIC-IP-CAPTURE.md +5 -5
- package/docs/BODY-CAPTURE-FIX.md +261 -0
- package/docs/BODY-CAPTURE-QUICKSTART.md +2 -2
- package/docs/CHANGELOG-NEXTJS.md +1 -35
- package/docs/COMPLETION-REPORT.md +408 -0
- package/docs/CUSTOMER-GUIDE.md +16 -16
- package/docs/EASIEST-SETUP.md +5 -5
- package/docs/ENVIRONMENT-VARIABLES.md +880 -652
- package/docs/EXPRESS-BODY-CAPTURE.md +13 -12
- package/docs/EXPRESS-SETUP-GUIDE.md +719 -720
- package/docs/FINAL-SOLUTION.md +335 -0
- package/docs/FIREWALL-GUIDE.md +426 -0
- package/docs/IMPLEMENTATION-SUMMARY.md +410 -0
- package/docs/INDEX.md +22 -4
- package/docs/LOGGING-GUIDE.md +701 -708
- package/docs/LOGGING-QUICKSTART.md +234 -255
- package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +323 -0
- package/docs/NEXTJS-BODY-CAPTURE.md +2 -2
- package/docs/NEXTJS-GUIDE.md +14 -14
- package/docs/NEXTJS-QUICKSTART.md +1 -1
- package/docs/NEXTJS-SETUP-COMPLETE.md +795 -0
- package/docs/NEXTJS-WRAPPER-APPROACH.md +1 -1
- package/docs/NUXT-GUIDE.md +166 -0
- package/docs/QUICKSTART-BODY-CAPTURE.md +2 -2
- package/docs/REDACTION-EXAMPLES.md +1 -1
- package/docs/REQUEST-BODY-CAPTURE.md +19 -10
- package/docs/SOLUTION-SUMMARY.md +312 -0
- package/docs/VERCEL-OTEL-MIGRATION.md +3 -3
- package/examples/README.md +6 -6
- package/examples/instrumentation-with-auto-capture.ts +1 -1
- package/examples/nextjs-env-example.txt +2 -2
- package/examples/nextjs-instrumentation.js +1 -1
- package/examples/nextjs-instrumentation.ts +1 -1
- package/examples/nextjs-with-logging-example.md +6 -6
- package/examples/nextjs-with-options.ts +1 -1
- package/examples/test-nextjs-setup.js +1 -1
- package/firewall-cloud.js +212 -0
- package/firewall-iptables.js +139 -0
- package/firewall-only.js +38 -0
- package/firewall-tcp.js +74 -0
- package/firewall.js +720 -0
- package/free-trial-banner.js +174 -0
- package/nextjs-auto-capture.js +199 -207
- package/nextjs-middleware.js +186 -181
- package/nextjs-webpack-config.js +88 -53
- package/nextjs-wrapper.js +158 -158
- package/nextjs.d.ts +1 -1
- package/nextjs.js +639 -647
- package/nuxt-server-plugin.mjs +423 -0
- package/nuxt.d.ts +60 -0
- package/nuxt.mjs +75 -0
- package/package.json +186 -164
- package/postinstall.js +6 -6
- package/register.d.ts +1 -1
- package/register.js +39 -4
- package/resolve-ip.js +77 -0
- package/tracing.d.ts +2 -1
- package/tracing.js +295 -34
- package/web-vite.mjs +239 -156
- 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
|
+
```
|