@neurosec/sentry 1.0.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 +21 -0
- package/README.md +118 -0
- package/bin/cli.js +18 -0
- package/bin/sentryd.js +19 -0
- package/dist/api.d.ts +21 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +161 -0
- package/dist/api.js.map +1 -0
- package/dist/audit.d.ts +18 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +114 -0
- package/dist/audit.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +255 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +54 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +160 -0
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts +5 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +279 -0
- package/dist/discovery.js.map +1 -0
- package/dist/enforcement/enforcement-engine.d.ts +37 -0
- package/dist/enforcement/enforcement-engine.d.ts.map +1 -0
- package/dist/enforcement/enforcement-engine.js +325 -0
- package/dist/enforcement/enforcement-engine.js.map +1 -0
- package/dist/enforcement/file-monitor.d.ts +4 -0
- package/dist/enforcement/file-monitor.d.ts.map +1 -0
- package/dist/enforcement/file-monitor.js +114 -0
- package/dist/enforcement/file-monitor.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +248 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +17 -0
- package/dist/logger.js.map +1 -0
- package/dist/sandbox/index.d.ts +14 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +91 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/linux-sandbox.d.ts +21 -0
- package/dist/sandbox/linux-sandbox.d.ts.map +1 -0
- package/dist/sandbox/linux-sandbox.js +186 -0
- package/dist/sandbox/linux-sandbox.js.map +1 -0
- package/dist/sandbox/macos-sandbox.d.ts +17 -0
- package/dist/sandbox/macos-sandbox.d.ts.map +1 -0
- package/dist/sandbox/macos-sandbox.js +145 -0
- package/dist/sandbox/macos-sandbox.js.map +1 -0
- package/dist/setup.d.ts +14 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +220 -0
- package/dist/setup.js.map +1 -0
- package/dist/skill-authz/skill-evaluator.d.ts +20 -0
- package/dist/skill-authz/skill-evaluator.d.ts.map +1 -0
- package/dist/skill-authz/skill-evaluator.js +159 -0
- package/dist/skill-authz/skill-evaluator.js.map +1 -0
- package/dist/skill-authz/skill-scanner.d.ts +18 -0
- package/dist/skill-authz/skill-scanner.d.ts.map +1 -0
- package/dist/skill-authz/skill-scanner.js +169 -0
- package/dist/skill-authz/skill-scanner.js.map +1 -0
- package/dist/telemetry.d.ts +18 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +106 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +127 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +209 -0
- package/dist/types.js.map +1 -0
- package/package.json +69 -0
- package/scripts/install-sentry-macos.sh +238 -0
- package/scripts/install-sentry.sh +253 -0
- package/scripts/postinstall.js +191 -0
- package/scripts/prepack.js +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NeuroSec
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# NeuroShield Sentry
|
|
2
|
+
|
|
3
|
+
**Host-level agent protection daemon.** Detects AI agent processes running on your infrastructure, sandboxes them with kernel-level isolation, and enforces policies on filesystem access, network egress, syscalls, and skill/tool execution.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npm install -g @neurosec/sentry
|
|
7
|
+
neuroshield-sentry setup
|
|
8
|
+
sudo neuroshield-sentry install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## How It Works
|
|
12
|
+
|
|
13
|
+
The Sentry daemon runs on each host and connects to your **NeuroSec** security platform:
|
|
14
|
+
|
|
15
|
+
1. **Discovery** — scans `/proc/*` for processes matching agent framework signatures (LangChain, CrewAI, Claude Code, MCP, AutoGen, etc.)
|
|
16
|
+
2. **Sandbox** — applies cgroups v2 (CPU/memory limits), seccomp (syscall allowlist), and Landlock (filesystem path restrictions) to each agent process
|
|
17
|
+
3. **Enforcement** — evaluates every file access, network connection, and syscall against policy. Monitor mode = log-only. Enforce mode = block violations. Quarantine mode = kill on repeat offenses
|
|
18
|
+
4. **Skill Authorization** — detects tool definitions from MCP manifests, env vars, and process args. High-risk skills (shell exec, file write, database queries) require approval or are blocked
|
|
19
|
+
5. **Audit** — all decisions are logged as JSON Lines with auto-rotation and SIEM-ready format
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Install globally
|
|
25
|
+
npm install -g @neurosec/sentry
|
|
26
|
+
|
|
27
|
+
# Interactive setup (prompts for NeuroSec URL, org ID, token)
|
|
28
|
+
neuroshield-sentry setup
|
|
29
|
+
|
|
30
|
+
# Or non-interactive for automation
|
|
31
|
+
neuroshield-sentry setup \
|
|
32
|
+
--org=org_abc123 \
|
|
33
|
+
--token=nst_yourtoken \
|
|
34
|
+
--mode=enforce \
|
|
35
|
+
--url=https://api.neurosec.ai
|
|
36
|
+
|
|
37
|
+
# Install as system service (systemd on Linux, launchd on macOS)
|
|
38
|
+
sudo neuroshield-sentry install
|
|
39
|
+
|
|
40
|
+
# Check status
|
|
41
|
+
neuroshield-sentry status
|
|
42
|
+
|
|
43
|
+
# View real-time enforcement decisions
|
|
44
|
+
neuroshield-sentry logs -f
|
|
45
|
+
|
|
46
|
+
# Start the daemon manually
|
|
47
|
+
sudo neuroshield-sentryd
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## CLI Reference
|
|
51
|
+
|
|
52
|
+
| Command | Description |
|
|
53
|
+
|---------|-------------|
|
|
54
|
+
| `setup` | Generate sentry.yaml configuration |
|
|
55
|
+
| `install` | Install system service (systemd/launchd) |
|
|
56
|
+
| `status` | Show daemon status and active processes |
|
|
57
|
+
| `logs` | Tail the audit log (`-f` to follow, `-n 100` for lines) |
|
|
58
|
+
| `version` | Print version |
|
|
59
|
+
| `help` | Show usage |
|
|
60
|
+
|
|
61
|
+
## Local API
|
|
62
|
+
|
|
63
|
+
When running, the daemon exposes a local HTTP API on `127.0.0.1:9191`:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
GET /api/v1/status — Daemon status
|
|
67
|
+
GET /api/v1/processes — Tagged agent processes
|
|
68
|
+
GET /api/v1/processes/:pid — Single process detail
|
|
69
|
+
GET /api/v1/decisions — Recent enforcement decisions
|
|
70
|
+
GET /api/v1/policy — Active policy
|
|
71
|
+
POST /api/v1/policy/reload — Force policy sync
|
|
72
|
+
GET /api/v1/approvals — Pending skill approvals
|
|
73
|
+
POST /api/v1/approve/:id — Approve a skill invocation
|
|
74
|
+
POST /api/v1/deny/:id — Deny a skill invocation
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Requirements
|
|
78
|
+
|
|
79
|
+
- **Linux** (kernel 5.4+ for cgroups v2, seccomp, Landlock) or **macOS** (Ventura+)
|
|
80
|
+
- **Node.js** >= 20
|
|
81
|
+
- **Systemd** (Linux) or **launchd** (macOS) for service installation
|
|
82
|
+
- Root/sudo access for sandbox (cgroups, seccomp) and `/proc` scanning
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
Config is at `/etc/neuroshield/sentry.yaml`. Key settings:
|
|
87
|
+
|
|
88
|
+
```yaml
|
|
89
|
+
neurosec:
|
|
90
|
+
endpoint: "https://api.neurosec.ai"
|
|
91
|
+
org_id: "your-org-id"
|
|
92
|
+
token_path: /etc/neuroshield/sentry.token
|
|
93
|
+
|
|
94
|
+
enforcement:
|
|
95
|
+
mode: "monitor" # monitor | enforce | quarantine
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
All settings are also configurable via environment variables (`NEUROSEC_ORG_ID`, `SENTRY_ENFORCEMENT_MODE`, etc.)
|
|
99
|
+
|
|
100
|
+
## Platform Backends
|
|
101
|
+
|
|
102
|
+
| Feature | Linux | macOS |
|
|
103
|
+
|---------|-------|-------|
|
|
104
|
+
| Cgroups CPU/memory limits | ✓ cgroups v2 | — |
|
|
105
|
+
| Seccomp syscall filtering | ✓ BPF | — |
|
|
106
|
+
| Landlock FS restrictions | ✓ kernel 5.13+ | — |
|
|
107
|
+
| Seatbelt sandbox profile | — | ✓ sandbox-exec |
|
|
108
|
+
| Endpoint Security monitor | — | ✓ ES framework |
|
|
109
|
+
| Process discovery (/proc) | ✓ | limited |
|
|
110
|
+
| Network monitoring | ✓ nftables/iptables | ✓ pf |
|
|
111
|
+
|
|
112
|
+
## Kubernetes
|
|
113
|
+
|
|
114
|
+
Deploy as a DaemonSet for per-node enforcement:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
kubectl apply -f https://raw.githubusercontent.com/neurosec-ai/neurosec/main/packages/sentry/k8s/daemonset.yaml
|
|
118
|
+
```
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// NeuroShield Sentry — CLI management tool
|
|
3
|
+
// Installed globally via `npm install -g @neurosec/sentry`
|
|
4
|
+
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
let cli;
|
|
8
|
+
try {
|
|
9
|
+
cli = require(path.resolve(__dirname, '..', 'dist', 'cli.js'));
|
|
10
|
+
} catch (e1) {
|
|
11
|
+
try {
|
|
12
|
+
cli = require(path.resolve(__dirname, '..', 'src', 'cli.ts'));
|
|
13
|
+
} catch (e2) {
|
|
14
|
+
console.error('Failed to load CLI. Build it first: npm run build');
|
|
15
|
+
console.error(' or install globally: npm install -g @neurosec/sentry');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
}
|
package/bin/sentryd.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// NeuroShield Sentry Daemon — binary entry point
|
|
3
|
+
// Installed globally via `npm install -g @neurosec/sentry`
|
|
4
|
+
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
// Try the dist build first (production), then source as fallback (dev)
|
|
8
|
+
let main;
|
|
9
|
+
try {
|
|
10
|
+
main = require(path.resolve(__dirname, '..', 'dist', 'index.js'));
|
|
11
|
+
} catch (e1) {
|
|
12
|
+
try {
|
|
13
|
+
main = require(path.resolve(__dirname, '..', 'src', 'index.ts'));
|
|
14
|
+
} catch (e2) {
|
|
15
|
+
console.error('Failed to load sentry daemon. Build it first: npm run build');
|
|
16
|
+
console.error(' or install globally: npm install -g @neurosec/sentry');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
}
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SentryConfig } from './config';
|
|
2
|
+
import { TaggedProcess, SentryStatus } from './types';
|
|
3
|
+
import { EnforcementEngine } from './enforcement/enforcement-engine';
|
|
4
|
+
import { SkillEvaluator } from './skill-authz/skill-evaluator';
|
|
5
|
+
export declare class SentryApiServer {
|
|
6
|
+
private config;
|
|
7
|
+
private getTaggedProcesses;
|
|
8
|
+
private getEngine;
|
|
9
|
+
private getSkillEvaluator;
|
|
10
|
+
private getPolicyVersion;
|
|
11
|
+
private getLastSyncAt;
|
|
12
|
+
private server;
|
|
13
|
+
private startTime;
|
|
14
|
+
constructor(config: SentryConfig, getTaggedProcesses: () => TaggedProcess[], getEngine: () => EnforcementEngine, getSkillEvaluator: () => SkillEvaluator, getPolicyVersion: () => string, getLastSyncAt: () => string | null);
|
|
15
|
+
start(): Promise<void>;
|
|
16
|
+
stop(): Promise<void>;
|
|
17
|
+
getStatus(): SentryStatus;
|
|
18
|
+
private handleRequest;
|
|
19
|
+
private json;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,aAAa,EAAuB,YAAY,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAG/D,qBAAa,eAAe;IAKxB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,aAAa;IATvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,SAAS,CAAc;gBAGrB,MAAM,EAAE,YAAY,EACpB,kBAAkB,EAAE,MAAM,aAAa,EAAE,EACzC,SAAS,EAAE,MAAM,iBAAiB,EAClC,iBAAiB,EAAE,MAAM,cAAc,EACvC,gBAAgB,EAAE,MAAM,MAAM,EAC9B,aAAa,EAAE,MAAM,MAAM,GAAG,IAAI;IAGtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,SAAS,IAAI,YAAY;YAmBX,aAAa;YAuGb,IAAI;CAInB"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SentryApiServer = void 0;
|
|
7
|
+
const http_1 = __importDefault(require("http"));
|
|
8
|
+
const logger_1 = require("./logger");
|
|
9
|
+
class SentryApiServer {
|
|
10
|
+
constructor(config, getTaggedProcesses, getEngine, getSkillEvaluator, getPolicyVersion, getLastSyncAt) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.getTaggedProcesses = getTaggedProcesses;
|
|
13
|
+
this.getEngine = getEngine;
|
|
14
|
+
this.getSkillEvaluator = getSkillEvaluator;
|
|
15
|
+
this.getPolicyVersion = getPolicyVersion;
|
|
16
|
+
this.getLastSyncAt = getLastSyncAt;
|
|
17
|
+
this.server = null;
|
|
18
|
+
this.startTime = Date.now();
|
|
19
|
+
}
|
|
20
|
+
async start() {
|
|
21
|
+
if (this.server)
|
|
22
|
+
return;
|
|
23
|
+
this.server = http_1.default.createServer((req, res) => {
|
|
24
|
+
this.handleRequest(req, res).catch(err => {
|
|
25
|
+
logger_1.logger.error('API handler error', { err: err.message });
|
|
26
|
+
if (!res.headersSent) {
|
|
27
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
28
|
+
}
|
|
29
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
await new Promise((resolve, reject) => {
|
|
33
|
+
this.server.once('error', reject);
|
|
34
|
+
this.server.listen(this.config.sentry.apiPort, '127.0.0.1', () => resolve());
|
|
35
|
+
});
|
|
36
|
+
logger_1.logger.info('Sentry API server listening', { port: this.config.sentry.apiPort });
|
|
37
|
+
}
|
|
38
|
+
async stop() {
|
|
39
|
+
if (!this.server)
|
|
40
|
+
return;
|
|
41
|
+
await new Promise((resolve, reject) => {
|
|
42
|
+
this.server?.close(err => (err ? reject(err) : resolve()));
|
|
43
|
+
});
|
|
44
|
+
this.server = null;
|
|
45
|
+
}
|
|
46
|
+
getStatus() {
|
|
47
|
+
const engine = this.getEngine();
|
|
48
|
+
const stats = engine.getStats();
|
|
49
|
+
const processes = this.getTaggedProcesses();
|
|
50
|
+
return {
|
|
51
|
+
version: this.config.sentry.version,
|
|
52
|
+
uptime: Math.floor((Date.now() - this.startTime) / 1000),
|
|
53
|
+
mode: this.config.enforcement.mode,
|
|
54
|
+
policyVersion: this.getPolicyVersion(),
|
|
55
|
+
taggedProcesses: processes.length,
|
|
56
|
+
sandboxedProcesses: processes.filter(p => p.sandboxed).length,
|
|
57
|
+
decisionsTotal: stats.total,
|
|
58
|
+
decisionsDenied: stats.denied,
|
|
59
|
+
lastSyncAt: this.getLastSyncAt(),
|
|
60
|
+
platform: process.platform === 'linux' ? 'linux' : process.platform === 'darwin' ? 'darwin' : 'unknown',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async handleRequest(req, res) {
|
|
64
|
+
res.setHeader('Content-Type', 'application/json');
|
|
65
|
+
const parsed = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
66
|
+
const pathname = parsed.pathname;
|
|
67
|
+
const method = req.method ?? 'GET';
|
|
68
|
+
// CORS for local dev
|
|
69
|
+
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
|
|
70
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
71
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
72
|
+
if (method === 'OPTIONS') {
|
|
73
|
+
res.writeHead(204);
|
|
74
|
+
res.end();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
switch (true) {
|
|
79
|
+
case method === 'GET' && pathname === '/api/v1/status':
|
|
80
|
+
await this.json(res, 200, this.getStatus());
|
|
81
|
+
break;
|
|
82
|
+
case method === 'GET' && pathname === '/api/v1/processes':
|
|
83
|
+
await this.json(res, 200, this.getTaggedProcesses());
|
|
84
|
+
break;
|
|
85
|
+
case method === 'GET' && /^\/api\/v1\/processes\/(\d+)$/.test(pathname): {
|
|
86
|
+
const pid = parseInt(pathname.match(/^\/api\/v1\/processes\/(\d+)$/)[1], 10);
|
|
87
|
+
const processes = this.getTaggedProcesses();
|
|
88
|
+
const proc = processes.find(p => p.pid === pid);
|
|
89
|
+
if (proc) {
|
|
90
|
+
await this.json(res, 200, proc);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
await this.json(res, 404, { error: 'Process not found' });
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case method === 'GET' && pathname === '/api/v1/decisions':
|
|
98
|
+
await this.json(res, 200, this.getEngine().getRecentDecisions());
|
|
99
|
+
break;
|
|
100
|
+
case method === 'GET' && pathname === '/api/v1/policy':
|
|
101
|
+
await this.json(res, 200, {
|
|
102
|
+
version: this.getPolicyVersion(),
|
|
103
|
+
mode: this.config.enforcement.mode,
|
|
104
|
+
sandboxEnabled: this.config.enforcement.sandboxEnabled,
|
|
105
|
+
skillAuthzEnabled: this.config.skillAuthz.enabled,
|
|
106
|
+
allowedEgress: this.config.network.allowHosts,
|
|
107
|
+
blockedEgress: this.config.network.blockHosts,
|
|
108
|
+
});
|
|
109
|
+
break;
|
|
110
|
+
case method === 'POST' && pathname === '/api/v1/policy/reload':
|
|
111
|
+
await this.json(res, 200, { message: 'Policy reload requested' });
|
|
112
|
+
break;
|
|
113
|
+
case method === 'POST' && /^\/api\/v1\/sandbox\/(\d+)\/(disable|restrict)$/.test(pathname): {
|
|
114
|
+
const match = pathname.match(/^\/api\/v1\/sandbox\/(\d+)\/(disable|restrict)$/);
|
|
115
|
+
const pid = parseInt(match[1], 10);
|
|
116
|
+
const action = match[2];
|
|
117
|
+
logger_1.logger.info('Sandbox action requested', { pid, action });
|
|
118
|
+
await this.json(res, 200, { message: `Sandbox ${action} for pid ${pid}` });
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case method === 'GET' && pathname === '/api/v1/approvals':
|
|
122
|
+
await this.json(res, 200, this.getSkillEvaluator().getPendingApprovals());
|
|
123
|
+
break;
|
|
124
|
+
case method === 'POST' && /^\/api\/v1\/approve\/(.+)$/.test(pathname): {
|
|
125
|
+
const invocationId = pathname.match(/^\/api\/v1\/approve\/(.+)$/)[1];
|
|
126
|
+
const success = this.getSkillEvaluator().approve(invocationId);
|
|
127
|
+
if (success) {
|
|
128
|
+
await this.json(res, 200, { message: 'Skill invocation approved', invocationId });
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
await this.json(res, 404, { error: 'Approval request not found or expired', invocationId });
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case method === 'POST' && /^\/api\/v1\/deny\/(.+)$/.test(pathname): {
|
|
136
|
+
const invocationId = pathname.match(/^\/api\/v1\/deny\/(.+)$/)[1];
|
|
137
|
+
const success = this.getSkillEvaluator().deny(invocationId);
|
|
138
|
+
if (success) {
|
|
139
|
+
await this.json(res, 200, { message: 'Skill invocation denied', invocationId });
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
await this.json(res, 404, { error: 'Denial request not found or expired', invocationId });
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
default:
|
|
147
|
+
await this.json(res, 404, { error: 'Not found', path: pathname });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
logger_1.logger.error('API error', { path: pathname, err: err.message });
|
|
152
|
+
await this.json(res, 500, { error: 'Internal error' });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async json(res, status, data) {
|
|
156
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
157
|
+
res.end(JSON.stringify(data));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
exports.SentryApiServer = SentryApiServer;
|
|
161
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AuditEntry } from './types';
|
|
2
|
+
import { SentryConfig } from './config';
|
|
3
|
+
export declare class AuditLogger {
|
|
4
|
+
private config;
|
|
5
|
+
private stream;
|
|
6
|
+
private writeQueue;
|
|
7
|
+
private flushTimer;
|
|
8
|
+
private currentSizeBytes;
|
|
9
|
+
private logDir;
|
|
10
|
+
constructor(config: SentryConfig);
|
|
11
|
+
init(): Promise<void>;
|
|
12
|
+
log(entry: AuditEntry): Promise<void>;
|
|
13
|
+
private flush;
|
|
14
|
+
private rotate;
|
|
15
|
+
private cleanupOldRotations;
|
|
16
|
+
shutdown(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,qBAAa,WAAW;IAOV,OAAO,CAAC,MAAM;IAN1B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,MAAM,CAAS;gBAEH,MAAM,EAAE,YAAY;IAIlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBrB,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;YAQ7B,KAAK;YAoBL,MAAM;YAqBN,mBAAmB;IA4B3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAahC"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AuditLogger = void 0;
|
|
7
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const logger_1 = require("./logger");
|
|
11
|
+
class AuditLogger {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.stream = null;
|
|
15
|
+
this.writeQueue = [];
|
|
16
|
+
this.flushTimer = null;
|
|
17
|
+
this.currentSizeBytes = 0;
|
|
18
|
+
this.logDir = path_1.default.dirname(config.audit.logPath);
|
|
19
|
+
}
|
|
20
|
+
async init() {
|
|
21
|
+
await promises_1.default.mkdir(this.logDir, { recursive: true });
|
|
22
|
+
try {
|
|
23
|
+
const stat = await promises_1.default.stat(this.config.audit.logPath).catch(() => null);
|
|
24
|
+
if (stat) {
|
|
25
|
+
this.currentSizeBytes = stat.size;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
this.currentSizeBytes = 0;
|
|
30
|
+
}
|
|
31
|
+
this.stream = (0, fs_1.createWriteStream)(this.config.audit.logPath, { flags: 'a' });
|
|
32
|
+
this.flushTimer = setInterval(() => this.flush(), 5000);
|
|
33
|
+
logger_1.logger.info('Audit logger initialized', { path: this.config.audit.logPath });
|
|
34
|
+
}
|
|
35
|
+
async log(entry) {
|
|
36
|
+
this.writeQueue.push(entry);
|
|
37
|
+
if (this.writeQueue.length >= 100) {
|
|
38
|
+
await this.flush();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async flush() {
|
|
42
|
+
if (this.writeQueue.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
const batch = this.writeQueue.splice(0, this.writeQueue.length);
|
|
45
|
+
const lines = batch.map(entry => JSON.stringify(entry)).join('\n') + '\n';
|
|
46
|
+
if (this.stream) {
|
|
47
|
+
const canWrite = this.stream.write(lines);
|
|
48
|
+
this.currentSizeBytes += Buffer.byteLength(lines);
|
|
49
|
+
if (this.currentSizeBytes >= this.config.audit.maxSizeMb * 1024 * 1024) {
|
|
50
|
+
await this.rotate();
|
|
51
|
+
}
|
|
52
|
+
if (!canWrite) {
|
|
53
|
+
await new Promise(resolve => this.stream.once('drain', resolve));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async rotate() {
|
|
58
|
+
if (this.stream) {
|
|
59
|
+
this.stream.end();
|
|
60
|
+
this.stream = null;
|
|
61
|
+
}
|
|
62
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
63
|
+
const rotatedPath = `${this.config.audit.logPath}.${timestamp}`;
|
|
64
|
+
try {
|
|
65
|
+
await promises_1.default.rename(this.config.audit.logPath, rotatedPath);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Already rotated or doesn't exist
|
|
69
|
+
}
|
|
70
|
+
this.currentSizeBytes = 0;
|
|
71
|
+
this.stream = (0, fs_1.createWriteStream)(this.config.audit.logPath, { flags: 'a' });
|
|
72
|
+
await this.cleanupOldRotations();
|
|
73
|
+
}
|
|
74
|
+
async cleanupOldRotations() {
|
|
75
|
+
try {
|
|
76
|
+
const dir = path_1.default.dirname(this.config.audit.logPath);
|
|
77
|
+
const baseName = path_1.default.basename(this.config.audit.logPath);
|
|
78
|
+
const files = await promises_1.default.readdir(dir);
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
const maxAge = this.config.audit.retentionDays * 24 * 60 * 60 * 1000;
|
|
81
|
+
for (const file of files) {
|
|
82
|
+
if (file.startsWith(baseName + '.')) {
|
|
83
|
+
const filePath = path_1.default.join(dir, file);
|
|
84
|
+
try {
|
|
85
|
+
const stat = await promises_1.default.stat(filePath);
|
|
86
|
+
if (now - stat.mtimeMs > maxAge) {
|
|
87
|
+
await promises_1.default.unlink(filePath);
|
|
88
|
+
logger_1.logger.debug('Removed old audit rotation', { file: filePath });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// skip
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// cleanup is best-effort
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async shutdown() {
|
|
102
|
+
if (this.flushTimer) {
|
|
103
|
+
clearInterval(this.flushTimer);
|
|
104
|
+
this.flushTimer = null;
|
|
105
|
+
}
|
|
106
|
+
await this.flush();
|
|
107
|
+
if (this.stream) {
|
|
108
|
+
this.stream.end();
|
|
109
|
+
this.stream = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.AuditLogger = AuditLogger;
|
|
114
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|