slaunt 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +152 -0
- package/dist/audit/risk-engine.d.ts +4 -0
- package/dist/audit/risk-engine.d.ts.map +1 -0
- package/dist/audit/risk-engine.js +173 -0
- package/dist/audit/risk-engine.js.map +1 -0
- package/dist/audit/run.d.ts +13 -0
- package/dist/audit/run.d.ts.map +1 -0
- package/dist/audit/run.js +55 -0
- package/dist/audit/run.js.map +1 -0
- package/dist/classification/builtin-catalog.d.ts +3 -0
- package/dist/classification/builtin-catalog.d.ts.map +1 -0
- package/dist/classification/builtin-catalog.js +283 -0
- package/dist/classification/builtin-catalog.js.map +1 -0
- package/dist/classification/catalog.d.ts +10 -0
- package/dist/classification/catalog.d.ts.map +1 -0
- package/dist/classification/catalog.js +139 -0
- package/dist/classification/catalog.js.map +1 -0
- package/dist/classification/classifier.d.ts +3 -0
- package/dist/classification/classifier.d.ts.map +1 -0
- package/dist/classification/classifier.js +64 -0
- package/dist/classification/classifier.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +187 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/discover.d.ts +8 -0
- package/dist/config/discover.d.ts.map +1 -0
- package/dist/config/discover.js +123 -0
- package/dist/config/discover.js.map +1 -0
- package/dist/config/install.d.ts +10 -0
- package/dist/config/install.d.ts.map +1 -0
- package/dist/config/install.js +143 -0
- package/dist/config/install.js.map +1 -0
- package/dist/config/paths.d.ts +17 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +84 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/demo.d.ts +4 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +99 -0
- package/dist/demo.js.map +1 -0
- package/dist/mcp/introspect.d.ts +9 -0
- package/dist/mcp/introspect.d.ts.map +1 -0
- package/dist/mcp/introspect.js +153 -0
- package/dist/mcp/introspect.js.map +1 -0
- package/dist/report/html.d.ts +4 -0
- package/dist/report/html.d.ts.map +1 -0
- package/dist/report/html.js +96 -0
- package/dist/report/html.js.map +1 -0
- package/dist/tui/render.d.ts +4 -0
- package/dist/tui/render.d.ts.map +1 -0
- package/dist/tui/render.js +132 -0
- package/dist/tui/render.js.map +1 -0
- package/dist/types.d.ts +119 -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 +56 -0
package/dist/demo.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAgB,WAAW,EAAE,MAAM,YAAY,CAAC;AA8ErF,wBAAgB,aAAa,IAAI,uBAAuB,CAUvD;AAED,wBAAgB,UAAU,IAAI,WAAW,EAAE,CAsB1C"}
|
package/dist/demo.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
function server(id, client, clientLabel, name, transport = 'stdio') {
|
|
2
|
+
return {
|
|
3
|
+
id,
|
|
4
|
+
client,
|
|
5
|
+
clientLabel,
|
|
6
|
+
name,
|
|
7
|
+
transport,
|
|
8
|
+
sourcePath: client === 'codex' ? '~/.codex/config.toml' : '~/.claude.json',
|
|
9
|
+
scope: 'user',
|
|
10
|
+
...(transport === 'stdio' ? { command: 'demo-mcp' } : { url: 'https://example.invalid/mcp' }),
|
|
11
|
+
args: [],
|
|
12
|
+
env: {},
|
|
13
|
+
envKeys: [],
|
|
14
|
+
headers: {},
|
|
15
|
+
headerKeys: [],
|
|
16
|
+
enabled: true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const servers = [
|
|
20
|
+
server('claude-github', 'claude-code', 'Claude Code', 'github'),
|
|
21
|
+
server('codex-github', 'codex', 'Codex', 'github'),
|
|
22
|
+
server('claude-railway', 'claude-code', 'Claude Code', 'railway', 'http'),
|
|
23
|
+
server('claude-filesystem', 'claude-code', 'Claude Code', 'filesystem'),
|
|
24
|
+
server('codex-filesystem', 'codex', 'Codex', 'filesystem'),
|
|
25
|
+
server('claude-shell', 'claude-code', 'Claude Code', 'shell'),
|
|
26
|
+
server('codex-shell', 'codex', 'Codex', 'shell'),
|
|
27
|
+
server('codex-secrets', 'codex', 'Codex', 'secrets'),
|
|
28
|
+
];
|
|
29
|
+
function probe(config, tools) {
|
|
30
|
+
return {
|
|
31
|
+
serverId: config.id,
|
|
32
|
+
status: 'ok',
|
|
33
|
+
tools: tools.map(([name, description]) => ({
|
|
34
|
+
serverId: config.id,
|
|
35
|
+
serverName: config.name,
|
|
36
|
+
client: config.client,
|
|
37
|
+
clientLabel: config.clientLabel,
|
|
38
|
+
name,
|
|
39
|
+
description,
|
|
40
|
+
inputSchema: { type: 'object', properties: {} },
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const githubTools = [
|
|
45
|
+
['list_repositories', 'List repositories visible to the authenticated user'],
|
|
46
|
+
['get_file', 'Get a repository file'],
|
|
47
|
+
['search_code', 'Search source code'],
|
|
48
|
+
['create_file', 'Create a repository file'],
|
|
49
|
+
['update_file', 'Update a repository file'],
|
|
50
|
+
['create_pull_request', 'Create a pull request'],
|
|
51
|
+
['merge_pull_request', 'Merge a pull request'],
|
|
52
|
+
];
|
|
53
|
+
const filesystemTools = [
|
|
54
|
+
['list_files', 'List files in an allowed directory'],
|
|
55
|
+
['read_file', 'Read a local file'],
|
|
56
|
+
['write_file', 'Write a local file'],
|
|
57
|
+
['edit_file', 'Edit a local file'],
|
|
58
|
+
['delete_file', 'Delete a local file'],
|
|
59
|
+
];
|
|
60
|
+
const shellTools = [
|
|
61
|
+
['exec_command', 'Execute a shell command'],
|
|
62
|
+
['run_command', 'Run a command in the workspace'],
|
|
63
|
+
['list_processes', 'List running processes'],
|
|
64
|
+
];
|
|
65
|
+
export function demoDiscovery() {
|
|
66
|
+
return {
|
|
67
|
+
clients: [
|
|
68
|
+
{ id: 'claude-code', label: 'Claude Code', detected: true, sources: ['~/.claude.json'] },
|
|
69
|
+
{ id: 'claude-desktop', label: 'Claude Desktop', detected: false, sources: [] },
|
|
70
|
+
{ id: 'codex', label: 'Codex', detected: true, sources: ['~/.codex/config.toml'] },
|
|
71
|
+
],
|
|
72
|
+
servers,
|
|
73
|
+
warnings: [],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function demoProbes() {
|
|
77
|
+
return [
|
|
78
|
+
probe(servers[0], githubTools),
|
|
79
|
+
probe(servers[1], githubTools),
|
|
80
|
+
probe(servers[2], [
|
|
81
|
+
['list_services', 'List Railway services'],
|
|
82
|
+
['get_deployment', 'Get deployment details'],
|
|
83
|
+
['deploy_service', 'Deploy a service to production'],
|
|
84
|
+
['list_variables', 'List configured variable names'],
|
|
85
|
+
['trigger_job', 'Trigger a configured Railway job'],
|
|
86
|
+
]),
|
|
87
|
+
probe(servers[3], [...filesystemTools, ['sync', 'Synchronize an internal workspace']]),
|
|
88
|
+
probe(servers[4], [...filesystemTools, ['company_data.query', 'Run a proprietary company lookup']]),
|
|
89
|
+
probe(servers[5], [...shellTools, ['internal.run_workflow', 'Run an internal workflow']]),
|
|
90
|
+
probe(servers[6], [...shellTools, ['admin.execute', 'Execute an internal administrative action']]),
|
|
91
|
+
probe(servers[7], [
|
|
92
|
+
['get_secret', 'Get a credential'],
|
|
93
|
+
['list_secrets', 'List credential names'],
|
|
94
|
+
['read_credential', 'Read a stored credential'],
|
|
95
|
+
['rotate_secret', 'Rotate a stored credential'],
|
|
96
|
+
]),
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=demo.js.map
|
package/dist/demo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"AAEA,SAAS,MAAM,CACb,EAAU,EACV,MAA8B,EAC9B,WAAmB,EACnB,IAAY,EACZ,SAAS,GAA8B,OAAO;IAE9C,OAAO;QACL,EAAE;QACF,MAAM;QACN,WAAW;QACX,IAAI;QACJ,SAAS;QACT,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,gBAAgB;QAC1E,KAAK,EAAE,MAAM;QACb,GAAG,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,6BAA6B,EAAE,CAAC;QAC7F,IAAI,EAAE,EAAE;QACR,GAAG,EAAE,EAAE;QACP,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,EAAE;QACX,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAG;IACd,MAAM,CAAC,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,CAAC;IAC/D,MAAM,CAAC,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;IAClD,MAAM,CAAC,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC;IACzE,MAAM,CAAC,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,CAAC;IACvE,MAAM,CAAC,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC;IAC1D,MAAM,CAAC,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,CAAC;IAC7D,MAAM,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;IAChD,MAAM,CAAC,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC;CACrD,CAAC;AAEF,SAAS,KAAK,CAAC,MAAoB,EAAE,KAA8B;IACjE,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;YACzC,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,IAAI;YACJ,WAAW;YACX,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;SAChD,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED,MAAM,WAAW,GAA4B;IAC3C,CAAC,mBAAmB,EAAE,qDAAqD,CAAC;IAC5E,CAAC,UAAU,EAAE,uBAAuB,CAAC;IACrC,CAAC,aAAa,EAAE,oBAAoB,CAAC;IACrC,CAAC,aAAa,EAAE,0BAA0B,CAAC;IAC3C,CAAC,aAAa,EAAE,0BAA0B,CAAC;IAC3C,CAAC,qBAAqB,EAAE,uBAAuB,CAAC;IAChD,CAAC,oBAAoB,EAAE,sBAAsB,CAAC;CAC/C,CAAC;AAEF,MAAM,eAAe,GAA4B;IAC/C,CAAC,YAAY,EAAE,oCAAoC,CAAC;IACpD,CAAC,WAAW,EAAE,mBAAmB,CAAC;IAClC,CAAC,YAAY,EAAE,oBAAoB,CAAC;IACpC,CAAC,WAAW,EAAE,mBAAmB,CAAC;IAClC,CAAC,aAAa,EAAE,qBAAqB,CAAC;CACvC,CAAC;AAEF,MAAM,UAAU,GAA4B;IAC1C,CAAC,cAAc,EAAE,yBAAyB,CAAC;IAC3C,CAAC,aAAa,EAAE,gCAAgC,CAAC;IACjD,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;CAC7C,CAAC;AAEF,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,OAAO,EAAE;YACP,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE;YACxF,EAAE,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;YAC/E,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE;SACnF;QACD,OAAO;QACP,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,WAAW,CAAC;QAC/B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,WAAW,CAAC;QAC/B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE;YACjB,CAAC,eAAe,EAAE,uBAAuB,CAAC;YAC1C,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;YAC5C,CAAC,gBAAgB,EAAE,gCAAgC,CAAC;YACpD,CAAC,gBAAgB,EAAE,gCAAgC,CAAC;YACpD,CAAC,aAAa,EAAE,kCAAkC,CAAC;SACpD,CAAC;QACF,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,MAAM,EAAE,mCAAmC,CAAC,CAAC,CAAC;QACvF,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,CAAC,GAAG,eAAe,EAAE,CAAC,oBAAoB,EAAE,kCAAkC,CAAC,CAAC,CAAC;QACpG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,uBAAuB,EAAE,0BAA0B,CAAC,CAAC,CAAC;QAC1F,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,eAAe,EAAE,2CAA2C,CAAC,CAAC,CAAC;QACnG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE;YACjB,CAAC,YAAY,EAAE,kBAAkB,CAAC;YAClC,CAAC,cAAc,EAAE,uBAAuB,CAAC;YACzC,CAAC,iBAAiB,EAAE,0BAA0B,CAAC;YAC/C,CAAC,eAAe,EAAE,4BAA4B,CAAC;SAChD,CAAC;KACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ServerConfig, ServerProbe } from '../types.js';
|
|
2
|
+
export interface ProbeOptions {
|
|
3
|
+
allowServerStarts: boolean;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
concurrency?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function probeServers(servers: ServerConfig[], options: ProbeOptions): Promise<ServerProbe[]>;
|
|
8
|
+
export declare function isDynamicLauncher(server: ServerConfig): boolean;
|
|
9
|
+
//# sourceMappingURL=introspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/mcp/introspect.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAgB,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAqJ3E,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAMzG;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAG/D"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
4
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
5
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
6
|
+
function resolvedEnvironment(configured) {
|
|
7
|
+
const inherited = Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === 'string'));
|
|
8
|
+
return { ...inherited, ...configured };
|
|
9
|
+
}
|
|
10
|
+
function expandEnvironment(value) {
|
|
11
|
+
return value.replace(/\$\{([A-Z_][A-Z0-9_]*)(?::-([^}]*))?\}/gi, (_match, name, fallback) => {
|
|
12
|
+
return process.env[name] ?? fallback ?? '';
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function redactedError(error, server) {
|
|
16
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
for (const value of [...Object.values(server.env), ...Object.values(server.headers)]) {
|
|
18
|
+
if (value.length >= 4)
|
|
19
|
+
message = message.replaceAll(value, '[redacted]');
|
|
20
|
+
}
|
|
21
|
+
message = message
|
|
22
|
+
.replace(/(bearer\s+)[a-z0-9._~+/=-]+/gi, '$1[redacted]')
|
|
23
|
+
.replace(/([?&](?:token|key|secret|password)=)[^&\s]+/gi, '$1[redacted]');
|
|
24
|
+
return message.slice(0, 300);
|
|
25
|
+
}
|
|
26
|
+
function asInputSchema(value) {
|
|
27
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
28
|
+
? value
|
|
29
|
+
: undefined;
|
|
30
|
+
}
|
|
31
|
+
async function listAllTools(client, server) {
|
|
32
|
+
const tools = [];
|
|
33
|
+
let cursor;
|
|
34
|
+
do {
|
|
35
|
+
const response = await client.listTools(cursor ? { cursor } : undefined);
|
|
36
|
+
for (const tool of response.tools) {
|
|
37
|
+
const inputSchema = asInputSchema(tool.inputSchema);
|
|
38
|
+
tools.push({
|
|
39
|
+
serverId: server.id,
|
|
40
|
+
serverName: server.name,
|
|
41
|
+
client: server.client,
|
|
42
|
+
clientLabel: server.clientLabel,
|
|
43
|
+
name: tool.name,
|
|
44
|
+
description: tool.description || '',
|
|
45
|
+
...(inputSchema ? { inputSchema } : {}),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
cursor = response.nextCursor;
|
|
49
|
+
} while (cursor);
|
|
50
|
+
return tools;
|
|
51
|
+
}
|
|
52
|
+
async function connectAndList(server, transport) {
|
|
53
|
+
const client = new Client({ name: 'slaunt-audit', version: '0.1.0' }, { capabilities: {} });
|
|
54
|
+
try {
|
|
55
|
+
// The SDK's transport classes declare `sessionId?: string` while its shared
|
|
56
|
+
// Transport interface is emitted without exact-optional compatibility.
|
|
57
|
+
await client.connect(transport);
|
|
58
|
+
return await listAllTools(client, server);
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
await client.close().catch(() => undefined);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function withTimeout(operation, milliseconds, onTimeout) {
|
|
65
|
+
let timer;
|
|
66
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
67
|
+
timer = setTimeout(() => {
|
|
68
|
+
void onTimeout().finally(() => reject(new Error(`MCP probe timed out after ${milliseconds} ms`)));
|
|
69
|
+
}, milliseconds);
|
|
70
|
+
});
|
|
71
|
+
try {
|
|
72
|
+
return await Promise.race([operation, timeout]);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
if (timer)
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function probeServer(server, allowServerStarts, timeoutMs) {
|
|
80
|
+
if (server.transport === 'stdio') {
|
|
81
|
+
if (!allowServerStarts) {
|
|
82
|
+
return { serverId: server.id, status: 'skipped', tools: [], message: 'Local server start was not approved' };
|
|
83
|
+
}
|
|
84
|
+
if (!server.command)
|
|
85
|
+
return { serverId: server.id, status: 'failed', tools: [], message: 'Missing stdio command' };
|
|
86
|
+
try {
|
|
87
|
+
const transport = new StdioClientTransport({
|
|
88
|
+
command: expandEnvironment(server.command),
|
|
89
|
+
args: server.args.map(expandEnvironment),
|
|
90
|
+
env: resolvedEnvironment(server.env),
|
|
91
|
+
stderr: 'pipe',
|
|
92
|
+
});
|
|
93
|
+
const tools = await withTimeout(connectAndList(server, transport), timeoutMs, () => transport.close());
|
|
94
|
+
return { serverId: server.id, status: 'ok', tools };
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
return { serverId: server.id, status: 'failed', tools: [], message: redactedError(error, server) };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if ((server.transport === 'http' || server.transport === 'sse') && server.url) {
|
|
101
|
+
try {
|
|
102
|
+
const endpoint = new URL(expandEnvironment(server.url));
|
|
103
|
+
const headers = Object.fromEntries(Object.entries(server.headers).map(([name, value]) => [name, expandEnvironment(value)]));
|
|
104
|
+
const requestInit = { headers, redirect: 'error' };
|
|
105
|
+
if (server.transport === 'sse') {
|
|
106
|
+
const transport = new SSEClientTransport(endpoint, { requestInit });
|
|
107
|
+
const tools = await withTimeout(connectAndList(server, transport), timeoutMs, () => transport.close());
|
|
108
|
+
return { serverId: server.id, status: 'ok', tools };
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const transport = new StreamableHTTPClientTransport(endpoint, { requestInit });
|
|
112
|
+
const tools = await withTimeout(connectAndList(server, transport), timeoutMs, () => transport.close());
|
|
113
|
+
return { serverId: server.id, status: 'ok', tools };
|
|
114
|
+
}
|
|
115
|
+
catch (streamableError) {
|
|
116
|
+
const message = redactedError(streamableError, server);
|
|
117
|
+
if (!/4\d\d|sse|method|content[- ]type/i.test(message))
|
|
118
|
+
throw streamableError;
|
|
119
|
+
const transport = new SSEClientTransport(endpoint, { requestInit });
|
|
120
|
+
const tools = await withTimeout(connectAndList(server, transport), timeoutMs, () => transport.close());
|
|
121
|
+
return { serverId: server.id, status: 'ok', tools };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
return { serverId: server.id, status: 'failed', tools: [], message: redactedError(error, server) };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { serverId: server.id, status: 'skipped', tools: [], message: `Unsupported ${server.transport} transport` };
|
|
129
|
+
}
|
|
130
|
+
async function mapWithConcurrency(items, concurrency, mapper) {
|
|
131
|
+
const results = new Array(items.length);
|
|
132
|
+
let next = 0;
|
|
133
|
+
async function worker() {
|
|
134
|
+
while (true) {
|
|
135
|
+
const index = next++;
|
|
136
|
+
if (index >= items.length)
|
|
137
|
+
return;
|
|
138
|
+
const item = items[index];
|
|
139
|
+
if (item !== undefined)
|
|
140
|
+
results[index] = await mapper(item);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker));
|
|
144
|
+
return results;
|
|
145
|
+
}
|
|
146
|
+
export async function probeServers(servers, options) {
|
|
147
|
+
return mapWithConcurrency(servers, options.concurrency || 4, (server) => probeServer(server, options.allowServerStarts, options.timeoutMs || 8_000));
|
|
148
|
+
}
|
|
149
|
+
export function isDynamicLauncher(server) {
|
|
150
|
+
const command = server.command ? basename(server.command).toLowerCase() : '';
|
|
151
|
+
return ['npx', 'uvx', 'docker', 'podman', 'bunx', 'pnpx'].includes(command);
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=introspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/mcp/introspect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/report/html.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAwB,MAAM,aAAa,CAAC;AAqCrE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAgC5D;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B/F"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { access, link, mkdir, unlink, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
function escapeHtml(value) {
|
|
5
|
+
return String(value)
|
|
6
|
+
.replaceAll('&', '&')
|
|
7
|
+
.replaceAll('<', '<')
|
|
8
|
+
.replaceAll('>', '>')
|
|
9
|
+
.replaceAll('"', '"')
|
|
10
|
+
.replaceAll("'", ''');
|
|
11
|
+
}
|
|
12
|
+
const severityLabels = {
|
|
13
|
+
critical: 'Critical', high: 'High', medium: 'Medium', low: 'Low', info: 'Info',
|
|
14
|
+
};
|
|
15
|
+
const capabilityLabels = {
|
|
16
|
+
'read-data': 'Read data', 'write-data': 'Write data', 'read-files': 'Read files',
|
|
17
|
+
'write-files': 'Write files', 'delete-data': 'Delete data', 'execute-code': 'Execute code',
|
|
18
|
+
'execute-shell': 'Execute commands', 'read-secrets': 'Read credentials', 'manage-auth': 'Manage identity',
|
|
19
|
+
'network-access': 'Access network', 'deploy-production': 'Deploy production', 'edit-code': 'Edit code',
|
|
20
|
+
'create-pull-request': 'Create pull requests', 'merge-pull-request': 'Merge pull requests',
|
|
21
|
+
'administer-system': 'Administer systems', 'control-browser': 'Control browser', 'send-message': 'Send messages',
|
|
22
|
+
};
|
|
23
|
+
function accessOverview(result) {
|
|
24
|
+
return result.discovery.clients.filter((client) => client.detected).map((client) => {
|
|
25
|
+
const servers = result.discovery.servers.filter((server) => server.client === client.id);
|
|
26
|
+
const rows = servers.map((server) => {
|
|
27
|
+
const capabilities = [...new Set(result.tools
|
|
28
|
+
.filter((tool) => tool.serverId === server.id)
|
|
29
|
+
.flatMap((tool) => tool.classification.capabilities))];
|
|
30
|
+
return `<tr><td>${escapeHtml(server.name)}</td><td>${escapeHtml(capabilities.map((item) => capabilityLabels[item]).join(', ') || 'Tool list unavailable')}</td></tr>`;
|
|
31
|
+
}).join('');
|
|
32
|
+
return `<section class="client"><h3>${escapeHtml(client.label)}</h3><table><tbody>${rows}</tbody></table></section>`;
|
|
33
|
+
}).join('');
|
|
34
|
+
}
|
|
35
|
+
export function renderHtmlReport(result) {
|
|
36
|
+
const summary = result.summary;
|
|
37
|
+
const findings = result.findings.map((item) => `
|
|
38
|
+
<article class="finding ${escapeHtml(item.severity)}">
|
|
39
|
+
<div class="severity">${severityLabels[item.severity]}</div>
|
|
40
|
+
<h3>${escapeHtml(item.title)}</h3>
|
|
41
|
+
${item.serverNames.length ? `<p><strong>Servers:</strong> ${escapeHtml(item.serverNames.join(', '))}</p>` : ''}
|
|
42
|
+
${item.toolNames.length ? `<p><strong>Tools:</strong> ${escapeHtml(item.toolNames.join(', '))}</p>` : ''}
|
|
43
|
+
<p><strong>Why flagged:</strong> ${escapeHtml(item.why)}</p>
|
|
44
|
+
<p><strong>Recommendation:</strong> ${escapeHtml(item.recommendation)}</p>
|
|
45
|
+
</article>`).join('');
|
|
46
|
+
const unknown = result.tools.filter((tool) => tool.classification.source === 'unknown');
|
|
47
|
+
const scoreClass = summary.postureScore >= 80 ? 'good' : summary.postureScore >= 55 ? 'warn' : 'bad';
|
|
48
|
+
return `<!doctype html>
|
|
49
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
50
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:">
|
|
51
|
+
<title>Slaunt Agent Access Audit</title><style>
|
|
52
|
+
:root{color-scheme:light dark;--bg:#0b0d12;--card:#141821;--ink:#f4f6fb;--muted:#9ba6b8;--line:#293142;--accent:#8b5cf6;--critical:#ff4d6d;--high:#ff8a4c;--medium:#f7c948;--low:#48cae4}*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at 15% 0,#24164a 0,transparent 32%),var(--bg);color:var(--ink);font:15px/1.55 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}main{width:min(1060px,calc(100% - 32px));margin:0 auto;padding:64px 0 96px}header{display:grid;grid-template-columns:1fr auto;gap:24px;align-items:end;padding-bottom:36px;border-bottom:1px solid var(--line)}.eyebrow{color:#b69cff;text-transform:uppercase;letter-spacing:.14em;font-size:12px;font-weight:800}h1{font-size:clamp(34px,6vw,64px);line-height:1;margin:.18em 0}.sub{color:var(--muted);max-width:640px}.score{width:136px;height:136px;border-radius:50%;display:grid;place-items:center;background:conic-gradient(var(--accent) calc(var(--score)*1%),#252b38 0);position:relative}.score:before{content:"";position:absolute;inset:9px;border-radius:50%;background:var(--card)}.score span{position:relative;font-size:38px;font-weight:850}.score small{display:block;font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.1em}.metrics{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin:28px 0}.metric{padding:18px;background:color-mix(in srgb,var(--card) 92%,transparent);border:1px solid var(--line);border-radius:14px}.metric b{display:block;font-size:28px}.metric span{color:var(--muted);font-size:12px}h2{margin:52px 0 18px;font-size:24px}.finding{border:1px solid var(--line);border-left-width:4px;border-radius:14px;background:var(--card);padding:22px;margin:14px 0}.finding.critical{border-left-color:var(--critical)}.finding.high{border-left-color:var(--high)}.finding.medium{border-left-color:var(--medium)}.finding.low{border-left-color:var(--low)}.finding h3{margin:4px 0 12px}.finding p{margin:7px 0;color:#cbd3df}.severity{text-transform:uppercase;letter-spacing:.12em;font-size:11px;font-weight:900}.critical .severity{color:var(--critical)}.high .severity{color:var(--high)}.medium .severity{color:var(--medium)}.low .severity{color:var(--low)}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}.client{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:18px}.client h3{margin:0 0 12px}table{width:100%;border-collapse:collapse}td{padding:9px 0;border-top:1px solid var(--line);vertical-align:top}td:first-child{font-weight:750;width:32%}td:last-child{color:var(--muted)}code{background:#202635;padding:.15em .38em;border-radius:5px}.notice{padding:18px;border:1px solid #4c3a86;background:#171229;border-radius:14px;color:#d9cffc}.unknown{columns:2;margin:0;padding-left:22px}.unknown li{break-inside:avoid;padding:3px}.cta{margin-top:52px;padding:30px;border-radius:18px;background:linear-gradient(130deg,#5b21b6,#312e81);box-shadow:0 22px 70px #5b21b633}.cta h2{margin:0 0 8px}.cta a{display:inline-block;margin-top:12px;background:white;color:#28145d;text-decoration:none;font-weight:850;padding:11px 16px;border-radius:9px}.fine{font-size:12px;color:var(--muted);margin-top:42px}@media(max-width:800px){header{grid-template-columns:1fr}.metrics{grid-template-columns:repeat(2,1fr)}.grid{grid-template-columns:1fr}.unknown{columns:1}}
|
|
53
|
+
</style></head><body><main>
|
|
54
|
+
<header><div><div class="eyebrow">Slaunt audit</div><h1>Agent access, mapped.</h1><p class="sub">A local-first inventory of MCP tools exposed to Claude and Codex. No tool was called and no audit payload was uploaded.</p></div><div class="score ${scoreClass}" style="--score:${summary.postureScore}"><span>${summary.postureScore}<small>posture</small></span></div></header>
|
|
55
|
+
<section class="metrics">
|
|
56
|
+
<div class="metric"><b>${summary.clientsDetected}</b><span>Clients</span></div><div class="metric"><b>${summary.servers}</b><span>MCP servers</span></div><div class="metric"><b>${summary.tools}</b><span>Tools exposed</span></div><div class="metric"><b>${summary.sensitiveCapabilities}</b><span>Sensitive tools</span></div><div class="metric"><b>${summary.highRiskFindings}</b><span>High-risk findings</span></div><div class="metric"><b>${summary.unclassified}</b><span>Unclassified</span></div>
|
|
57
|
+
</section>
|
|
58
|
+
<div class="notice">Classification catalog: <strong>${escapeHtml(result.privacy.catalogSource)}</strong>. Tool names, descriptions, schemas, configuration values, and findings remained on this machine.</div>
|
|
59
|
+
<h2>Needs attention</h2>${findings || '<p>No correlated high-risk paths were identified from the available declarations.</p>'}
|
|
60
|
+
<h2>Access overview</h2><div class="grid">${accessOverview(result)}</div>
|
|
61
|
+
<h2>Classification coverage</h2><p><strong>${summary.classified}</strong> verified or recognized · <strong>${summary.unclassified}</strong> unknown</p>
|
|
62
|
+
${unknown.length ? `<ul class="unknown">${unknown.map((tool) => `<li><code>${escapeHtml(tool.name)}</code> <span>(${escapeHtml(tool.serverName)})</span></li>`).join('')}</ul>` : '<p>Every retrieved tool matched a catalog rule.</p>'}
|
|
63
|
+
<section class="cta"><h2>You found the paths. Put guardrails on them.</h2><p>Slaunt can add role-scoped access, approvals, continuous monitoring, and remote shutdown around the MCP stack you already use. You choose when to connect.</p><a href="https://slaunt.ai/setup">Create a Slaunt workspace →</a></section>
|
|
64
|
+
<p class="fine">Scope: configured MCP servers and their declared tools only. This audit did not inspect prompts, file contents, credentials, non-MCP agents, or whether any tool has been used. Generated ${escapeHtml(result.generatedAt)}.</p>
|
|
65
|
+
</main></body></html>`;
|
|
66
|
+
}
|
|
67
|
+
export async function writeHtmlReport(result, outputPath) {
|
|
68
|
+
const date = result.generatedAt.slice(0, 10);
|
|
69
|
+
const requested = resolve(outputPath || `slaunt-audit-${date}.html`);
|
|
70
|
+
let path = requested;
|
|
71
|
+
if (outputPath) {
|
|
72
|
+
await access(path).then(() => { throw new Error(`refusing to overwrite existing report: ${path}`); }, () => undefined);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
for (let suffix = 2; suffix < 1_000; suffix += 1) {
|
|
76
|
+
try {
|
|
77
|
+
await access(path);
|
|
78
|
+
path = resolve(`slaunt-audit-${date}-${suffix}.html`);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const temporary = `${path}.${randomBytes(10).toString('hex')}.tmp`;
|
|
86
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
87
|
+
try {
|
|
88
|
+
await writeFile(temporary, renderHtmlReport(result), { encoding: 'utf8', mode: 0o600, flag: 'wx' });
|
|
89
|
+
await link(temporary, path);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
await unlink(temporary).catch(() => undefined);
|
|
93
|
+
}
|
|
94
|
+
return path;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/report/html.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/tui/render.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAiC,MAAM,aAAa,CAAC;AAsE9E,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAoFvD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
const capabilityLabels = {
|
|
3
|
+
'read-data': 'Read data', 'write-data': 'Write data', 'read-files': 'Read files',
|
|
4
|
+
'write-files': 'Write files', 'delete-data': 'Delete data', 'execute-code': 'Execute code',
|
|
5
|
+
'execute-shell': 'Execute commands', 'read-secrets': 'Read credentials', 'manage-auth': 'Manage identity',
|
|
6
|
+
'network-access': 'Network access', 'deploy-production': 'View and deploy', 'edit-code': 'Edit code',
|
|
7
|
+
'create-pull-request': 'Create pull requests', 'merge-pull-request': 'Merge pull requests',
|
|
8
|
+
'administer-system': 'Administer systems', 'control-browser': 'Control browser', 'send-message': 'Send messages',
|
|
9
|
+
};
|
|
10
|
+
const severityColor = {
|
|
11
|
+
critical: chalk.bgRed.white.bold,
|
|
12
|
+
high: chalk.hex('#ff8a4c').bold,
|
|
13
|
+
medium: chalk.yellow.bold,
|
|
14
|
+
low: chalk.cyan.bold,
|
|
15
|
+
info: chalk.gray,
|
|
16
|
+
};
|
|
17
|
+
function width() {
|
|
18
|
+
return Math.max(54, Math.min(76, process.stdout.columns || 76));
|
|
19
|
+
}
|
|
20
|
+
function divider(character = '─') {
|
|
21
|
+
return chalk.gray(character.repeat(width()));
|
|
22
|
+
}
|
|
23
|
+
function row(label, value) {
|
|
24
|
+
const valueText = String(value);
|
|
25
|
+
return `${label}${' '.repeat(Math.max(2, width() - label.length - valueText.length))}${chalk.bold(valueText)}`;
|
|
26
|
+
}
|
|
27
|
+
function findingBlock(item) {
|
|
28
|
+
const lines = [
|
|
29
|
+
severityColor[item.severity](item.severity.toUpperCase()),
|
|
30
|
+
chalk.bold(item.title),
|
|
31
|
+
];
|
|
32
|
+
if (item.serverNames.length)
|
|
33
|
+
lines.push('', ` ${chalk.gray(item.serverNames.length > 1 ? 'Servers:' : 'Server:')} ${item.serverNames.join(', ')}`);
|
|
34
|
+
if (item.toolNames.length === 1)
|
|
35
|
+
lines.push(` ${chalk.gray('Tool:')} ${item.toolNames[0]}`);
|
|
36
|
+
if (item.access.length) {
|
|
37
|
+
lines.push(` ${chalk.gray('Access:')}`);
|
|
38
|
+
for (const access of item.access)
|
|
39
|
+
lines.push(` ${chalk.hex('#a78bfa')('•')} ${access}`);
|
|
40
|
+
}
|
|
41
|
+
lines.push('', ` ${chalk.gray('Why flagged:')} ${item.why}`, ` ${chalk.gray('Recommendation:')} ${item.recommendation}`);
|
|
42
|
+
return lines.join('\n');
|
|
43
|
+
}
|
|
44
|
+
function accessOverview(result) {
|
|
45
|
+
const blocks = [];
|
|
46
|
+
for (const client of result.discovery.clients.filter((item) => item.detected)) {
|
|
47
|
+
blocks.push(chalk.bold(client.label));
|
|
48
|
+
for (const server of result.discovery.servers.filter((item) => item.client === client.id)) {
|
|
49
|
+
const capabilities = [...new Set(result.tools
|
|
50
|
+
.filter((tool) => tool.serverId === server.id)
|
|
51
|
+
.flatMap((tool) => tool.classification.capabilities))];
|
|
52
|
+
const label = server.name.slice(0, 16).padEnd(16);
|
|
53
|
+
blocks.push(` ${chalk.hex('#c4b5fd')(label)}${capabilities.length ? capabilities.slice(0, 4).map((item) => capabilityLabels[item]).join(', ') : chalk.gray('Tool list unavailable')}`);
|
|
54
|
+
}
|
|
55
|
+
blocks.push('');
|
|
56
|
+
}
|
|
57
|
+
return blocks.join('\n').trimEnd();
|
|
58
|
+
}
|
|
59
|
+
function postureBar(score) {
|
|
60
|
+
const slots = 20;
|
|
61
|
+
const filled = Math.round(score / 100 * slots);
|
|
62
|
+
const color = score >= 80 ? chalk.green : score >= 55 ? chalk.yellow : chalk.red;
|
|
63
|
+
return `${color('█'.repeat(filled))}${chalk.gray('░'.repeat(slots - filled))} ${chalk.bold(String(score))}/100`;
|
|
64
|
+
}
|
|
65
|
+
export function renderAudit(result) {
|
|
66
|
+
const summary = result.summary;
|
|
67
|
+
const unknown = result.tools.filter((tool) => tool.classification.source === 'unknown');
|
|
68
|
+
const failedProbes = result.probes.filter((probe) => probe.status !== 'ok');
|
|
69
|
+
const lines = [
|
|
70
|
+
'',
|
|
71
|
+
chalk.bold('Slaunt Agent Access Audit'),
|
|
72
|
+
chalk.gray('Inspecting MCP configurations locally. No audit payload uploaded.'),
|
|
73
|
+
'',
|
|
74
|
+
`${chalk.green('✓')} Found ${summary.clientsDetected} agent client${summary.clientsDetected === 1 ? '' : 's'}`,
|
|
75
|
+
`${chalk.green('✓')} Found ${summary.servers} MCP server${summary.servers === 1 ? '' : 's'}`,
|
|
76
|
+
`${chalk.green('✓')} Retrieved ${summary.tools} tool definition${summary.tools === 1 ? '' : 's'}`,
|
|
77
|
+
`${chalk.green('✓')} Classified ${summary.classified} tool${summary.classified === 1 ? '' : 's'}`,
|
|
78
|
+
summary.unclassified > 0
|
|
79
|
+
? `${chalk.yellow('!')} ${summary.unclassified} tool${summary.unclassified === 1 ? '' : 's'} require review`
|
|
80
|
+
: `${chalk.green('✓')} Every retrieved tool is recognized`,
|
|
81
|
+
'',
|
|
82
|
+
divider(),
|
|
83
|
+
'',
|
|
84
|
+
chalk.bold('Audit summary'),
|
|
85
|
+
'',
|
|
86
|
+
row('Clients detected', summary.clientsDetected),
|
|
87
|
+
row('MCP servers', summary.servers),
|
|
88
|
+
row('Tools exposed', summary.tools),
|
|
89
|
+
row('Sensitive capabilities', summary.sensitiveCapabilities),
|
|
90
|
+
row('High-risk findings', summary.highRiskFindings),
|
|
91
|
+
row('Unclassified tools', summary.unclassified),
|
|
92
|
+
'',
|
|
93
|
+
`${'Security posture'.padEnd(22)}${postureBar(summary.postureScore)}`,
|
|
94
|
+
'',
|
|
95
|
+
divider(),
|
|
96
|
+
'',
|
|
97
|
+
chalk.bold('Needs attention'),
|
|
98
|
+
'',
|
|
99
|
+
result.findings.length ? result.findings.map(findingBlock).join(`\n\n${chalk.gray('·'.repeat(20))}\n\n`) : chalk.green('No correlated high-risk paths were identified.'),
|
|
100
|
+
'',
|
|
101
|
+
divider(),
|
|
102
|
+
'',
|
|
103
|
+
chalk.bold('Access overview'),
|
|
104
|
+
'',
|
|
105
|
+
accessOverview(result) || chalk.gray('No MCP access was discovered.'),
|
|
106
|
+
'',
|
|
107
|
+
divider(),
|
|
108
|
+
'',
|
|
109
|
+
chalk.bold('Classification coverage'),
|
|
110
|
+
'',
|
|
111
|
+
`${summary.classified} verified or recognized`,
|
|
112
|
+
`${String(summary.unclassified).padStart(String(summary.classified).length)} unknown`,
|
|
113
|
+
];
|
|
114
|
+
if (unknown.length) {
|
|
115
|
+
lines.push('', 'Unknown tools:', ...unknown.map((tool) => ` ${chalk.yellow('•')} ${tool.name}`), '', chalk.gray('Unknown tools are treated as potentially sensitive until reviewed.'));
|
|
116
|
+
}
|
|
117
|
+
if (failedProbes.length) {
|
|
118
|
+
lines.push('', chalk.bold('Unavailable tool inventories'), '', ...failedProbes.map((probe) => {
|
|
119
|
+
const server = result.discovery.servers.find((item) => item.id === probe.serverId);
|
|
120
|
+
return ` ${chalk.yellow('!')} ${server?.clientLabel || 'Client'} / ${server?.name || probe.serverId}: ${probe.message || probe.status}`;
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
lines.push('', divider(), '', chalk.bold('Audit scope'), '', 'This audit inspected configured MCP servers and their declared tools.', 'It did not call tools or inspect prompts, files, credentials, or non-MCP agents.', 'It did not determine whether any exposed tool has actually been used.', '', chalk.bgHex('#5b21b6').white.bold(' MAP COMPLETE '), '', chalk.bold('You found the paths. Put guardrails on them.'), `Slaunt can add approvals, role-scoped access, continuous monitoring, and`, `remote shutdown around the MCP stack you already use. ${chalk.bold('You choose when to connect.')}`, '', `${chalk.hex('#a78bfa')('Create your Slaunt workspace →')} ${chalk.underline('https://slaunt.ai/setup')}`);
|
|
124
|
+
if (result.discovery.warnings.length) {
|
|
125
|
+
lines.push('', chalk.gray(`Notes: ${result.discovery.warnings.join(' · ')}`));
|
|
126
|
+
}
|
|
127
|
+
return lines.join('\n');
|
|
128
|
+
}
|
|
129
|
+
export function renderHeader() {
|
|
130
|
+
return `\n${chalk.bold.hex('#a78bfa')('SLAUNT')} ${chalk.bold('agent access audit')}\n${chalk.gray('Local-first MCP exposure mapping')}`;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/tui/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,gBAAgB,GAA+B;IACnD,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY;IAChF,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc;IAC1F,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,iBAAiB;IACzG,gBAAgB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW;IACpG,qBAAqB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,qBAAqB;IAC1F,mBAAmB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe;CACjH,CAAC;AAEF,MAAM,aAAa,GAAgD;IACjE,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI;IAChC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI;IAC/B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;IACzB,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI;IACpB,IAAI,EAAE,KAAK,CAAC,IAAI;CACjB,CAAC;AAEF,SAAS,KAAK;IACZ,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,OAAO,CAAC,SAAS,GAAG,GAAG;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,GAAG,CAAC,KAAa,EAAE,KAAa;IACvC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,GAAG,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;AACjH,CAAC;AAED,SAAS,YAAY,CAAC,IAAa;IACjC,MAAM,KAAK,GAAG;QACZ,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QACzD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;KACvB,CAAC;IACF,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpJ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7F,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACzC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;IAC3H,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,MAAmB;IACzC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9E,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAC1F,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK;qBAC1C,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC;qBAC7C,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACzD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClD,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC;QAC1L,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;IACjF,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAClH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAmB;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;IACxF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAa;QACtB,EAAE;QACF,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,mEAAmE,CAAC;QAC/E,EAAE;QACF,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,OAAO,CAAC,eAAe,gBAAgB,OAAO,CAAC,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QAC9G,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,OAAO,CAAC,OAAO,cAAc,OAAO,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QAC5F,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,KAAK,mBAAmB,OAAO,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QACjG,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,UAAU,QAAQ,OAAO,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QACjG,OAAO,CAAC,YAAY,GAAG,CAAC;YACtB,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,YAAY,QAAQ,OAAO,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,iBAAiB;YAC5G,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,qCAAqC;QAC5D,EAAE;QACF,OAAO,EAAE;QACT,EAAE;QACF,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;QAC3B,EAAE;QACF,GAAG,CAAC,kBAAkB,EAAE,OAAO,CAAC,eAAe,CAAC;QAChD,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC;QACnC,GAAG,CAAC,eAAe,EAAE,OAAO,CAAC,KAAK,CAAC;QACnC,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,qBAAqB,CAAC;QAC5D,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,gBAAgB,CAAC;QACnD,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,YAAY,CAAC;QAC/C,EAAE;QACF,GAAG,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;QACrE,EAAE;QACF,OAAO,EAAE;QACT,EAAE;QACF,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC;QAC7B,EAAE;QACF,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,gDAAgD,CAAC;QACxK,EAAE;QACF,OAAO,EAAE;QACT,EAAE;QACF,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC;QAC7B,EAAE;QACF,cAAc,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC;QACrE,EAAE;QACF,OAAO,EAAE;QACT,EAAE;QACF,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC;QACrC,EAAE;QACF,GAAG,OAAO,CAAC,UAAU,yBAAyB;QAC9C,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,UAAU;KACtF,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC,CAAC;IAC1L,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,EAAE,EAAE,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAC3F,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC;YACnF,OAAO,KAAK,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,MAAM,EAAE,WAAW,IAAI,QAAQ,MAAM,MAAM,EAAE,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC3I,CAAC,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,IAAI,CACR,EAAE,EACF,OAAO,EAAE,EACT,EAAE,EACF,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,EACzB,EAAE,EACF,uEAAuE,EACvE,kFAAkF,EAClF,uEAAuE,EACvE,EAAE,EACF,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,EACrD,EAAE,EACF,KAAK,CAAC,IAAI,CAAC,8CAA8C,CAAC,EAC1D,0EAA0E,EAC1E,yDAAyD,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,EAAE,EACpG,EAAE,EACF,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,gCAAgC,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,yBAAyB,CAAC,EAAE,CAC1G,CAAC;IAEF,IAAI,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,kCAAkC,CAAC,EAAE,CAAC;AAC3I,CAAC"}
|