devfortress-sdk 4.2.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/LICENSE +63 -0
- package/README.md +474 -0
- package/bin/devfortress-init.js +206 -0
- package/dist/browser.d.ts +61 -0
- package/dist/browser.js +184 -0
- package/dist/circuit-breaker.d.ts +68 -0
- package/dist/circuit-breaker.js +116 -0
- package/dist/client.d.ts +26 -0
- package/dist/client.js +98 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +78 -0
- package/dist/middleware/express.d.ts +9 -0
- package/dist/middleware/express.js +236 -0
- package/dist/quick.d.ts +37 -0
- package/dist/quick.js +135 -0
- package/dist/types.d.ts +217 -0
- package/dist/types.js +12 -0
- package/package.json +101 -0
- package/src/middleware/fastapi.py +232 -0
- package/src/middleware/flask.py +213 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Licensor: Duncan Ndegwa / DevFortress
|
|
4
|
+
devfortress.net
|
|
5
|
+
Nairobi, Kenya
|
|
6
|
+
|
|
7
|
+
Licensed Work: DevFortress SDK
|
|
8
|
+
The Licensed Work is (c) 2026 Duncan Ndegwa
|
|
9
|
+
|
|
10
|
+
Change Date: Four years from the date each version of the
|
|
11
|
+
Licensed Work is first publicly distributed.
|
|
12
|
+
For devfortress-sdk@4.0.0, the Change Date
|
|
13
|
+
is 2030-01-01.
|
|
14
|
+
|
|
15
|
+
Change License: Apache License, Version 2.0
|
|
16
|
+
|
|
17
|
+
Additional Use Grant: You may use the Licensed Work to monitor,
|
|
18
|
+
observe, and protect your own applications,
|
|
19
|
+
APIs, and AI agents for security threats,
|
|
20
|
+
provided that you do not use the Licensed Work
|
|
21
|
+
to provide a competing commercial security
|
|
22
|
+
monitoring service or platform to third parties.
|
|
23
|
+
|
|
24
|
+
For commercial licensing, enterprise use, or questions:
|
|
25
|
+
support@devfortress.net
|
|
26
|
+
|
|
27
|
+
-----------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
Business Source License 1.1
|
|
30
|
+
|
|
31
|
+
Terms
|
|
32
|
+
|
|
33
|
+
The Licensor hereby grants you the right to copy, modify, create
|
|
34
|
+
derivative works, redistribute, and make non-production use of the
|
|
35
|
+
Licensed Work. The Licensor may make an Additional Use Grant, above,
|
|
36
|
+
permitting limited production use.
|
|
37
|
+
|
|
38
|
+
Effective on the Change Date, or the fourth anniversary of the first
|
|
39
|
+
publicly available distribution of a specific version of the Licensed
|
|
40
|
+
Work under this License, whichever comes first, the Licensor hereby
|
|
41
|
+
grants you rights under the terms of the Change License, and the
|
|
42
|
+
rights granted in the paragraph above terminate.
|
|
43
|
+
|
|
44
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
45
|
+
currently in effect as described in this License, you must purchase a
|
|
46
|
+
commercial license from the Licensor, refrain from using the Licensed
|
|
47
|
+
Work, or make arrangements with the Licensor for a separate license.
|
|
48
|
+
|
|
49
|
+
For avoidance of doubt, a "Competing Service" means any commercial
|
|
50
|
+
product or service that provides API security monitoring, application
|
|
51
|
+
security monitoring, AI agent security monitoring, session threat
|
|
52
|
+
detection, automated threat response, or credential isolation
|
|
53
|
+
functionality to third parties.
|
|
54
|
+
|
|
55
|
+
Notice
|
|
56
|
+
|
|
57
|
+
The Business Source License (this document, or the "License") is not
|
|
58
|
+
an Open Source license. However, the Licensed Work will eventually be
|
|
59
|
+
made available under an Open Source License, as stated in this License.
|
|
60
|
+
|
|
61
|
+
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights
|
|
62
|
+
Reserved. "Business Source License" is a trademark of MariaDB
|
|
63
|
+
Corporation Ab.
|
package/README.md
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# devfortress-sdk
|
|
2
|
+
|
|
3
|
+
The developer-first **Application and API security** SDK that stops attacks automatically — not just monitors them.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/devfortress-sdk)
|
|
6
|
+
[](https://github.com/duncan982/devfortress/blob/main/packages/devfortress-sdk/LICENSE)
|
|
7
|
+
|
|
8
|
+
## 🔒 Privacy First — What We Collect vs. What We Never Collect
|
|
9
|
+
|
|
10
|
+
| ✅ We Collect | ❌ We Never Collect |
|
|
11
|
+
| ------------------------------------ | --------------------------------------- |
|
|
12
|
+
| IP address (hashable in strict mode) | Request/response body content |
|
|
13
|
+
| HTTP method & path | Cookies or session data |
|
|
14
|
+
| Status code & response time | Authorization headers or tokens |
|
|
15
|
+
| User agent (first 200 chars) | Query string values or form data |
|
|
16
|
+
| Timestamp | User PII (names, emails, phone numbers) |
|
|
17
|
+
| Session identifiers (anonymised) | Real session tokens |
|
|
18
|
+
| | Database queries or source code |
|
|
19
|
+
|
|
20
|
+
> **Your real session tokens never leave your server.** DevFortress uses a proprietary aliasing mechanism — the platform never sees or stores your actual tokens. [Full transparency →](https://devfortress.net/privacy/data-collected)
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install devfortress-sdk
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## ⚡ Zero-Config Quick Start (under 3 minutes)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx devfortress-init
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or one line in your code:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import df from 'devfortress-sdk/quick';
|
|
38
|
+
df.init({ apiKey: 'df_your_key' });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Privacy-Strict Mode
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
df.init({ apiKey: 'df_...', privacy: 'strict' });
|
|
45
|
+
// IPs are SHA-256 hashed before sending, user agents omitted
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Debug Mode — See Exactly What's Sent
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
df.init({ apiKey: 'df_...', debug: true });
|
|
52
|
+
// Console: [DF →] DevFortress initialized (framework: express, privacy: standard)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Data Snapshot — Inspect Before Sending
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { getDataSnapshot } from 'devfortress-sdk/quick';
|
|
59
|
+
console.log(getDataSnapshot(req));
|
|
60
|
+
// { collected: { ip, method, path, ... }, neverCollected: ['Request body', ...] }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
### Express.js Middleware (Automatic)
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import express from 'express';
|
|
69
|
+
import { devfortressMiddleware } from 'devfortress-sdk';
|
|
70
|
+
|
|
71
|
+
const app = express();
|
|
72
|
+
|
|
73
|
+
// Add DevFortress monitoring — automatically detects threats
|
|
74
|
+
app.use(
|
|
75
|
+
devfortressMiddleware({
|
|
76
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
app.get('/api/users', (req, res) => {
|
|
81
|
+
res.json({ users: [] });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
app.listen(3000);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Manual Event Tracking (Node.js)
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { DevFortressClient } from 'devfortress-sdk';
|
|
91
|
+
|
|
92
|
+
const client = new DevFortressClient({
|
|
93
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Track a security event
|
|
97
|
+
await client.trackEvent({
|
|
98
|
+
eventType: 'auth_failure',
|
|
99
|
+
ip: req.ip || '0.0.0.0',
|
|
100
|
+
userAgent: req.get('user-agent'),
|
|
101
|
+
metadata: {
|
|
102
|
+
username: req.body.username,
|
|
103
|
+
reason: 'invalid_password',
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Browser Client
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { DevFortressBrowserClient } from 'devfortress-sdk/browser';
|
|
112
|
+
|
|
113
|
+
const client = new DevFortressBrowserClient({
|
|
114
|
+
apiKey: 'your-publishable-key', // Use a PUBLIC/scoped key — visible in DevTools
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Install global error handler
|
|
118
|
+
const cleanup = client.installGlobalErrorHandler();
|
|
119
|
+
|
|
120
|
+
// Track API failures
|
|
121
|
+
client.trackApiFailure('/api/data', 500, 'GET');
|
|
122
|
+
|
|
123
|
+
// Cleanup when done
|
|
124
|
+
cleanup();
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
> ⚠️ **Browser Security Notice:** The API key is visible to end users via browser DevTools. Use a scoped/publishable key with limited permissions — never use your secret admin key in browser builds.
|
|
128
|
+
|
|
129
|
+
## Features
|
|
130
|
+
|
|
131
|
+
- 🚀 **Zero-config Express.js middleware** — automatic threat detection
|
|
132
|
+
- 🔒 **Pattern detection** — SQL injection, XSS, path traversal, brute force
|
|
133
|
+
- 📊 **Real-time security insights** — events stream to your DevFortress dashboard
|
|
134
|
+
- ⚡ **Non-blocking** — async event capture, never slows your API
|
|
135
|
+
- 🎯 **Custom event tracking** — send any security-relevant event
|
|
136
|
+
- 🌐 **Multi-platform** — Node.js, Browser, Express, FastAPI, Flask
|
|
137
|
+
- 🔧 **Type-safe** — full TypeScript support with exported types
|
|
138
|
+
- 🤖 **Agent Security (v3.2)** — observe AI agent tool calls, per-agent credential isolation, behavioral baselines, anomaly detection, scope enforcement
|
|
139
|
+
- 🔑 **Session Privacy** — Encrypted session identifiers, secure reverse-lookup, fallback cache
|
|
140
|
+
- 🛡️ **Closed-Loop Response** — automatic threat detection → block → webhook notification → action report
|
|
141
|
+
- 🏭 **Internal Mode (v3.3)** — Sub-millisecond inline protection with air-gap mode and zero external dependencies
|
|
142
|
+
- 🔄 **Hybrid Mode (v4.0)** — Local evaluation first, external enrichment with automatic failover
|
|
143
|
+
- ⚡ **Resilient Failover (v4.0)** — Automatic failover for hybrid mode resilience
|
|
144
|
+
- 🎫 **Tier Gating (v4.0)** — Starter/Pro/Enterprise subscription enforcement: modes, blocking, event limits at SDK level
|
|
145
|
+
- 📋 **Unified Audit Trail (v4.0)** — single timeline merging internal/external/hybrid decisions with stats, histograms, export
|
|
146
|
+
|
|
147
|
+
## 🤖 AI Agent Security (v3.2)
|
|
148
|
+
|
|
149
|
+
Protect AI agents (LangChain, OpenAI, Anthropic, custom) from prompt injection, credential theft, and scope escalation.
|
|
150
|
+
|
|
151
|
+
### Agent Tool Observability
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { DevFortress, AgentAdapter } from 'devfortress-sdk';
|
|
155
|
+
|
|
156
|
+
const df = new DevFortress({ apiKey: process.env.DEVFORTRESS_API_KEY! });
|
|
157
|
+
const agent = new AgentAdapter(df, {
|
|
158
|
+
agentId: 'research-agent',
|
|
159
|
+
agentName: 'Research Assistant',
|
|
160
|
+
sanitizeInputs: true, // Auto-redact keys/tokens/secrets
|
|
161
|
+
onFlagged: (toolCall, result) => {
|
|
162
|
+
console.error(`Tool ${toolCall.tool} flagged: risk=${result.riskScore}`);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// LangChain integration
|
|
167
|
+
await agent.observeLangChainTool(
|
|
168
|
+
'web_search',
|
|
169
|
+
{ query: 'test' },
|
|
170
|
+
{ model: 'gpt-4o' }
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// OpenAI function calling
|
|
174
|
+
await agent.observeOpenAIToolCall({
|
|
175
|
+
function: { name: 'get_weather', arguments: '{"location":"London"}' },
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Raw HTTP tool call
|
|
179
|
+
await agent.observeHttpToolCall('https://api.example.com/data', 'POST', {
|
|
180
|
+
statusCode: 200,
|
|
181
|
+
durationMs: 150,
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Agent Credential Isolation
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { DevFortress } from 'devfortress-sdk';
|
|
189
|
+
|
|
190
|
+
const df = new DevFortress({
|
|
191
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
192
|
+
appId: 'my-app',
|
|
193
|
+
mode: 'internal',
|
|
194
|
+
tier: 'enterprise',
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Isolate agent credentials — real keys never leave your server
|
|
198
|
+
const alias = await df.isolateCredential('sk-real-api-key-here', 'agent-1');
|
|
199
|
+
|
|
200
|
+
// Quarantine an agent (preserves session for forensics)
|
|
201
|
+
await df.quarantineAgent('agent-1', 'Suspicious tool usage');
|
|
202
|
+
|
|
203
|
+
// Full revocation — compromised agent
|
|
204
|
+
await df.revokeAgentAccess('agent-1', 'active_threat');
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Behavioral Baseline & Anomaly Detection
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { DevFortress } from 'devfortress-sdk';
|
|
211
|
+
|
|
212
|
+
const df = new DevFortress({
|
|
213
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
214
|
+
appId: 'my-app',
|
|
215
|
+
tier: 'enterprise',
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Register handler for anomalies
|
|
219
|
+
df.onAnomaly((signal) => {
|
|
220
|
+
if (signal.severity === 'critical') {
|
|
221
|
+
// Auto-quarantine agent on critical anomaly
|
|
222
|
+
df.quarantineAgent(signal.agentId, signal.description);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Record sessions to build baseline (auto after 5 sessions)
|
|
227
|
+
df.recordSession({ agentId: 'agent-1', sessionId: 's1', toolCalls: [...] });
|
|
228
|
+
|
|
229
|
+
// Detect anomalies per tool call
|
|
230
|
+
const signals = df.analyzeToolCall('agent-1', 'delete_database', 1_000_000);
|
|
231
|
+
// → [{ type: 'scope_deviation', severity: 'medium' },
|
|
232
|
+
// { type: 'data_volume_anomaly', severity: 'high' }]
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Scope Enforcement (Prompt Injection Defence)
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { DevFortress } from 'devfortress-sdk';
|
|
239
|
+
|
|
240
|
+
const df = new DevFortress({
|
|
241
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
242
|
+
appId: 'my-app',
|
|
243
|
+
tier: 'enterprise',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Define what tools an agent is allowed to use
|
|
247
|
+
df.defineAgentScope('agent-1', ['web_search', 'calculator', 'format'], true);
|
|
248
|
+
|
|
249
|
+
// Check before execution
|
|
250
|
+
if (!df.isToolAllowed('agent-1', 'shell_exec')) {
|
|
251
|
+
// CRITICAL: unsanctioned tool — likely prompt injection
|
|
252
|
+
// The anomaly detector also fires this automatically
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Configuration
|
|
257
|
+
|
|
258
|
+
### Middleware Options
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
interface DevFortressMiddlewareOptions {
|
|
262
|
+
apiKey: string; // Required: Your DevFortress API key
|
|
263
|
+
endpoint?: string; // Default: https://www.devfortress.net/api/events/ingest
|
|
264
|
+
captureBody?: boolean; // Default: false — capture request body
|
|
265
|
+
captureHeaders?: boolean; // Default: false — capture request headers
|
|
266
|
+
excludePaths?: string[]; // Paths to exclude from monitoring (e.g. ['/health'])
|
|
267
|
+
sanitize?: (data) => data; // Sanitize metadata before sending
|
|
268
|
+
onRequest?: (req) => event; // Custom event detection callback
|
|
269
|
+
onError?: (error) => void; // Error handler for failed event sends
|
|
270
|
+
timeout?: number; // Request timeout in ms (default: 5000)
|
|
271
|
+
retries?: number; // Retry failed requests (default: 3)
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
> ⚠️ **Privacy Warning:** When `captureHeaders` is `true`, headers including `Authorization`, `Cookie`, and session tokens are sent to DevFortress. When `captureBody` is `true`, raw request bodies (which may contain passwords, credit cards, etc.) are captured. Always use the `sanitize` callback to strip sensitive data.
|
|
276
|
+
|
|
277
|
+
### Client Options
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
interface DevFortressClientOptions {
|
|
281
|
+
apiKey: string; // Required: Your DevFortress API key
|
|
282
|
+
endpoint?: string; // Default: https://www.devfortress.net/api/events/ingest
|
|
283
|
+
timeout?: number; // Request timeout in ms (default: 5000)
|
|
284
|
+
retries?: number; // Retry count (default: 3, exponential backoff)
|
|
285
|
+
debug?: boolean; // Enable debug logging (default: false)
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Event Types
|
|
290
|
+
|
|
291
|
+
The SDK automatically detects and reports:
|
|
292
|
+
|
|
293
|
+
| Event Type | Description | Auto-Detected |
|
|
294
|
+
| ----------------------- | ---------------------------------- | ------------- |
|
|
295
|
+
| `auth_failure` | Failed authentication (401/403) | ✅ |
|
|
296
|
+
| `validation_error` | Input validation errors (400/422) | ✅ |
|
|
297
|
+
| `rate_limit_exceeded` | Rate limit violations (429) | ✅ |
|
|
298
|
+
| `5xx_error` | Server errors | ✅ |
|
|
299
|
+
| `4xx_error` | Client errors | ✅ |
|
|
300
|
+
| `suspicious_pattern` | SQL injection, XSS, path traversal | ✅ |
|
|
301
|
+
| `sql_injection_attempt` | SQL injection detected | Manual |
|
|
302
|
+
| `xss_attempt` | XSS attack detected | Manual |
|
|
303
|
+
| `custom` | Any custom security event | Manual |
|
|
304
|
+
|
|
305
|
+
## Python Middleware
|
|
306
|
+
|
|
307
|
+
### FastAPI / Starlette
|
|
308
|
+
|
|
309
|
+
Copy `src/middleware/fastapi.py` into your project:
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from devfortress_middleware import DevFortressMiddleware
|
|
313
|
+
|
|
314
|
+
app = FastAPI()
|
|
315
|
+
app.add_middleware(
|
|
316
|
+
DevFortressMiddleware,
|
|
317
|
+
api_key="your-api-key",
|
|
318
|
+
endpoint="https://www.devfortress.net/api/events/ingest"
|
|
319
|
+
)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Flask
|
|
323
|
+
|
|
324
|
+
Copy `src/middleware/flask.py` into your project:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from devfortress_middleware import DevFortressFlask
|
|
328
|
+
|
|
329
|
+
app = Flask(__name__)
|
|
330
|
+
devfortress = DevFortressFlask(
|
|
331
|
+
app,
|
|
332
|
+
api_key="your-api-key",
|
|
333
|
+
endpoint="https://www.devfortress.net/api/events/ingest"
|
|
334
|
+
)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Security Best Practices
|
|
338
|
+
|
|
339
|
+
1. **API Key Management** — Store keys in environment variables, never commit them
|
|
340
|
+
2. **Header/Body Capture** — Both default to `false`. Enable only with a `sanitize` callback
|
|
341
|
+
3. **Browser Keys** — Use scoped/publishable keys for browser builds (visible in DevTools)
|
|
342
|
+
4. **HTTPS Only** — The SDK warns if a non-HTTPS endpoint is configured
|
|
343
|
+
5. **Error Handling** — Implement `onError` to prevent monitoring failures from affecting your API
|
|
344
|
+
6. **Rate Limiting** — SDK respects rate limits (1000 events/minute per project)
|
|
345
|
+
|
|
346
|
+
## Advanced Usage
|
|
347
|
+
|
|
348
|
+
### Custom Threat Detection
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
app.use(
|
|
352
|
+
devfortressMiddleware({
|
|
353
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
354
|
+
onRequest: req => {
|
|
355
|
+
// Custom threat detection logic
|
|
356
|
+
if (isCustomThreat(req)) {
|
|
357
|
+
return {
|
|
358
|
+
eventType: 'custom',
|
|
359
|
+
severity: 'HIGH',
|
|
360
|
+
reason: 'Custom rule triggered',
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
},
|
|
365
|
+
})
|
|
366
|
+
);
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Sanitizing Sensitive Data
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
app.use(
|
|
373
|
+
devfortressMiddleware({
|
|
374
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
375
|
+
captureBody: true,
|
|
376
|
+
captureHeaders: true,
|
|
377
|
+
sanitize: data => {
|
|
378
|
+
// Strip sensitive fields before sending to DevFortress
|
|
379
|
+
const sanitized = { ...data };
|
|
380
|
+
if (sanitized.body) {
|
|
381
|
+
delete (sanitized.body as Record<string, unknown>).password;
|
|
382
|
+
delete (sanitized.body as Record<string, unknown>).creditCard;
|
|
383
|
+
}
|
|
384
|
+
if (sanitized.headers) {
|
|
385
|
+
delete (sanitized.headers as Record<string, unknown>).authorization;
|
|
386
|
+
delete (sanitized.headers as Record<string, unknown>).cookie;
|
|
387
|
+
}
|
|
388
|
+
return sanitized;
|
|
389
|
+
},
|
|
390
|
+
})
|
|
391
|
+
);
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Required Endpoints
|
|
395
|
+
|
|
396
|
+
The SDK communicates with these DevFortress platform endpoints (all must be accessible):
|
|
397
|
+
|
|
398
|
+
| Endpoint | Method | Purpose |
|
|
399
|
+
| -------------------------- | -------- | ------------------------ |
|
|
400
|
+
| `/api/events/ingest` | POST | Send security events |
|
|
401
|
+
| `/api/events/blocked` | GET | Check if IP is blocked |
|
|
402
|
+
| `/api/events/action-taken` | POST | Report actions taken |
|
|
403
|
+
| `/api/events/test-ips` | GET/POST | Manage test IP whitelist |
|
|
404
|
+
|
|
405
|
+
Base URL: `https://www.devfortress.net`
|
|
406
|
+
|
|
407
|
+
> **Note:** In Internal mode (`mode: 'internal'`), no external endpoints are called. In Hybrid mode, endpoints are called only for allowed traffic with automatic failover to local-only processing.
|
|
408
|
+
|
|
409
|
+
## 🔄 Three-Mode Closed-Loop (v4.0)
|
|
410
|
+
|
|
411
|
+
SDK v4.0.0 introduces three closed-loop protection modes:
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
import { DevFortress } from 'devfortress-sdk';
|
|
415
|
+
|
|
416
|
+
// External mode — cloud-based analysis (default for Starter/Pro)
|
|
417
|
+
const dfExternal = new DevFortress({
|
|
418
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
419
|
+
appId: 'my-app',
|
|
420
|
+
mode: 'external',
|
|
421
|
+
tier: 'pro',
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Internal mode — air-gapped, zero network calls (Enterprise only)
|
|
425
|
+
const dfInternal = new DevFortress({
|
|
426
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
427
|
+
appId: 'my-app',
|
|
428
|
+
mode: 'internal',
|
|
429
|
+
tier: 'enterprise',
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// Hybrid mode — local first, cloud enrichment with automatic failover
|
|
433
|
+
const dfHybrid = new DevFortress({
|
|
434
|
+
apiKey: process.env.DEVFORTRESS_API_KEY!,
|
|
435
|
+
appId: 'my-app',
|
|
436
|
+
mode: 'hybrid',
|
|
437
|
+
tier: 'enterprise',
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// All modes use the same observe() API
|
|
441
|
+
const result = await dfHybrid.observe({
|
|
442
|
+
ip: '1.2.3.4',
|
|
443
|
+
endpoint: '/api/users',
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// Unified audit trail — one view across all modes
|
|
447
|
+
const stats = dfHybrid.getAudit().getStats();
|
|
448
|
+
// { internalDecisions, externalDecisions, hybridDecisions, fallbackEvents, ... }
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Testing Your Integration
|
|
452
|
+
|
|
453
|
+
See the full [SDK Integration Guide](https://github.com/duncan982/devfortress/blob/main/docs/sdk-integration-guide.md) for step-by-step testing and troubleshooting.
|
|
454
|
+
|
|
455
|
+
## Pricing
|
|
456
|
+
|
|
457
|
+
| Tier | Events/Month | Automated Actions | Retention |
|
|
458
|
+
| ---------------- | :----------: | :---------------: | :-------: |
|
|
459
|
+
| Starter ($99/mo) | 50K | ❌ alerts only | 7 days |
|
|
460
|
+
| Pro ($199/mo) | 500K | 500/mo | 30 days |
|
|
461
|
+
| Team ($499/mo) | 5M | 5K/mo | 90 days |
|
|
462
|
+
|
|
463
|
+
## Support
|
|
464
|
+
|
|
465
|
+
- 📖 [SDK Integration Guide](https://github.com/duncan982/devfortress/blob/main/docs/sdk-integration-guide.md)
|
|
466
|
+
- 📋 [Full SDK Specification](https://github.com/duncan982/devfortress/blob/main/devfortress-updated/devfortress-sdk-spec.md)
|
|
467
|
+
- 💬 [GitHub Discussions](https://github.com/duncan982/devfortress/discussions)
|
|
468
|
+
- 🐛 [Report Issues](https://github.com/duncan982/devfortress/issues)
|
|
469
|
+
|
|
470
|
+
## License
|
|
471
|
+
|
|
472
|
+
BUSL-1.1 © DevFortress (devfortress.net)
|
|
473
|
+
|
|
474
|
+
See [LICENSE](./LICENSE) for details. The Change License is Apache-2.0, effective 2030-01-01.
|