@sentinel-atl/trust-gateway 0.3.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/dist/proxy.js ADDED
@@ -0,0 +1,399 @@
1
+ /**
2
+ * Trust Gateway HTTP Proxy — sits between MCP client and server,
3
+ * enforcing trust policies on every tool call.
4
+ *
5
+ * Supports upstream protocols:
6
+ * - http:// / https:// → SSE-based MCP server
7
+ * - stdio:// → stdio-based MCP server (spawns child process)
8
+ *
9
+ * Endpoints exposed:
10
+ * GET /sse → SSE stream (proxied from upstream)
11
+ * POST /message → JSON-RPC message relay (tool calls pass through trust engine)
12
+ * GET /health → Proxy health
13
+ * GET /stats → Gateway stats
14
+ */
15
+ import { spawn } from 'node:child_process';
16
+ import { TrustGateway } from './gateway.js';
17
+ import { TrustStore } from './trust-store.js';
18
+ import { randomUUID } from 'node:crypto';
19
+ import { authenticate, sendUnauthorized, applyCors, defaultCorsConfig, createSecureServer, setRateLimitHeaders, sendRateLimited, applySecurityHeaders, } from '@sentinel-atl/hardening';
20
+ // ─── Proxy ───────────────────────────────────────────────────────────
21
+ export class TrustGatewayProxy {
22
+ server = null;
23
+ gateway;
24
+ config;
25
+ sseClients = new Set();
26
+ stdioUpstreams = new Map();
27
+ defaultCallerId;
28
+ authConfig;
29
+ corsConfig;
30
+ tlsConfig;
31
+ globalRateLimiter;
32
+ constructor(options) {
33
+ this.config = options.config;
34
+ this.defaultCallerId = options.defaultCallerId ?? 'anonymous';
35
+ this.authConfig = options.auth ?? { enabled: false, keys: [] };
36
+ this.corsConfig = options.cors ?? defaultCorsConfig();
37
+ this.tlsConfig = options.tls;
38
+ const trustStore = options.trustStore ?? new TrustStore();
39
+ this.gateway = new TrustGateway(this.config, trustStore);
40
+ // Public paths: health + stats + SSE are readable without auth
41
+ if (this.authConfig.enabled && !this.authConfig.publicPaths) {
42
+ this.authConfig.publicPaths = ['/health', '/stats', '/sse'];
43
+ }
44
+ }
45
+ getGateway() {
46
+ return this.gateway;
47
+ }
48
+ /**
49
+ * Start the HTTP proxy server.
50
+ */
51
+ async start() {
52
+ const port = this.config.gateway.port ?? 3100;
53
+ // Pre-connect to stdio upstreams
54
+ for (const server of this.config.servers) {
55
+ if (server.upstream.startsWith('stdio://')) {
56
+ this.connectStdio(server);
57
+ }
58
+ }
59
+ return new Promise((resolve, reject) => {
60
+ this.server = createSecureServer((req, res) => this.handleRequest(req, res), this.tlsConfig);
61
+ this.server.on('error', reject);
62
+ this.server.listen(port, () => {
63
+ resolve({ port });
64
+ });
65
+ });
66
+ }
67
+ /**
68
+ * Stop the proxy and clean up.
69
+ */
70
+ async stop() {
71
+ // Close SSE clients
72
+ for (const client of this.sseClients) {
73
+ client.res.end();
74
+ }
75
+ this.sseClients.clear();
76
+ // Kill stdio upstreams
77
+ for (const [, upstream] of this.stdioUpstreams) {
78
+ upstream.process.kill();
79
+ for (const [, pending] of upstream.pending) {
80
+ pending.reject(new Error('Proxy shutting down'));
81
+ }
82
+ }
83
+ this.stdioUpstreams.clear();
84
+ return new Promise((resolve) => {
85
+ if (this.server) {
86
+ this.server.close(() => resolve());
87
+ }
88
+ else {
89
+ resolve();
90
+ }
91
+ });
92
+ }
93
+ // ─── HTTP Router ────────────────────────────────────────────────
94
+ handleRequest(req, res) {
95
+ const url = new URL(req.url ?? '/', `http://localhost`);
96
+ const path = url.pathname;
97
+ // CORS (configurable origins)
98
+ if (applyCors(req, res, this.corsConfig))
99
+ return; // preflight handled
100
+ // Security headers
101
+ applySecurityHeaders(res, { hsts: !!this.tlsConfig?.enabled });
102
+ // Authentication
103
+ const authResult = authenticate(req, this.authConfig);
104
+ if (!authResult.authenticated) {
105
+ sendUnauthorized(res, this.authConfig, authResult.error);
106
+ return;
107
+ }
108
+ if (path === '/health' && req.method === 'GET') {
109
+ this.handleHealth(res);
110
+ }
111
+ else if (path === '/stats' && req.method === 'GET') {
112
+ this.handleStats(res);
113
+ }
114
+ else if (path === '/sse' && req.method === 'GET') {
115
+ this.handleSSE(req, res, url);
116
+ }
117
+ else if (path === '/message' && req.method === 'POST') {
118
+ this.handleMessage(req, res);
119
+ }
120
+ else {
121
+ res.writeHead(404, { 'Content-Type': 'application/json' });
122
+ res.end(JSON.stringify({ error: 'Not found' }));
123
+ }
124
+ }
125
+ // ─── Health ──────────────────────────────────────────────────────
126
+ handleHealth(res) {
127
+ const payload = {
128
+ status: 'ok',
129
+ gateway: this.config.gateway.name,
130
+ mode: this.config.gateway.mode,
131
+ servers: this.config.servers.map(s => s.name),
132
+ sseClients: this.sseClients.size,
133
+ };
134
+ res.writeHead(200, { 'Content-Type': 'application/json' });
135
+ res.end(JSON.stringify(payload));
136
+ }
137
+ // ─── Stats ───────────────────────────────────────────────────────
138
+ handleStats(res) {
139
+ res.writeHead(200, { 'Content-Type': 'application/json' });
140
+ res.end(JSON.stringify(this.gateway.getStats()));
141
+ }
142
+ // ─── SSE Stream ──────────────────────────────────────────────────
143
+ handleSSE(req, res, url) {
144
+ const serverName = url.searchParams.get('server') ?? this.config.servers[0]?.name;
145
+ if (!serverName) {
146
+ res.writeHead(400, { 'Content-Type': 'application/json' });
147
+ res.end(JSON.stringify({ error: 'No server configured' }));
148
+ return;
149
+ }
150
+ const client = { id: randomUUID(), res, serverName };
151
+ res.writeHead(200, {
152
+ 'Content-Type': 'text/event-stream',
153
+ 'Cache-Control': 'no-cache',
154
+ 'Connection': 'keep-alive',
155
+ });
156
+ // Send endpoint info
157
+ res.write(`event: endpoint\ndata: /message?sessionId=${client.id}&server=${serverName}\n\n`);
158
+ this.sseClients.add(client);
159
+ req.on('close', () => {
160
+ this.sseClients.delete(client);
161
+ });
162
+ }
163
+ sendSSEEvent(client, data) {
164
+ client.res.write(`event: message\ndata: ${JSON.stringify(data)}\n\n`);
165
+ }
166
+ // ─── Message (JSON-RPC) ──────────────────────────────────────────
167
+ async handleMessage(req, res) {
168
+ // Content-Type enforcement
169
+ const contentType = req.headers['content-type'];
170
+ if (!contentType || !contentType.includes('application/json')) {
171
+ res.writeHead(415, { 'Content-Type': 'application/json' });
172
+ res.end(JSON.stringify({ error: 'Content-Type must be application/json' }));
173
+ return;
174
+ }
175
+ const url = new URL(req.url ?? '/', `http://localhost`);
176
+ const serverName = url.searchParams.get('server')
177
+ ?? req.headers['x-server-name']
178
+ ?? this.config.servers[0]?.name;
179
+ if (!serverName) {
180
+ res.writeHead(400, { 'Content-Type': 'application/json' });
181
+ res.end(JSON.stringify({ error: 'No server specified' }));
182
+ return;
183
+ }
184
+ const callerId = req.headers['x-caller-id'] ?? this.defaultCallerId;
185
+ let body;
186
+ try {
187
+ body = await readBody(req);
188
+ }
189
+ catch {
190
+ res.writeHead(400, { 'Content-Type': 'application/json' });
191
+ res.end(JSON.stringify({ error: 'Invalid request body' }));
192
+ return;
193
+ }
194
+ let jsonRpc;
195
+ try {
196
+ jsonRpc = JSON.parse(body);
197
+ }
198
+ catch {
199
+ res.writeHead(400, { 'Content-Type': 'application/json' });
200
+ res.end(JSON.stringify({ error: 'Invalid JSON' }));
201
+ return;
202
+ }
203
+ // Extract tool name from JSON-RPC method
204
+ const method = jsonRpc.method ?? '';
205
+ const toolName = method === 'tools/call'
206
+ ? jsonRpc.params?.name ?? 'unknown'
207
+ : method;
208
+ // ── Trust check ──
209
+ const gatewayResult = await this.gateway.processRequest({
210
+ serverName,
211
+ toolName,
212
+ callerId,
213
+ arguments: jsonRpc.params?.arguments,
214
+ });
215
+ // ── Global rate-limit check (with RFC 6585 headers) ──
216
+ if (this.globalRateLimiter) {
217
+ const rlResult = this.globalRateLimiter.check(callerId);
218
+ if (!rlResult.allowed) {
219
+ sendRateLimited(res, rlResult.info);
220
+ return;
221
+ }
222
+ setRateLimitHeaders(res, rlResult.info);
223
+ }
224
+ if (!gatewayResult.allowed) {
225
+ // Per-server rate-limit denial from gateway uses 429
226
+ const statusCode = gatewayResult.decision === 'deny-rate-limit' ? 429 : 403;
227
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
228
+ if (statusCode === 429) {
229
+ res.setHeader('Retry-After', '60');
230
+ }
231
+ res.end(JSON.stringify({
232
+ jsonrpc: '2.0',
233
+ id: jsonRpc.id,
234
+ error: {
235
+ code: -32600,
236
+ message: `Trust gateway denied: ${gatewayResult.reason}`,
237
+ data: {
238
+ decision: gatewayResult.decision,
239
+ trustScore: gatewayResult.trustScore,
240
+ grade: gatewayResult.grade,
241
+ },
242
+ },
243
+ }));
244
+ // Notify SSE clients
245
+ const sessionId = url.searchParams.get('sessionId');
246
+ if (sessionId) {
247
+ const client = [...this.sseClients].find(c => c.id === sessionId);
248
+ if (client) {
249
+ this.sendSSEEvent(client, {
250
+ jsonrpc: '2.0',
251
+ id: jsonRpc.id,
252
+ error: { code: -32600, message: `Trust gateway denied: ${gatewayResult.reason}` },
253
+ });
254
+ }
255
+ }
256
+ return;
257
+ }
258
+ // ── Forward to upstream ──
259
+ try {
260
+ const upstream = this.findUpstream(serverName);
261
+ const upstreamResult = await this.forwardToUpstream(upstream, serverName, jsonRpc);
262
+ res.writeHead(200, { 'Content-Type': 'application/json' });
263
+ res.end(JSON.stringify(upstreamResult));
264
+ // Notify SSE clients
265
+ const sessionId = url.searchParams.get('sessionId');
266
+ if (sessionId) {
267
+ const client = [...this.sseClients].find(c => c.id === sessionId);
268
+ if (client) {
269
+ this.sendSSEEvent(client, upstreamResult);
270
+ }
271
+ }
272
+ }
273
+ catch (err) {
274
+ res.writeHead(502, { 'Content-Type': 'application/json' });
275
+ res.end(JSON.stringify({
276
+ jsonrpc: '2.0',
277
+ id: jsonRpc.id,
278
+ error: { code: -32603, message: `Upstream error: ${err.message}` },
279
+ }));
280
+ }
281
+ }
282
+ // ─── Upstream Management ─────────────────────────────────────────
283
+ findUpstream(serverName) {
284
+ const server = this.config.servers.find(s => s.name === serverName);
285
+ if (!server)
286
+ throw new Error(`Unknown server: ${serverName}`);
287
+ return server;
288
+ }
289
+ async forwardToUpstream(server, serverName, jsonRpc) {
290
+ if (server.upstream.startsWith('stdio://')) {
291
+ return this.forwardStdio(serverName, jsonRpc);
292
+ }
293
+ else {
294
+ return this.forwardHttp(server.upstream, jsonRpc);
295
+ }
296
+ }
297
+ // ─── HTTP Upstream ───────────────────────────────────────────────
298
+ async forwardHttp(upstream, jsonRpc) {
299
+ // Resolve message endpoint from upstream URL
300
+ const baseUrl = upstream.replace(/\/sse$/, '');
301
+ const messageUrl = `${baseUrl}/message`;
302
+ const response = await fetch(messageUrl, {
303
+ method: 'POST',
304
+ headers: { 'Content-Type': 'application/json' },
305
+ body: JSON.stringify(jsonRpc),
306
+ signal: AbortSignal.timeout(30_000),
307
+ });
308
+ if (!response.ok) {
309
+ throw new Error(`Upstream returned ${response.status}`);
310
+ }
311
+ return response.json();
312
+ }
313
+ // ─── Stdio Upstream ──────────────────────────────────────────────
314
+ connectStdio(server) {
315
+ const command = server.upstream.replace('stdio://', '');
316
+ const parts = command.split(' ');
317
+ const proc = spawn(parts[0], parts.slice(1), {
318
+ stdio: ['pipe', 'pipe', 'pipe'],
319
+ });
320
+ const upstream = {
321
+ process: proc,
322
+ pending: new Map(),
323
+ buffer: '',
324
+ };
325
+ proc.stdout.on('data', (chunk) => {
326
+ upstream.buffer += chunk.toString();
327
+ // Process complete JSON-RPC messages (newline-delimited)
328
+ const lines = upstream.buffer.split('\n');
329
+ upstream.buffer = lines.pop() ?? '';
330
+ for (const line of lines) {
331
+ if (!line.trim())
332
+ continue;
333
+ try {
334
+ const msg = JSON.parse(line);
335
+ if (msg.id !== undefined && upstream.pending.has(msg.id)) {
336
+ const { resolve } = upstream.pending.get(msg.id);
337
+ upstream.pending.delete(msg.id);
338
+ resolve(msg);
339
+ }
340
+ }
341
+ catch {
342
+ // Ignore malformed lines
343
+ }
344
+ }
345
+ });
346
+ proc.on('error', (err) => {
347
+ for (const [, { reject }] of upstream.pending) {
348
+ reject(err);
349
+ }
350
+ upstream.pending.clear();
351
+ });
352
+ proc.on('exit', () => {
353
+ for (const [, { reject }] of upstream.pending) {
354
+ reject(new Error('Process exited'));
355
+ }
356
+ upstream.pending.clear();
357
+ this.stdioUpstreams.delete(server.name);
358
+ });
359
+ this.stdioUpstreams.set(server.name, upstream);
360
+ }
361
+ forwardStdio(serverName, jsonRpc) {
362
+ const upstream = this.stdioUpstreams.get(serverName);
363
+ if (!upstream)
364
+ throw new Error(`No stdio connection for server: ${serverName}`);
365
+ return new Promise((resolve, reject) => {
366
+ const msg = jsonRpc;
367
+ const id = msg.id ?? randomUUID();
368
+ const timer = setTimeout(() => {
369
+ upstream.pending.delete(id);
370
+ reject(new Error('Stdio upstream timeout'));
371
+ }, 30_000);
372
+ upstream.pending.set(id, {
373
+ resolve: (data) => { clearTimeout(timer); resolve(data); },
374
+ reject: (err) => { clearTimeout(timer); reject(err); },
375
+ });
376
+ upstream.process.stdin.write(JSON.stringify(jsonRpc) + '\n');
377
+ });
378
+ }
379
+ }
380
+ // ─── Helpers ──────────────────────────────────────────────────────────
381
+ function readBody(req) {
382
+ return new Promise((resolve, reject) => {
383
+ const chunks = [];
384
+ let size = 0;
385
+ const MAX_BODY = 1_048_576; // 1 MB
386
+ req.on('data', (chunk) => {
387
+ size += chunk.length;
388
+ if (size > MAX_BODY) {
389
+ reject(new Error('Request body too large'));
390
+ req.destroy();
391
+ return;
392
+ }
393
+ chunks.push(chunk);
394
+ });
395
+ req.on('end', () => resolve(Buffer.concat(chunks).toString()));
396
+ req.on('error', reject);
397
+ });
398
+ }
399
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Trust Store — manages loaded Sentinel Trust Certificates for runtime verification.
3
+ * Supports optional persistent backend via SentinelStore.
4
+ */
5
+ import { type SentinelTrustCertificate } from '@sentinel-atl/scanner';
6
+ import type { SentinelStore } from '@sentinel-atl/store';
7
+ export interface StoredCertificate {
8
+ certificate: SentinelTrustCertificate;
9
+ serverName: string;
10
+ verified: boolean;
11
+ loadedAt: string;
12
+ }
13
+ export interface TrustStoreOptions {
14
+ /** Persistent backend — data survives restarts */
15
+ backend?: SentinelStore;
16
+ /** Key prefix for the backend (default: 'trust-store:') */
17
+ prefix?: string;
18
+ }
19
+ export declare class TrustStore {
20
+ private certificates;
21
+ private backend?;
22
+ private prefix;
23
+ constructor(options?: TrustStoreOptions);
24
+ /** Load all entries from the backend into the in-memory cache. Call once on startup. */
25
+ load(): Promise<void>;
26
+ /**
27
+ * Load an STC from a file and verify its signature.
28
+ */
29
+ loadCertificate(serverName: string, filePath: string): Promise<StoredCertificate>;
30
+ /**
31
+ * Register a pre-loaded certificate.
32
+ */
33
+ addCertificate(serverName: string, certificate: SentinelTrustCertificate): Promise<StoredCertificate>;
34
+ /**
35
+ * Get the certificate for a server.
36
+ */
37
+ getCertificate(serverName: string): StoredCertificate | undefined;
38
+ /**
39
+ * Check if a server has a valid, non-expired certificate.
40
+ */
41
+ isVerified(serverName: string): boolean;
42
+ /**
43
+ * Get all stored certificates.
44
+ */
45
+ getAll(): StoredCertificate[];
46
+ /**
47
+ * Remove a certificate.
48
+ */
49
+ remove(serverName: string): Promise<boolean>;
50
+ }
51
+ //# sourceMappingURL=trust-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-store.d.ts","sourceRoot":"","sources":["../src/trust-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAa,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,wBAAwB,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,qBAAa,UAAU;IACrB,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,OAAO,CAAC,CAAgB;IAChC,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,CAAC,EAAE,iBAAiB;IAKvC,wFAAwF;IAClF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsBvF;;OAEG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,wBAAwB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmB3G;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIjE;;OAEG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAMvC;;OAEG;IACH,MAAM,IAAI,iBAAiB,EAAE;IAI7B;;OAEG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAOnD"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Trust Store — manages loaded Sentinel Trust Certificates for runtime verification.
3
+ * Supports optional persistent backend via SentinelStore.
4
+ */
5
+ import { readFile } from 'node:fs/promises';
6
+ import { verifySTC } from '@sentinel-atl/scanner';
7
+ const KEY_PREFIX_DEFAULT = 'trust-store:';
8
+ export class TrustStore {
9
+ certificates = new Map();
10
+ backend;
11
+ prefix;
12
+ constructor(options) {
13
+ this.backend = options?.backend;
14
+ this.prefix = options?.prefix ?? KEY_PREFIX_DEFAULT;
15
+ }
16
+ /** Load all entries from the backend into the in-memory cache. Call once on startup. */
17
+ async load() {
18
+ if (!this.backend)
19
+ return;
20
+ const keys = await this.backend.keys(this.prefix);
21
+ const values = await this.backend.getMany(keys);
22
+ for (const [, json] of values) {
23
+ const stored = JSON.parse(json);
24
+ this.certificates.set(stored.serverName, stored);
25
+ }
26
+ }
27
+ /**
28
+ * Load an STC from a file and verify its signature.
29
+ */
30
+ async loadCertificate(serverName, filePath) {
31
+ const raw = await readFile(filePath, 'utf-8');
32
+ const certificate = JSON.parse(raw);
33
+ const result = await verifySTC(certificate);
34
+ const stored = {
35
+ certificate,
36
+ serverName,
37
+ verified: result.valid,
38
+ loadedAt: new Date().toISOString(),
39
+ };
40
+ this.certificates.set(serverName, stored);
41
+ if (this.backend) {
42
+ await this.backend.set(`${this.prefix}${serverName}`, JSON.stringify(stored));
43
+ }
44
+ return stored;
45
+ }
46
+ /**
47
+ * Register a pre-loaded certificate.
48
+ */
49
+ async addCertificate(serverName, certificate) {
50
+ const result = await verifySTC(certificate);
51
+ const stored = {
52
+ certificate,
53
+ serverName,
54
+ verified: result.valid,
55
+ loadedAt: new Date().toISOString(),
56
+ };
57
+ this.certificates.set(serverName, stored);
58
+ if (this.backend) {
59
+ await this.backend.set(`${this.prefix}${serverName}`, JSON.stringify(stored));
60
+ }
61
+ return stored;
62
+ }
63
+ /**
64
+ * Get the certificate for a server.
65
+ */
66
+ getCertificate(serverName) {
67
+ return this.certificates.get(serverName);
68
+ }
69
+ /**
70
+ * Check if a server has a valid, non-expired certificate.
71
+ */
72
+ isVerified(serverName) {
73
+ const stored = this.certificates.get(serverName);
74
+ if (!stored || !stored.verified)
75
+ return false;
76
+ return new Date(stored.certificate.expiresAt) > new Date();
77
+ }
78
+ /**
79
+ * Get all stored certificates.
80
+ */
81
+ getAll() {
82
+ return Array.from(this.certificates.values());
83
+ }
84
+ /**
85
+ * Remove a certificate.
86
+ */
87
+ async remove(serverName) {
88
+ const existed = this.certificates.delete(serverName);
89
+ if (existed && this.backend) {
90
+ await this.backend.delete(`${this.prefix}${serverName}`);
91
+ }
92
+ return existed;
93
+ }
94
+ }
95
+ //# sourceMappingURL=trust-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-store.js","sourceRoot":"","sources":["../src/trust-store.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@sentinel-atl/trust-gateway",
3
+ "version": "0.3.0",
4
+ "description": "YAML-configured MCP trust gateway — runtime enforcement of Sentinel Trust Certificates",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "sentinel-gateway": "dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "test": "vitest run",
20
+ "lint": "tsc --noEmit",
21
+ "clean": "rm -rf dist"
22
+ },
23
+ "dependencies": {
24
+ "@sentinel-atl/core": "*",
25
+ "@sentinel-atl/scanner": "*",
26
+ "@sentinel-atl/audit": "*",
27
+ "@sentinel-atl/hardening": "*",
28
+ "@sentinel-atl/store": "*",
29
+ "yaml": "^2.7.0"
30
+ },
31
+ "devDependencies": {
32
+ "vitest": "^3.2.4",
33
+ "typescript": "^5.7.0",
34
+ "@types/node": "^20.0.0"
35
+ },
36
+ "license": "Apache-2.0",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/sentinel-atl/project-sentinel.git",
40
+ "directory": "packages/trust-gateway"
41
+ },
42
+ "keywords": [
43
+ "mcp",
44
+ "gateway",
45
+ "trust",
46
+ "security",
47
+ "proxy",
48
+ "ai-agent",
49
+ "yaml"
50
+ ],
51
+ "homepage": "https://github.com/sentinel-atl/project-sentinel#readme",
52
+ "bugs": {
53
+ "url": "https://github.com/sentinel-atl/project-sentinel/issues"
54
+ },
55
+ "files": [
56
+ "dist",
57
+ "README.md"
58
+ ]
59
+ }