@blacksandscyber/mcp-server-bursar 0.5.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/README.md +230 -0
- package/build/config.d.ts +45 -0
- package/build/config.js +177 -0
- package/build/http-transport.d.ts +16 -0
- package/build/http-transport.js +191 -0
- package/build/index.d.ts +16 -0
- package/build/index.js +31 -0
- package/build/server.d.ts +41 -0
- package/build/server.js +902 -0
- package/build/shared/errors.d.ts +50 -0
- package/build/shared/errors.js +69 -0
- package/build/shared/linkBuilder.d.ts +93 -0
- package/build/shared/linkBuilder.js +148 -0
- package/build/shared/logger.d.ts +10 -0
- package/build/shared/logger.js +28 -0
- package/build/shield/bootRole.d.ts +60 -0
- package/build/shield/bootRole.js +145 -0
- package/build/shield/client.d.ts +265 -0
- package/build/shield/client.js +656 -0
- package/build/shield/deploy/index.d.ts +69 -0
- package/build/shield/deploy/index.js +569 -0
- package/build/shield/discovery/dataStoreDetector.d.ts +3 -0
- package/build/shield/discovery/dataStoreDetector.js +125 -0
- package/build/shield/discovery/dockerScanner.d.ts +34 -0
- package/build/shield/discovery/dockerScanner.js +543 -0
- package/build/shield/discovery/endpointScanner.d.ts +3 -0
- package/build/shield/discovery/endpointScanner.js +306 -0
- package/build/shield/discovery/environmentScanner.d.ts +86 -0
- package/build/shield/discovery/environmentScanner.js +545 -0
- package/build/shield/discovery/externalServiceDetector.d.ts +3 -0
- package/build/shield/discovery/externalServiceDetector.js +98 -0
- package/build/shield/discovery/frameworkDetector.d.ts +3 -0
- package/build/shield/discovery/frameworkDetector.js +114 -0
- package/build/shield/discovery/manifestGenerator.d.ts +12 -0
- package/build/shield/discovery/manifestGenerator.js +124 -0
- package/build/shield/discovery/piiDetector.d.ts +5 -0
- package/build/shield/discovery/piiDetector.js +203 -0
- package/build/shield/discovery/severity.d.ts +47 -0
- package/build/shield/discovery/severity.js +138 -0
- package/build/shield/discovery/topologyNormalizer.d.ts +109 -0
- package/build/shield/discovery/topologyNormalizer.js +416 -0
- package/build/shield/identity.d.ts +53 -0
- package/build/shield/identity.js +70 -0
- package/build/shield/install/configMerge.d.ts +91 -0
- package/build/shield/install/configMerge.js +324 -0
- package/build/shield/install/keystore.d.ts +25 -0
- package/build/shield/install/keystore.js +156 -0
- package/build/shield/install/orchestrator.d.ts +33 -0
- package/build/shield/install/orchestrator.js +404 -0
- package/build/shield/install/transports/awsSsm.d.ts +43 -0
- package/build/shield/install/transports/awsSsm.js +378 -0
- package/build/shield/install/transports/bootstrapToken.d.ts +39 -0
- package/build/shield/install/transports/bootstrapToken.js +117 -0
- package/build/shield/install/transports/ssh.d.ts +50 -0
- package/build/shield/install/transports/ssh.js +569 -0
- package/build/shield/install/types.d.ts +139 -0
- package/build/shield/install/types.js +10 -0
- package/build/shield/protocol-walkthrough.d.ts +65 -0
- package/build/shield/protocol-walkthrough.js +392 -0
- package/build/shield/provision/appProvisioner.d.ts +15 -0
- package/build/shield/provision/appProvisioner.js +25 -0
- package/build/shield/types.d.ts +261 -0
- package/build/shield/types.js +4 -0
- package/build/shield/verify/postureReporter.d.ts +4 -0
- package/build/shield/verify/postureReporter.js +31 -0
- package/dxt/blacksands-ca.crt +67 -0
- package/dxt/scripts/setup.js +520 -0
- package/package.json +76 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shield API Client — Broker mode only.
|
|
3
|
+
*
|
|
4
|
+
* Every request flows through the Blacksands Broker:
|
|
5
|
+
* Step 1: POST {authorizer}/api/agent/auth with { password, serviceId }
|
|
6
|
+
* — the Authorizer validates the mTLS client cert (presented by our
|
|
7
|
+
* httpsAgent), authenticates the password, and resolves the serviceId
|
|
8
|
+
* to a Receiver URL — all in one round trip. Returns a sessionToken
|
|
9
|
+
* plus { service: { serviceUrl } }.
|
|
10
|
+
* Step 2: All subsequent Shield API calls go to service.serviceUrl (the
|
|
11
|
+
* Receiver), which authenticates us and proxies to Shield API.
|
|
12
|
+
*
|
|
13
|
+
* The mTLS client certificate and auth password are issued by a human
|
|
14
|
+
* administrator through Overwatch or SysAdmin (or by the Phase-2 setup-token
|
|
15
|
+
* bootstrap flow, which is just a thin wrapper around the same issuance).
|
|
16
|
+
*/
|
|
17
|
+
import * as https from "https";
|
|
18
|
+
import type { Organization, App, Certificate, Endpoint, Policy, PolicyRule, DnsRule, Manifest, Operation, VerifyResult, ComplianceReport, ComplianceFramework, Session, ListResponse } from "./types";
|
|
19
|
+
export interface ShieldClientOptions {
|
|
20
|
+
timeout?: number;
|
|
21
|
+
maxRetries?: number;
|
|
22
|
+
/** PEM-encoded client certificate for mTLS authentication */
|
|
23
|
+
clientCert: string;
|
|
24
|
+
/** PEM-encoded client private key for mTLS authentication */
|
|
25
|
+
clientKey: string;
|
|
26
|
+
/** Optional PEM-encoded CA certificate to pin the Authorizer/Receiver server cert */
|
|
27
|
+
caCert?: string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Broker connection settings. Required for client-side (stdio) mode where
|
|
30
|
+
* the MCP server connects to Shield API via the full Authorizer handshake.
|
|
31
|
+
* Mutually exclusive with `directUrl`.
|
|
32
|
+
*/
|
|
33
|
+
broker?: {
|
|
34
|
+
authorizerUrl: string;
|
|
35
|
+
serviceId: string;
|
|
36
|
+
authPassword: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Direct Shield API base URL. Used when the MCP server is deployed as an
|
|
40
|
+
* internal HTTP service behind a Receiver and authenticates to Shield API
|
|
41
|
+
* using a service-level mTLS certificate (no broker handshake).
|
|
42
|
+
* Mutually exclusive with `broker`.
|
|
43
|
+
*/
|
|
44
|
+
directUrl?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare class BrokerConnector {
|
|
47
|
+
private authorizerUrl;
|
|
48
|
+
private serviceId;
|
|
49
|
+
private authPassword;
|
|
50
|
+
private httpsAgent;
|
|
51
|
+
private sessionToken;
|
|
52
|
+
private receiverUrl;
|
|
53
|
+
private connectedAt;
|
|
54
|
+
private sessionTtlMs;
|
|
55
|
+
private heartbeatTimer;
|
|
56
|
+
private readonly requestedTtlSec?;
|
|
57
|
+
constructor(authorizerUrl: string, serviceId: string, authPassword: string, httpsAgent: https.Agent, requestedTtlSec?: number | undefined);
|
|
58
|
+
get isConnected(): boolean;
|
|
59
|
+
get url(): string;
|
|
60
|
+
connect(): Promise<string>;
|
|
61
|
+
ensureConnected(): Promise<void>;
|
|
62
|
+
reconnect(): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Tear down state and stop the heartbeat. Tests/teardown call this; runtime
|
|
65
|
+
* normally stays connected for the process lifetime.
|
|
66
|
+
*/
|
|
67
|
+
close(): void;
|
|
68
|
+
private startHeartbeat;
|
|
69
|
+
private stopHeartbeat;
|
|
70
|
+
}
|
|
71
|
+
export declare class ShieldClient {
|
|
72
|
+
private http;
|
|
73
|
+
private maxRetries;
|
|
74
|
+
private broker;
|
|
75
|
+
private httpsAgent;
|
|
76
|
+
private options;
|
|
77
|
+
private mode;
|
|
78
|
+
constructor(options: ShieldClientOptions);
|
|
79
|
+
/** Complete the Broker handshake. No-op in direct mode. */
|
|
80
|
+
connect(): Promise<void>;
|
|
81
|
+
get authMethod(): "broker" | "direct";
|
|
82
|
+
request<T = unknown>(method: string, path: string, data?: unknown): Promise<T>;
|
|
83
|
+
pollOperation(operationId: string, opts?: {
|
|
84
|
+
interval?: number;
|
|
85
|
+
timeout?: number;
|
|
86
|
+
}): Promise<Operation>;
|
|
87
|
+
listMcpCerts(): Promise<{
|
|
88
|
+
data: Array<{
|
|
89
|
+
id: string;
|
|
90
|
+
name: string;
|
|
91
|
+
cn: string;
|
|
92
|
+
fingerprint: string;
|
|
93
|
+
expires: string;
|
|
94
|
+
}>;
|
|
95
|
+
}>;
|
|
96
|
+
revokeMcpCert(clientName: string): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Issue a full MCP client certificate bundle. Internal use only —
|
|
99
|
+
* consumed by bursar_install_agent_remotely's SSH and aws-ssm transports,
|
|
100
|
+
* which need the key material in-process to ship to the target.
|
|
101
|
+
*
|
|
102
|
+
* The returned `key_pem` is SENSITIVE: callers MUST treat it as tainted
|
|
103
|
+
* and MUST NOT persist it. See bursar_install_agent_remotely §FR-1.
|
|
104
|
+
*/
|
|
105
|
+
issueMcpCert(clientName: string, orgId: string): Promise<{
|
|
106
|
+
cn: string;
|
|
107
|
+
cert_pem: string;
|
|
108
|
+
key_pem: string;
|
|
109
|
+
ca_pem: string | null;
|
|
110
|
+
auth_password: string;
|
|
111
|
+
fingerprint: string;
|
|
112
|
+
expires: string;
|
|
113
|
+
client_id: string;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Mint a short-lived single-use setup token bound to {clientName, orgId}.
|
|
117
|
+
* Consumed by bursar_install_agent_remotely's bootstrap-token transport —
|
|
118
|
+
* the token is handed to the target, which calls POST /mcp/setup-tokens/redeem
|
|
119
|
+
* to exchange it for a cert bundle. The private key is returned to the
|
|
120
|
+
* redeemer; the MCP host holding this call never sees it.
|
|
121
|
+
*
|
|
122
|
+
* `expiresIn` accepts a number of seconds or a shorthand like "1h"/"30m".
|
|
123
|
+
*
|
|
124
|
+
* `role` ('master' | 'consumer') stamps the role on the token row so the
|
|
125
|
+
* redeem flow propagates it to the issued McpClient.role, and the redeem
|
|
126
|
+
* response echoes it back so setup.js can write
|
|
127
|
+
* ~/.blacksands/mcp-certs/.role for boot-time tool filtering. Defaults
|
|
128
|
+
* to 'master' on the server side.
|
|
129
|
+
*/
|
|
130
|
+
mintSetupToken(clientName: string, orgId: string, expiresIn?: string | number, role?: "master" | "consumer"): Promise<{
|
|
131
|
+
token: string;
|
|
132
|
+
token_id: string;
|
|
133
|
+
token_prefix: string;
|
|
134
|
+
client_name: string;
|
|
135
|
+
org_id: string;
|
|
136
|
+
role: "master" | "consumer";
|
|
137
|
+
expires_at: string;
|
|
138
|
+
ttl_seconds: number;
|
|
139
|
+
url: string;
|
|
140
|
+
}>;
|
|
141
|
+
/**
|
|
142
|
+
* Revoke a pending (unconsumed) setup token by ID. Internal rollback
|
|
143
|
+
* helper for bursar_install_agent_remotely — NOT exposed as a tool.
|
|
144
|
+
* A 404 from the server means the token was already consumed or
|
|
145
|
+
* expired; callers should treat that as success for rollback purposes.
|
|
146
|
+
*/
|
|
147
|
+
revokeSetupToken(tokenId: string): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Check whether the named MCP client has completed its first broker
|
|
150
|
+
* handshake since issuance. Polled by the install orchestrator with
|
|
151
|
+
* exponential backoff until waitForHandshake timeout.
|
|
152
|
+
*/
|
|
153
|
+
getHandshakeStatus(clientName: string): Promise<{
|
|
154
|
+
success: boolean;
|
|
155
|
+
verified: boolean;
|
|
156
|
+
client_name?: string;
|
|
157
|
+
cn?: string;
|
|
158
|
+
fingerprint?: string;
|
|
159
|
+
expires?: string;
|
|
160
|
+
first_handshake_at?: string | null;
|
|
161
|
+
last_handshake_at?: string | null;
|
|
162
|
+
receiver_url?: string | null;
|
|
163
|
+
reason?: string | null;
|
|
164
|
+
}>;
|
|
165
|
+
/**
|
|
166
|
+
* Acquire the per-clientName advisory lock. Throws on 409 (conflict).
|
|
167
|
+
*/
|
|
168
|
+
acquireInstallLock(clientName: string, opts?: {
|
|
169
|
+
ttlSeconds?: number;
|
|
170
|
+
auditId?: string;
|
|
171
|
+
}): Promise<{
|
|
172
|
+
owner_id: string;
|
|
173
|
+
expires_at: string;
|
|
174
|
+
ttl_seconds: number;
|
|
175
|
+
}>;
|
|
176
|
+
/** Release the advisory lock. Owner-match enforced server-side. */
|
|
177
|
+
releaseInstallLock(clientName: string): Promise<void>;
|
|
178
|
+
/** Append an audit row for a bursar_install_agent_remotely invocation. */
|
|
179
|
+
recordInstallAudit(row: {
|
|
180
|
+
auditId: string;
|
|
181
|
+
clientName: string;
|
|
182
|
+
transportType: string;
|
|
183
|
+
agentType?: string;
|
|
184
|
+
status: string;
|
|
185
|
+
phase?: string;
|
|
186
|
+
dryRun?: boolean;
|
|
187
|
+
target?: Record<string, unknown>;
|
|
188
|
+
errorMessage?: string;
|
|
189
|
+
}): Promise<{
|
|
190
|
+
id: string;
|
|
191
|
+
audit_id: string;
|
|
192
|
+
}>;
|
|
193
|
+
createOrg(name: string, plan?: string): Promise<Organization>;
|
|
194
|
+
getOrg(orgId: string): Promise<Organization>;
|
|
195
|
+
listOrgs(page?: number, pageSize?: number): Promise<ListResponse<Organization>>;
|
|
196
|
+
createApp(orgId: string, name: string, opts?: {
|
|
197
|
+
type?: "web" | "mobile" | "api" | "iot" | "service";
|
|
198
|
+
framework?: string;
|
|
199
|
+
runtime?: string;
|
|
200
|
+
environment?: "development" | "staging" | "production";
|
|
201
|
+
domain?: string;
|
|
202
|
+
}): Promise<App>;
|
|
203
|
+
getApp(appId: string): Promise<App>;
|
|
204
|
+
listApps(orgId: string): Promise<ListResponse<App>>;
|
|
205
|
+
submitManifest(manifest: unknown, orgId: string): Promise<Manifest>;
|
|
206
|
+
getManifest(manifestId: string): Promise<Manifest>;
|
|
207
|
+
provisionManifest(manifestId: string): Promise<{
|
|
208
|
+
operationId: string;
|
|
209
|
+
}>;
|
|
210
|
+
listCerts(appId: string): Promise<ListResponse<Certificate>>;
|
|
211
|
+
rotateCert(appId: string, certId: string): Promise<Certificate>;
|
|
212
|
+
revokeCert(appId: string, certId: string, reason?: string): Promise<void>;
|
|
213
|
+
listEndpoints(appId: string): Promise<ListResponse<Endpoint>>;
|
|
214
|
+
listPolicies(appId: string): Promise<ListResponse<Policy>>;
|
|
215
|
+
createPolicy(appId: string, name: string, type: string, rules: PolicyRule[]): Promise<Policy>;
|
|
216
|
+
updateDnsRules(appId: string, rules: Array<{
|
|
217
|
+
domain: string;
|
|
218
|
+
action: "allow" | "block";
|
|
219
|
+
reason?: string;
|
|
220
|
+
}>): Promise<DnsRule[]>;
|
|
221
|
+
triggerVerify(appId: string, scanType?: "full" | "quick" | "compliance" | "penetration"): Promise<{
|
|
222
|
+
operationId: string;
|
|
223
|
+
}>;
|
|
224
|
+
getLatestPosture(appId: string): Promise<VerifyResult>;
|
|
225
|
+
getComplianceReport(appId: string, framework: ComplianceFramework): Promise<ComplianceReport>;
|
|
226
|
+
getComplianceControls(framework: ComplianceFramework): Promise<{
|
|
227
|
+
controls: Array<{
|
|
228
|
+
id: string;
|
|
229
|
+
name: string;
|
|
230
|
+
description: string;
|
|
231
|
+
}>;
|
|
232
|
+
}>;
|
|
233
|
+
listSessions(appId: string): Promise<ListResponse<Session>>;
|
|
234
|
+
revokeSession(appId: string, sessionId: string): Promise<void>;
|
|
235
|
+
emergencyLockdown(appId: string, reason: string): Promise<{
|
|
236
|
+
locked: boolean;
|
|
237
|
+
timestamp: string;
|
|
238
|
+
}>;
|
|
239
|
+
liftLockdown(appId: string): Promise<void>;
|
|
240
|
+
getReceiver(receiverUID: string): Promise<Record<string, unknown>>;
|
|
241
|
+
listReceivers(filters?: {
|
|
242
|
+
status?: string;
|
|
243
|
+
organizationId?: string;
|
|
244
|
+
}): Promise<Record<string, unknown>[]>;
|
|
245
|
+
initializeReceiver(installerEmail: string, organizationId: string, notes?: string): Promise<Record<string, unknown>>;
|
|
246
|
+
getReceiverStatus(receiverUID: string): Promise<Record<string, unknown>>;
|
|
247
|
+
activateReceiver(receiverUID: string): Promise<Record<string, unknown>>;
|
|
248
|
+
resendReceiverEmail(receiverUID: string): Promise<Record<string, unknown>>;
|
|
249
|
+
cancelReceiverInit(receiverUID: string): Promise<Record<string, unknown>>;
|
|
250
|
+
getReceiverStatistics(): Promise<Record<string, unknown>>;
|
|
251
|
+
onboardReceiverService(receiverUID: string, svc: {
|
|
252
|
+
name: string;
|
|
253
|
+
host: string;
|
|
254
|
+
port: number;
|
|
255
|
+
protocol: "http" | "https" | "ssh" | "rdp";
|
|
256
|
+
path?: string;
|
|
257
|
+
}): Promise<Record<string, unknown>>;
|
|
258
|
+
removeReceiverService(receiverUID: string, serviceName: string): Promise<Record<string, unknown>>;
|
|
259
|
+
listReceiverServices(receiverUID: string): Promise<Record<string, unknown>[]>;
|
|
260
|
+
pauseService(receiverUID: string, serviceName: string): Promise<Record<string, unknown>>;
|
|
261
|
+
resumeService(receiverUID: string, serviceName: string): Promise<Record<string, unknown>>;
|
|
262
|
+
disableService(receiverUID: string, serviceName: string): Promise<Record<string, unknown>>;
|
|
263
|
+
getServiceStatus(receiverUID: string, serviceName: string): Promise<Record<string, unknown>>;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=client.d.ts.map
|