cloudvault-mcp 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 +235 -0
- package/dist/adapters/aws.d.ts +42 -0
- package/dist/adapters/aws.d.ts.map +1 -0
- package/dist/adapters/aws.js +318 -0
- package/dist/adapters/aws.js.map +1 -0
- package/dist/adapters/types.d.ts +22 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/audit.d.ts +57 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +136 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/cost-estimates.d.ts +16 -0
- package/dist/lib/cost-estimates.d.ts.map +1 -0
- package/dist/lib/cost-estimates.js +101 -0
- package/dist/lib/cost-estimates.js.map +1 -0
- package/dist/lib/fetch-retry.d.ts +7 -0
- package/dist/lib/fetch-retry.d.ts.map +1 -0
- package/dist/lib/fetch-retry.js +35 -0
- package/dist/lib/fetch-retry.js.map +1 -0
- package/dist/lib/providers.d.ts +7 -0
- package/dist/lib/providers.d.ts.map +1 -0
- package/dist/lib/providers.js +37 -0
- package/dist/lib/providers.js.map +1 -0
- package/dist/premium/gate.d.ts +18 -0
- package/dist/premium/gate.d.ts.map +1 -0
- package/dist/premium/gate.js +27 -0
- package/dist/premium/gate.js.map +1 -0
- package/dist/tools/get_secrets.d.ts +16 -0
- package/dist/tools/get_secrets.d.ts.map +1 -0
- package/dist/tools/get_secrets.js +52 -0
- package/dist/tools/get_secrets.js.map +1 -0
- package/dist/tools/list_databases.d.ts +16 -0
- package/dist/tools/list_databases.d.ts.map +1 -0
- package/dist/tools/list_databases.js +42 -0
- package/dist/tools/list_databases.js.map +1 -0
- package/dist/tools/list_instances.d.ts +17 -0
- package/dist/tools/list_instances.d.ts.map +1 -0
- package/dist/tools/list_instances.js +43 -0
- package/dist/tools/list_instances.js.map +1 -0
- package/dist/tools/list_storage.d.ts +15 -0
- package/dist/tools/list_storage.d.ts.map +1 -0
- package/dist/tools/list_storage.js +40 -0
- package/dist/tools/list_storage.js.map +1 -0
- package/dist/types.d.ts +143 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CloudVault MCP — Cloud infrastructure analysis server.
|
|
4
|
+
* Phase 1: AWS inventory — compute, databases, storage, secrets.
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { list_instances } from './tools/list_instances.js';
|
|
10
|
+
import { list_databases } from './tools/list_databases.js';
|
|
11
|
+
import { list_storage } from './tools/list_storage.js';
|
|
12
|
+
import { get_secrets } from './tools/get_secrets.js';
|
|
13
|
+
const server = new McpServer({
|
|
14
|
+
name: 'cloudvault-mcp',
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
});
|
|
17
|
+
// list_instances
|
|
18
|
+
server.tool('list_instances', 'List compute instances with state, type, IP, region, and cost estimate.', {
|
|
19
|
+
provider: z.enum(['aws', 'gcp', 'azure']).describe('Cloud provider'),
|
|
20
|
+
region: z.string().optional().describe('Filter by region (e.g., us-east-1)'),
|
|
21
|
+
state: z.enum(['running', 'stopped', 'terminated', 'pending']).optional().describe('Filter by instance state'),
|
|
22
|
+
tags: z.record(z.string()).optional().describe('Filter by tag key/value pairs'),
|
|
23
|
+
}, async (input) => {
|
|
24
|
+
return list_instances(input);
|
|
25
|
+
});
|
|
26
|
+
// list_databases
|
|
27
|
+
server.tool('list_databases', 'List managed databases with engine, version, storage size, and backup status.', {
|
|
28
|
+
provider: z.enum(['aws', 'gcp', 'azure']).describe('Cloud provider'),
|
|
29
|
+
region: z.string().optional().describe('Filter by region'),
|
|
30
|
+
engine: z.string().optional().describe('Filter by database engine (e.g., postgres, mysql)'),
|
|
31
|
+
}, async (input) => {
|
|
32
|
+
return list_databases(input);
|
|
33
|
+
});
|
|
34
|
+
// list_storage
|
|
35
|
+
server.tool('list_storage', 'List storage buckets/containers with public access status and encryption info.', {
|
|
36
|
+
provider: z.enum(['aws', 'gcp', 'azure']).describe('Cloud provider'),
|
|
37
|
+
region: z.string().optional().describe('Filter by region'),
|
|
38
|
+
}, async (input) => {
|
|
39
|
+
return list_storage(input);
|
|
40
|
+
});
|
|
41
|
+
// get_secrets
|
|
42
|
+
server.tool('get_secrets', 'List secret names and metadata. SECURITY: Secret values are NEVER returned.', {
|
|
43
|
+
provider: z.enum(['aws', 'gcp', 'azure']).describe('Cloud provider'),
|
|
44
|
+
prefix: z.string().optional().describe('Filter secrets by name prefix (e.g., prod/)'),
|
|
45
|
+
}, async (input) => {
|
|
46
|
+
return get_secrets(input);
|
|
47
|
+
});
|
|
48
|
+
// Start server
|
|
49
|
+
const transport = new StdioServerTransport();
|
|
50
|
+
await server.connect(transport);
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit trail module — SQLite-backed logging of all CloudVault tool calls.
|
|
3
|
+
* Stores to ~/.cloudvault/audit.db by default.
|
|
4
|
+
* 90-day retention with automatic cleanup on init.
|
|
5
|
+
*/
|
|
6
|
+
export interface AuditLogEntry {
|
|
7
|
+
tool_name: string;
|
|
8
|
+
input_summary: string;
|
|
9
|
+
result_summary: string;
|
|
10
|
+
success: boolean;
|
|
11
|
+
duration_ms?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface AuditRow {
|
|
14
|
+
id: number;
|
|
15
|
+
created_at: string;
|
|
16
|
+
tool_name: string;
|
|
17
|
+
input_summary: string;
|
|
18
|
+
result_summary: string;
|
|
19
|
+
success: number;
|
|
20
|
+
duration_ms: number | null;
|
|
21
|
+
}
|
|
22
|
+
export interface AuditQueryOptions {
|
|
23
|
+
timeframe?: '1d' | '7d' | '30d';
|
|
24
|
+
tool_name?: string;
|
|
25
|
+
limit?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Return the shared AuditLog singleton, creating it on first call (lazy init).
|
|
29
|
+
* Callers should use this instead of `new AuditLog()` to avoid opening a new
|
|
30
|
+
* SQLite connection per tool invocation.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getAuditLog(): AuditLog;
|
|
33
|
+
/**
|
|
34
|
+
* Reset the singleton — intended for test isolation only.
|
|
35
|
+
* Closes the existing connection (if any) and clears the cached instance.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resetAuditLogSingleton(): void;
|
|
38
|
+
export declare class AuditLog {
|
|
39
|
+
private readonly db;
|
|
40
|
+
constructor(dbPath?: string);
|
|
41
|
+
private defaultPath;
|
|
42
|
+
private init;
|
|
43
|
+
/**
|
|
44
|
+
* Sanitize input record — redact any values whose key looks like a secret.
|
|
45
|
+
* Values are truncated to 200 chars to keep audit.db small.
|
|
46
|
+
*/
|
|
47
|
+
sanitize(input: Record<string, unknown>): string;
|
|
48
|
+
log(entry: AuditLogEntry): void;
|
|
49
|
+
query(opts?: AuditQueryOptions): AuditRow[];
|
|
50
|
+
/**
|
|
51
|
+
* Close the underlying SQLite connection.
|
|
52
|
+
* NOTE: Do not call this on the singleton returned by getAuditLog() — it will
|
|
53
|
+
* break subsequent log writes. This method is retained for test isolation only.
|
|
54
|
+
*/
|
|
55
|
+
close(): void;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/lib/audit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBD;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAKtC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAS7C;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAE3B,MAAM,CAAC,EAAE,MAAM;IAM3B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,IAAI;IAsBZ;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAehD,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAe/B,KAAK,CAAC,IAAI,GAAE,iBAAsB,GAAG,QAAQ,EAAE;IA6B/C;;;;OAIG;IACH,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit trail module — SQLite-backed logging of all CloudVault tool calls.
|
|
3
|
+
* Stores to ~/.cloudvault/audit.db by default.
|
|
4
|
+
* 90-day retention with automatic cleanup on init.
|
|
5
|
+
*/
|
|
6
|
+
import Database from 'better-sqlite3';
|
|
7
|
+
import { homedir } from 'os';
|
|
8
|
+
import { mkdirSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
// Sensitive key patterns to redact from input summaries
|
|
11
|
+
const SENSITIVE_PATTERNS = [
|
|
12
|
+
/token/i,
|
|
13
|
+
/password/i,
|
|
14
|
+
/secret/i,
|
|
15
|
+
/api_key/i,
|
|
16
|
+
/auth/i,
|
|
17
|
+
/credential/i,
|
|
18
|
+
/private/i,
|
|
19
|
+
];
|
|
20
|
+
// Module-level singleton — opened once, reused across all tool calls.
|
|
21
|
+
let _instance = null;
|
|
22
|
+
/**
|
|
23
|
+
* Return the shared AuditLog singleton, creating it on first call (lazy init).
|
|
24
|
+
* Callers should use this instead of `new AuditLog()` to avoid opening a new
|
|
25
|
+
* SQLite connection per tool invocation.
|
|
26
|
+
*/
|
|
27
|
+
export function getAuditLog() {
|
|
28
|
+
if (!_instance) {
|
|
29
|
+
_instance = new AuditLog();
|
|
30
|
+
}
|
|
31
|
+
return _instance;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reset the singleton — intended for test isolation only.
|
|
35
|
+
* Closes the existing connection (if any) and clears the cached instance.
|
|
36
|
+
*/
|
|
37
|
+
export function resetAuditLogSingleton() {
|
|
38
|
+
if (_instance) {
|
|
39
|
+
try {
|
|
40
|
+
_instance.close();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Ignore close errors during test teardown
|
|
44
|
+
}
|
|
45
|
+
_instance = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export class AuditLog {
|
|
49
|
+
db;
|
|
50
|
+
constructor(dbPath) {
|
|
51
|
+
const path = dbPath ?? this.defaultPath();
|
|
52
|
+
this.db = new Database(path);
|
|
53
|
+
this.init();
|
|
54
|
+
}
|
|
55
|
+
defaultPath() {
|
|
56
|
+
const dir = join(homedir(), '.cloudvault');
|
|
57
|
+
mkdirSync(dir, { recursive: true });
|
|
58
|
+
return join(dir, 'audit.db');
|
|
59
|
+
}
|
|
60
|
+
init() {
|
|
61
|
+
this.db.exec(`
|
|
62
|
+
CREATE TABLE IF NOT EXISTS audit_log (
|
|
63
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
64
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
65
|
+
tool_name TEXT NOT NULL,
|
|
66
|
+
input_summary TEXT NOT NULL DEFAULT '',
|
|
67
|
+
result_summary TEXT NOT NULL DEFAULT '',
|
|
68
|
+
success INTEGER DEFAULT 1,
|
|
69
|
+
duration_ms INTEGER
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_audit_created_at ON audit_log(created_at);
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_audit_tool ON audit_log(tool_name);
|
|
74
|
+
`);
|
|
75
|
+
// 90-day cleanup on init
|
|
76
|
+
this.db.exec("DELETE FROM audit_log WHERE created_at < datetime('now', '-90 days')");
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Sanitize input record — redact any values whose key looks like a secret.
|
|
80
|
+
* Values are truncated to 200 chars to keep audit.db small.
|
|
81
|
+
*/
|
|
82
|
+
sanitize(input) {
|
|
83
|
+
const sanitized = {};
|
|
84
|
+
for (const [key, value] of Object.entries(input)) {
|
|
85
|
+
const isSensitive = SENSITIVE_PATTERNS.some((p) => p.test(key));
|
|
86
|
+
if (isSensitive) {
|
|
87
|
+
sanitized[key] = '[REDACTED]';
|
|
88
|
+
}
|
|
89
|
+
else if (typeof value === 'string' && value.length > 200) {
|
|
90
|
+
sanitized[key] = value.substring(0, 200) + '…';
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
sanitized[key] = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return JSON.stringify(sanitized);
|
|
97
|
+
}
|
|
98
|
+
log(entry) {
|
|
99
|
+
const stmt = this.db.prepare(`
|
|
100
|
+
INSERT INTO audit_log (tool_name, input_summary, result_summary, success, duration_ms)
|
|
101
|
+
VALUES (?, ?, ?, ?, ?)
|
|
102
|
+
`);
|
|
103
|
+
stmt.run(entry.tool_name, entry.input_summary, entry.result_summary?.substring(0, 500) ?? '', entry.success ? 1 : 0, entry.duration_ms ?? null);
|
|
104
|
+
}
|
|
105
|
+
query(opts = {}) {
|
|
106
|
+
const conditions = [];
|
|
107
|
+
const params = [];
|
|
108
|
+
if (opts.timeframe) {
|
|
109
|
+
const days = opts.timeframe === '1d' ? 1 : opts.timeframe === '7d' ? 7 : 30;
|
|
110
|
+
conditions.push(`created_at >= datetime('now', '-${days} days')`);
|
|
111
|
+
}
|
|
112
|
+
if (opts.tool_name) {
|
|
113
|
+
conditions.push('tool_name = ?');
|
|
114
|
+
params.push(opts.tool_name);
|
|
115
|
+
}
|
|
116
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
117
|
+
const limit = opts.limit ?? 50;
|
|
118
|
+
const sql = `
|
|
119
|
+
SELECT id, created_at, tool_name, input_summary, result_summary, success, duration_ms
|
|
120
|
+
FROM audit_log
|
|
121
|
+
${where}
|
|
122
|
+
ORDER BY created_at DESC
|
|
123
|
+
LIMIT ?
|
|
124
|
+
`;
|
|
125
|
+
return this.db.prepare(sql).all(...params, limit);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Close the underlying SQLite connection.
|
|
129
|
+
* NOTE: Do not call this on the singleton returned by getAuditLog() — it will
|
|
130
|
+
* break subsequent log writes. This method is retained for test isolation only.
|
|
131
|
+
*/
|
|
132
|
+
close() {
|
|
133
|
+
this.db.close();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/lib/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static monthly cost estimates for common AWS EC2 instance types.
|
|
3
|
+
* Values are approximate on-demand prices in USD cents (us-east-1).
|
|
4
|
+
* These are estimates only — actual costs vary by region, OS, and usage.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Get the estimated monthly cost in USD cents for a given EC2 instance type.
|
|
8
|
+
* Returns undefined if the instance type is not in the lookup table.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getInstanceCostEstimate(instanceType: string): number | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Get a human-readable cost estimate string (e.g., "~$8/mo").
|
|
13
|
+
* Returns "unknown" if the type is not in the table.
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatCostEstimate(instanceType: string): string;
|
|
16
|
+
//# sourceMappingURL=cost-estimates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-estimates.d.ts","sourceRoot":"","sources":["../../src/lib/cost-estimates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0FH;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAK/D"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static monthly cost estimates for common AWS EC2 instance types.
|
|
3
|
+
* Values are approximate on-demand prices in USD cents (us-east-1).
|
|
4
|
+
* These are estimates only — actual costs vary by region, OS, and usage.
|
|
5
|
+
*/
|
|
6
|
+
// Monthly cost in USD cents (approximate on-demand, us-east-1, Linux)
|
|
7
|
+
const COST_TABLE = {
|
|
8
|
+
// t3 family
|
|
9
|
+
't3.nano': 475, // ~$4.75/mo
|
|
10
|
+
't3.micro': 834, // ~$8.34/mo
|
|
11
|
+
't3.small': 1670, // ~$16.70/mo
|
|
12
|
+
't3.medium': 3341, // ~$33.41/mo
|
|
13
|
+
't3.large': 6682, // ~$66.82/mo
|
|
14
|
+
't3.xlarge': 13363, // ~$133.63/mo
|
|
15
|
+
't3.2xlarge': 26726, // ~$267.26/mo
|
|
16
|
+
// t3a family
|
|
17
|
+
't3a.nano': 428,
|
|
18
|
+
't3a.micro': 752,
|
|
19
|
+
't3a.small': 1505,
|
|
20
|
+
't3a.medium': 3010,
|
|
21
|
+
't3a.large': 6019,
|
|
22
|
+
't3a.xlarge': 12038,
|
|
23
|
+
// t2 family
|
|
24
|
+
't2.nano': 517,
|
|
25
|
+
't2.micro': 1168,
|
|
26
|
+
't2.small': 2336,
|
|
27
|
+
't2.medium': 4672,
|
|
28
|
+
't2.large': 9344,
|
|
29
|
+
't2.xlarge': 18688,
|
|
30
|
+
't2.2xlarge': 37376,
|
|
31
|
+
// m5 family
|
|
32
|
+
'm5.large': 7008, // ~$70.08/mo
|
|
33
|
+
'm5.xlarge': 14016,
|
|
34
|
+
'm5.2xlarge': 28032,
|
|
35
|
+
'm5.4xlarge': 56064,
|
|
36
|
+
'm5.8xlarge': 112128,
|
|
37
|
+
'm5.12xlarge': 168192,
|
|
38
|
+
'm5.16xlarge': 224256,
|
|
39
|
+
'm5.24xlarge': 336384,
|
|
40
|
+
// m6i family
|
|
41
|
+
'm6i.large': 7344,
|
|
42
|
+
'm6i.xlarge': 14688,
|
|
43
|
+
'm6i.2xlarge': 29376,
|
|
44
|
+
'm6i.4xlarge': 58752,
|
|
45
|
+
// c5 family
|
|
46
|
+
'c5.large': 6197,
|
|
47
|
+
'c5.xlarge': 12395,
|
|
48
|
+
'c5.2xlarge': 24789,
|
|
49
|
+
'c5.4xlarge': 49579,
|
|
50
|
+
'c5.9xlarge': 111553,
|
|
51
|
+
'c5.12xlarge': 148737,
|
|
52
|
+
'c5.18xlarge': 223106,
|
|
53
|
+
'c5.24xlarge': 297474,
|
|
54
|
+
// c6i family
|
|
55
|
+
'c6i.large': 6140,
|
|
56
|
+
'c6i.xlarge': 12279,
|
|
57
|
+
'c6i.2xlarge': 24558,
|
|
58
|
+
'c6i.4xlarge': 49117,
|
|
59
|
+
// r5 family
|
|
60
|
+
'r5.large': 10079,
|
|
61
|
+
'r5.xlarge': 20158,
|
|
62
|
+
'r5.2xlarge': 40315,
|
|
63
|
+
'r5.4xlarge': 80630,
|
|
64
|
+
'r5.8xlarge': 161261,
|
|
65
|
+
'r5.12xlarge': 241891,
|
|
66
|
+
'r5.16xlarge': 322522,
|
|
67
|
+
'r5.24xlarge': 483782,
|
|
68
|
+
// r6i family
|
|
69
|
+
'r6i.large': 10548,
|
|
70
|
+
'r6i.xlarge': 21096,
|
|
71
|
+
'r6i.2xlarge': 42192,
|
|
72
|
+
'r6i.4xlarge': 84384,
|
|
73
|
+
// p3 family (GPU)
|
|
74
|
+
'p3.2xlarge': 306340,
|
|
75
|
+
'p3.8xlarge': 1225360,
|
|
76
|
+
'p3.16xlarge': 2450720,
|
|
77
|
+
// g4dn family (GPU)
|
|
78
|
+
'g4dn.xlarge': 52631,
|
|
79
|
+
'g4dn.2xlarge': 75209,
|
|
80
|
+
'g4dn.4xlarge': 136314,
|
|
81
|
+
'g4dn.8xlarge': 225657,
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Get the estimated monthly cost in USD cents for a given EC2 instance type.
|
|
85
|
+
* Returns undefined if the instance type is not in the lookup table.
|
|
86
|
+
*/
|
|
87
|
+
export function getInstanceCostEstimate(instanceType) {
|
|
88
|
+
return COST_TABLE[instanceType];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get a human-readable cost estimate string (e.g., "~$8/mo").
|
|
92
|
+
* Returns "unknown" if the type is not in the table.
|
|
93
|
+
*/
|
|
94
|
+
export function formatCostEstimate(instanceType) {
|
|
95
|
+
const cents = COST_TABLE[instanceType];
|
|
96
|
+
if (cents === undefined)
|
|
97
|
+
return 'unknown';
|
|
98
|
+
const dollars = Math.round(cents / 100);
|
|
99
|
+
return `~$${dollars}/mo`;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=cost-estimates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-estimates.js","sourceRoot":"","sources":["../../src/lib/cost-estimates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sEAAsE;AACtE,MAAM,UAAU,GAA2B;IACzC,YAAY;IACZ,SAAS,EAAK,GAAG,EAAK,YAAY;IAClC,UAAU,EAAI,GAAG,EAAK,YAAY;IAClC,UAAU,EAAI,IAAI,EAAI,aAAa;IACnC,WAAW,EAAG,IAAI,EAAI,aAAa;IACnC,UAAU,EAAI,IAAI,EAAI,aAAa;IACnC,WAAW,EAAG,KAAK,EAAG,cAAc;IACpC,YAAY,EAAE,KAAK,EAAG,cAAc;IAEpC,aAAa;IACb,UAAU,EAAI,GAAG;IACjB,WAAW,EAAG,GAAG;IACjB,WAAW,EAAG,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,WAAW,EAAG,IAAI;IAClB,YAAY,EAAE,KAAK;IAEnB,YAAY;IACZ,SAAS,EAAK,GAAG;IACjB,UAAU,EAAI,IAAI;IAClB,UAAU,EAAI,IAAI;IAClB,WAAW,EAAG,IAAI;IAClB,UAAU,EAAI,IAAI;IAClB,WAAW,EAAG,KAAK;IACnB,YAAY,EAAE,KAAK;IAEnB,YAAY;IACZ,UAAU,EAAK,IAAI,EAAI,aAAa;IACpC,WAAW,EAAI,KAAK;IACpB,YAAY,EAAG,KAAK;IACpB,YAAY,EAAG,KAAK;IACpB,YAAY,EAAG,MAAM;IACrB,aAAa,EAAE,MAAM;IACrB,aAAa,EAAE,MAAM;IACrB,aAAa,EAAE,MAAM;IAErB,aAAa;IACb,WAAW,EAAK,IAAI;IACpB,YAAY,EAAI,KAAK;IACrB,aAAa,EAAG,KAAK;IACrB,aAAa,EAAG,KAAK;IAErB,YAAY;IACZ,UAAU,EAAK,IAAI;IACnB,WAAW,EAAI,KAAK;IACpB,YAAY,EAAG,KAAK;IACpB,YAAY,EAAG,KAAK;IACpB,YAAY,EAAG,MAAM;IACrB,aAAa,EAAE,MAAM;IACrB,aAAa,EAAE,MAAM;IACrB,aAAa,EAAE,MAAM;IAErB,aAAa;IACb,WAAW,EAAK,IAAI;IACpB,YAAY,EAAI,KAAK;IACrB,aAAa,EAAG,KAAK;IACrB,aAAa,EAAG,KAAK;IAErB,YAAY;IACZ,UAAU,EAAK,KAAK;IACpB,WAAW,EAAI,KAAK;IACpB,YAAY,EAAG,KAAK;IACpB,YAAY,EAAG,KAAK;IACpB,YAAY,EAAG,MAAM;IACrB,aAAa,EAAE,MAAM;IACrB,aAAa,EAAE,MAAM;IACrB,aAAa,EAAE,MAAM;IAErB,aAAa;IACb,WAAW,EAAK,KAAK;IACrB,YAAY,EAAI,KAAK;IACrB,aAAa,EAAG,KAAK;IACrB,aAAa,EAAG,KAAK;IAErB,kBAAkB;IAClB,YAAY,EAAI,MAAM;IACtB,YAAY,EAAI,OAAO;IACvB,aAAa,EAAG,OAAO;IAEvB,oBAAoB;IACpB,aAAa,EAAG,KAAK;IACrB,cAAc,EAAE,KAAK;IACrB,cAAc,EAAE,MAAM;IACtB,cAAc,EAAE,MAAM;CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,YAAoB;IAC1D,OAAO,UAAU,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,YAAoB;IACrD,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;IACxC,OAAO,KAAK,OAAO,KAAK,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fetchWithRetry — retries on 429 (rate limit) and 5xx (server errors).
|
|
3
|
+
* Uses Retry-After header when present, otherwise exponential backoff.
|
|
4
|
+
* Max 3 retries by default.
|
|
5
|
+
*/
|
|
6
|
+
export declare function fetchWithRetry(url: string | URL, init?: RequestInit, maxRetries?: number): Promise<Response>;
|
|
7
|
+
//# sourceMappingURL=fetch-retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-retry.d.ts","sourceRoot":"","sources":["../../src/lib/fetch-retry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,GAAG,GAAG,EACjB,IAAI,CAAC,EAAE,WAAW,EAClB,UAAU,SAAI,GACb,OAAO,CAAC,QAAQ,CAAC,CA+BnB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fetchWithRetry — retries on 429 (rate limit) and 5xx (server errors).
|
|
3
|
+
* Uses Retry-After header when present, otherwise exponential backoff.
|
|
4
|
+
* Max 3 retries by default.
|
|
5
|
+
*/
|
|
6
|
+
export async function fetchWithRetry(url, init, maxRetries = 3) {
|
|
7
|
+
let lastError = null;
|
|
8
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
9
|
+
try {
|
|
10
|
+
const res = await fetch(url, init);
|
|
11
|
+
if (res.status === 429) {
|
|
12
|
+
if (attempt >= maxRetries)
|
|
13
|
+
return res;
|
|
14
|
+
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '', 10);
|
|
15
|
+
const waitMs = (retryAfter > 0 ? retryAfter * 1000 : 2000) * Math.pow(2, attempt);
|
|
16
|
+
await new Promise(r => setTimeout(r, waitMs));
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (res.status >= 500 && attempt < maxRetries) {
|
|
20
|
+
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
return res;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
27
|
+
if (attempt < maxRetries) {
|
|
28
|
+
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
throw lastError ?? new Error('fetchWithRetry: max retries exceeded');
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=fetch-retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-retry.js","sourceRoot":"","sources":["../../src/lib/fetch-retry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAiB,EACjB,IAAkB,EAClB,UAAU,GAAG,CAAC;IAEd,IAAI,SAAS,GAAiB,IAAI,CAAC;IAEnC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAEnC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,IAAI,OAAO,IAAI,UAAU;oBAAE,OAAO,GAAG,CAAC;gBACtC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBACtE,MAAM,MAAM,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBAClF,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;gBAC9C,SAAS;YACX,CAAC;YAED,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBAC9C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;gBACnE,SAAS;YACX,CAAC;YAED,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBACzB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;gBACnE,SAAS;YACX,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CloudProvider } from '../adapters/types.js';
|
|
2
|
+
export type ProviderName = 'aws' | 'gcp' | 'azure';
|
|
3
|
+
export declare function getProvider(name: ProviderName): CloudProvider;
|
|
4
|
+
export declare function getProviders(names: ProviderName[]): CloudProvider[];
|
|
5
|
+
/** Clear the cache — useful for testing. */
|
|
6
|
+
export declare function clearProviderCache(): void;
|
|
7
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/lib/providers.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;AAEnD,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAkB7D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,aAAa,EAAE,CAEnE;AAED,4CAA4C;AAC5C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cached provider factory.
|
|
3
|
+
* Adapters are created once and reused across calls to avoid
|
|
4
|
+
* repeated credential validation and multiple client instances.
|
|
5
|
+
*
|
|
6
|
+
* Phase 1: aws only
|
|
7
|
+
* Phase 2: + gcp
|
|
8
|
+
* Phase 3: + azure
|
|
9
|
+
*/
|
|
10
|
+
import { AwsAdapter } from '../adapters/aws.js';
|
|
11
|
+
const cache = new Map();
|
|
12
|
+
export function getProvider(name) {
|
|
13
|
+
if (cache.has(name))
|
|
14
|
+
return cache.get(name);
|
|
15
|
+
let adapter;
|
|
16
|
+
switch (name) {
|
|
17
|
+
case 'aws':
|
|
18
|
+
adapter = new AwsAdapter();
|
|
19
|
+
break;
|
|
20
|
+
case 'gcp':
|
|
21
|
+
throw new Error('Unknown provider: gcp. Supported: aws');
|
|
22
|
+
case 'azure':
|
|
23
|
+
throw new Error('Unknown provider: azure. Supported: aws');
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`Unknown provider: ${name}. Supported: aws`);
|
|
26
|
+
}
|
|
27
|
+
cache.set(name, adapter);
|
|
28
|
+
return adapter;
|
|
29
|
+
}
|
|
30
|
+
export function getProviders(names) {
|
|
31
|
+
return names.map((n) => getProvider(n));
|
|
32
|
+
}
|
|
33
|
+
/** Clear the cache — useful for testing. */
|
|
34
|
+
export function clearProviderCache() {
|
|
35
|
+
cache.clear();
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/lib/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;AAI/C,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;IAE7C,IAAI,OAAsB,CAAC;IAC3B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,KAAK;YACR,OAAO,GAAG,IAAI,UAAU,EAAE,CAAC;YAC3B,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,KAAK,OAAO;YACV,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAc,kBAAkB,CAAC,CAAC;IAC3E,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAqB;IAChD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,kBAAkB;IAChC,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Premium license gate.
|
|
3
|
+
* Reads PRO_LICENSE dynamically from process.env at call time — not cached.
|
|
4
|
+
* This allows the license to be set after server start without restart.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Returns true if a valid Pro license is currently set in the environment.
|
|
8
|
+
* A valid key starts with "CPK-" and is at least 8 characters long.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isPro(): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Throws if no valid Pro license is configured.
|
|
13
|
+
* Call at the start of every Pro-gated tool handler.
|
|
14
|
+
*
|
|
15
|
+
* @param toolName - The name of the tool being called, used in the error message.
|
|
16
|
+
*/
|
|
17
|
+
export declare function requirePro(toolName: string): void;
|
|
18
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/premium/gate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,wBAAgB,KAAK,IAAI,OAAO,CAG/B;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQjD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Premium license gate.
|
|
3
|
+
* Reads PRO_LICENSE dynamically from process.env at call time — not cached.
|
|
4
|
+
* This allows the license to be set after server start without restart.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Returns true if a valid Pro license is currently set in the environment.
|
|
8
|
+
* A valid key starts with "CPK-" and is at least 8 characters long.
|
|
9
|
+
*/
|
|
10
|
+
export function isPro() {
|
|
11
|
+
const key = process.env.PRO_LICENSE;
|
|
12
|
+
return Boolean(key && key.length >= 8 && key.startsWith("CPK-"));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Throws if no valid Pro license is configured.
|
|
16
|
+
* Call at the start of every Pro-gated tool handler.
|
|
17
|
+
*
|
|
18
|
+
* @param toolName - The name of the tool being called, used in the error message.
|
|
19
|
+
*/
|
|
20
|
+
export function requirePro(toolName) {
|
|
21
|
+
if (!isPro()) {
|
|
22
|
+
throw new Error(`[${toolName}] requires a Pro license. ` +
|
|
23
|
+
`Get one at https://craftpipe.dev/products/cloudvault-mcp — ` +
|
|
24
|
+
`then set PRO_LICENSE=<your-key> in your environment.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/premium/gate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,UAAU,KAAK;IACnB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IACpC,OAAO,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,IAAI,QAAQ,4BAA4B;YACtC,6DAA6D;YAC7D,sDAAsD,CACzD,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* get_secrets tool — secret names and metadata only.
|
|
3
|
+
* SECURITY: Secret values are NEVER returned, only names and metadata.
|
|
4
|
+
*/
|
|
5
|
+
import { type ProviderName } from '../lib/providers.js';
|
|
6
|
+
export interface GetSecretsInput {
|
|
7
|
+
provider: ProviderName;
|
|
8
|
+
prefix?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function get_secrets(input: GetSecretsInput): Promise<{
|
|
11
|
+
content: {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
}[];
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=get_secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_secrets.d.ts","sourceRoot":"","sources":["../../src/tools/get_secrets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGrE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,eAAe;;;;;GA+CvD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* get_secrets tool — secret names and metadata only.
|
|
3
|
+
* SECURITY: Secret values are NEVER returned, only names and metadata.
|
|
4
|
+
*/
|
|
5
|
+
import { getProvider } from '../lib/providers.js';
|
|
6
|
+
import { getAuditLog } from '../lib/audit.js';
|
|
7
|
+
export async function get_secrets(input) {
|
|
8
|
+
const start = Date.now();
|
|
9
|
+
const audit = getAuditLog();
|
|
10
|
+
try {
|
|
11
|
+
const provider = getProvider(input.provider);
|
|
12
|
+
const secrets = await provider.getSecrets({
|
|
13
|
+
prefix: input.prefix,
|
|
14
|
+
});
|
|
15
|
+
// SECURITY: Ensure no values are ever returned
|
|
16
|
+
const safeSecrets = secrets.map((s) => {
|
|
17
|
+
const safe = s;
|
|
18
|
+
const result = { ...safe };
|
|
19
|
+
// Belt-and-suspenders: remove any value fields that should not be there
|
|
20
|
+
delete result.value;
|
|
21
|
+
delete result.secret_value;
|
|
22
|
+
delete result.secret_string;
|
|
23
|
+
delete result.secret_binary;
|
|
24
|
+
return result;
|
|
25
|
+
});
|
|
26
|
+
audit.log({
|
|
27
|
+
tool_name: 'get_secrets',
|
|
28
|
+
input_summary: audit.sanitize({
|
|
29
|
+
provider: input.provider,
|
|
30
|
+
prefix: input.prefix,
|
|
31
|
+
}),
|
|
32
|
+
result_summary: JSON.stringify({ count: safeSecrets.length }),
|
|
33
|
+
success: true,
|
|
34
|
+
duration_ms: Date.now() - start,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: JSON.stringify({ data: safeSecrets, count: safeSecrets.length }) }],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
42
|
+
audit.log({
|
|
43
|
+
tool_name: 'get_secrets',
|
|
44
|
+
input_summary: audit.sanitize({ provider: input.provider }),
|
|
45
|
+
result_summary: message,
|
|
46
|
+
success: false,
|
|
47
|
+
duration_ms: Date.now() - start,
|
|
48
|
+
});
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=get_secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_secrets.js","sourceRoot":"","sources":["../../src/tools/get_secrets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAO9C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAsB;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC;YACxC,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;QAEH,+CAA+C;QAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACpC,MAAM,IAAI,GAAG,CAAuC,CAAC;YACrD,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;YAC3B,wEAAwE;YACxE,OAAO,MAAM,CAAC,KAAK,CAAC;YACpB,OAAO,MAAM,CAAC,YAAY,CAAC;YAC3B,OAAO,MAAM,CAAC,aAAa,CAAC;YAC5B,OAAO,MAAM,CAAC,aAAa,CAAC;YAC5B,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,GAAG,CAAC;YACR,SAAS,EAAE,aAAa;YACxB,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC;gBAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB,CAAC;YACF,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC;YAC7D,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAChC,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;SAC7G,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,KAAK,CAAC,GAAG,CAAC;YACR,SAAS,EAAE,aAAa;YACxB,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC3D,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAChC,CAAC,CAAC;QACH,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|