fullcourtdefense-cli 1.34.21 → 1.34.25
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 +1 -0
- package/dist/actionIdentity.d.ts +1 -0
- package/dist/actionIdentity.js +2 -0
- package/dist/actionPolicyEngine.d.ts +5 -0
- package/dist/actionPolicyEngine.js +273 -30
- package/dist/agentTerminal.d.ts +1 -3
- package/dist/agentTerminal.js +14 -29
- package/dist/approvalPrompt.d.ts +7 -0
- package/dist/approvalPrompt.js +46 -0
- package/dist/askDialog.d.ts +87 -0
- package/dist/askDialog.js +209 -0
- package/dist/blockExplanation.js +18 -6
- package/dist/boundaryVerification.d.ts +20 -0
- package/dist/boundaryVerification.js +147 -0
- package/dist/commands/daemon.js +198 -70
- package/dist/commands/deterministicGuard.d.ts +2 -0
- package/dist/commands/deterministicGuard.js +161 -9
- package/dist/commands/hook.js +81 -29
- package/dist/commands/installClaudeHook.js +11 -5
- package/dist/commands/installCursorHook.js +5 -4
- package/dist/commands/mcpGateway.d.ts +2 -0
- package/dist/commands/mcpGateway.js +163 -56
- package/dist/commands/onboard.js +6 -5
- package/dist/commands/onboardingSummary.d.ts +5 -0
- package/dist/commands/onboardingSummary.js +11 -0
- package/dist/commands/protectedRun.d.ts +14 -0
- package/dist/commands/protectedRun.js +207 -0
- package/dist/containment-runtime/index.mjs +30118 -0
- package/dist/containment-runtime/licenses/_anthropic-ai_sandbox-runtime.txt +201 -0
- package/dist/containment-runtime/licenses/_pondwader_socks5-server.txt +20 -0
- package/dist/containment-runtime/licenses/commander.txt +22 -0
- package/dist/containment-runtime/licenses/node-forge.txt +331 -0
- package/dist/containment-runtime/licenses/zod.txt +21 -0
- package/dist/containment-runtime/runtime-version.json +1 -0
- package/dist/containment-runtime/vendor/java-proxy-agent/build.ts +95 -0
- package/dist/containment-runtime/vendor/java-proxy-agent/srt-proxy-agent.jar +0 -0
- package/dist/containment-runtime/vendor/seccomp/arm64/apply-seccomp +0 -0
- package/dist/containment-runtime/vendor/seccomp/build.ts +69 -0
- package/dist/containment-runtime/vendor/seccomp/x64/apply-seccomp +0 -0
- package/dist/containment-runtime/vendor/srt-win/arm64/srt-win.exe +0 -0
- package/dist/containment-runtime/vendor/srt-win/build.ts +21 -0
- package/dist/containment-runtime/vendor/srt-win/x64/srt-win.exe +0 -0
- package/dist/containmentLease.d.ts +5 -0
- package/dist/containmentLease.js +72 -0
- package/dist/detectionUpdates.d.ts +23 -3
- package/dist/detectionUpdates.js +45 -14
- package/dist/detectorArtifact.d.ts +17 -0
- package/dist/detectorArtifact.js +35 -0
- package/dist/detectorBaseline.d.ts +2 -0
- package/dist/detectorBaseline.js +5 -0
- package/dist/detectorModule.d.ts +9 -0
- package/dist/detectorModule.js +84 -0
- package/dist/detectorRuntime.d.ts +21 -0
- package/dist/detectorRuntime.js +49 -0
- package/dist/detectorUpdates.d.ts +21 -0
- package/dist/detectorUpdates.js +86 -0
- package/dist/devConfirm.d.ts +97 -15
- package/dist/devConfirm.js +447 -117
- package/dist/distress.d.ts +2 -0
- package/dist/distress.js +2 -0
- package/dist/frictionRollout.js +103 -0
- package/dist/gatewayRuntime.d.ts +19 -0
- package/dist/gatewayRuntime.js +93 -0
- package/dist/hookSlim.js +17 -18
- package/dist/index.js +35 -0
- package/dist/localDetectionUpdates.d.ts +3 -1
- package/dist/localDetectionUpdates.js +8 -1
- package/dist/localSafetySnapshot.d.ts +9 -5
- package/dist/localSafetySnapshot.js +42 -15
- package/dist/mcpToolReview.d.ts +17 -0
- package/dist/mcpToolReview.js +127 -0
- package/dist/mcpToolTrust.d.ts +22 -0
- package/dist/mcpToolTrust.js +66 -0
- package/dist/nativeHook.d.ts +4 -0
- package/dist/nativeHook.js +31 -17
- package/dist/policyRefresh.d.ts +3 -0
- package/dist/policyRefresh.js +27 -0
- package/dist/protectionMaintenance.d.ts +10 -0
- package/dist/protectionMaintenance.js +64 -0
- package/dist/protectionProfile.d.ts +26 -0
- package/dist/protectionProfile.js +63 -0
- package/dist/runtimeConfig.d.ts +2 -0
- package/dist/runtimeConfig.js +65 -26
- package/dist/selfTest.d.ts +2 -0
- package/dist/selfTest.js +9 -1
- package/dist/sessionLimits.d.ts +2 -0
- package/dist/sessionLimits.js +24 -0
- package/dist/telemetry.d.ts +5 -0
- package/dist/telemetry.js +8 -0
- package/dist/version.json +1 -1
- package/package.json +10 -6
|
@@ -49,8 +49,11 @@ exports.installGeminiMcpGatewayCommand = installGeminiMcpGatewayCommand;
|
|
|
49
49
|
exports.installWindsurfMcpGatewayCommand = installWindsurfMcpGatewayCommand;
|
|
50
50
|
exports.installVscodeMcpGatewayCommand = installVscodeMcpGatewayCommand;
|
|
51
51
|
const fs = __importStar(require("fs"));
|
|
52
|
+
const mcpToolTrust_1 = require("../mcpToolTrust");
|
|
53
|
+
const mcpToolReview_1 = require("../mcpToolReview");
|
|
52
54
|
const os = __importStar(require("os"));
|
|
53
55
|
const path = __importStar(require("path"));
|
|
56
|
+
const gatewayRuntime_1 = require("../gatewayRuntime");
|
|
54
57
|
const child_process_1 = require("child_process");
|
|
55
58
|
const config_1 = require("../config");
|
|
56
59
|
const discoverPaths_1 = require("./discoverPaths");
|
|
@@ -222,6 +225,7 @@ function resolveGatewayConfig(args, config, defaults = {}) {
|
|
|
222
225
|
const agentClient = normalizeAgentClient(args.agentClient || process.env.FCD_AGENT_CLIENT || detectRuntimeAgentClient(), defaults.agentClient || 'cursor');
|
|
223
226
|
const developerName = detectedDeveloperName(args);
|
|
224
227
|
return {
|
|
228
|
+
mcpServerName: args.mcpServerName,
|
|
225
229
|
shieldId: creds.shieldId,
|
|
226
230
|
shieldKey: creds.shieldKey,
|
|
227
231
|
apiUrl: creds.apiUrl,
|
|
@@ -500,19 +504,7 @@ class StdioMcpClient {
|
|
|
500
504
|
this.notify('notifications/initialized', {});
|
|
501
505
|
}
|
|
502
506
|
async listTools() {
|
|
503
|
-
|
|
504
|
-
const tools = result?.tools;
|
|
505
|
-
if (!Array.isArray(tools))
|
|
506
|
-
return [];
|
|
507
|
-
return tools
|
|
508
|
-
.filter(tool => typeof tool.name === 'string')
|
|
509
|
-
.map(tool => ({
|
|
510
|
-
name: String(tool.name),
|
|
511
|
-
description: typeof tool.description === 'string'
|
|
512
|
-
? String(tool.description)
|
|
513
|
-
: undefined,
|
|
514
|
-
inputSchema: tool.inputSchema,
|
|
515
|
-
}));
|
|
507
|
+
return (0, mcpToolReview_1.readCompleteToolCatalog)(params => this.request('tools/list', params));
|
|
516
508
|
}
|
|
517
509
|
async callTool(name, args) {
|
|
518
510
|
return this.request('tools/call', { name, arguments: args });
|
|
@@ -661,19 +653,7 @@ class HttpMcpClient {
|
|
|
661
653
|
throw lastError || new Error(`Could not initialize remote MCP server at ${this.url}`);
|
|
662
654
|
}
|
|
663
655
|
async listTools() {
|
|
664
|
-
|
|
665
|
-
const tools = response?.tools;
|
|
666
|
-
if (!Array.isArray(tools))
|
|
667
|
-
return [];
|
|
668
|
-
return tools
|
|
669
|
-
.filter(tool => typeof tool.name === 'string')
|
|
670
|
-
.map(tool => ({
|
|
671
|
-
name: String(tool.name),
|
|
672
|
-
description: typeof tool.description === 'string'
|
|
673
|
-
? String(tool.description)
|
|
674
|
-
: undefined,
|
|
675
|
-
inputSchema: tool.inputSchema,
|
|
676
|
-
}));
|
|
656
|
+
return (0, mcpToolReview_1.readCompleteToolCatalog)(params => this.request('tools/list', params));
|
|
677
657
|
}
|
|
678
658
|
async callTool(name, args) {
|
|
679
659
|
return this.request('tools/call', { name, arguments: args });
|
|
@@ -986,6 +966,8 @@ function describeDeveloperNo(answer) {
|
|
|
986
966
|
class McpGatewayServer {
|
|
987
967
|
gatewayConfig;
|
|
988
968
|
downstreamSpec;
|
|
969
|
+
toolTrust;
|
|
970
|
+
reportedCatalog = '';
|
|
989
971
|
downstream;
|
|
990
972
|
downstreamReady;
|
|
991
973
|
buffer = '';
|
|
@@ -1082,6 +1064,7 @@ class McpGatewayServer {
|
|
|
1082
1064
|
if (message.method === 'tools/list') {
|
|
1083
1065
|
await this.ensureDownstream();
|
|
1084
1066
|
const tools = await this.downstream.listTools();
|
|
1067
|
+
this.reportCatalog(this.catalog(tools));
|
|
1085
1068
|
this.respond(message.id, {
|
|
1086
1069
|
tools: tools.map(tool => ({
|
|
1087
1070
|
...tool,
|
|
@@ -1117,6 +1100,51 @@ class McpGatewayServer {
|
|
|
1117
1100
|
}
|
|
1118
1101
|
await this.downstreamReady;
|
|
1119
1102
|
}
|
|
1103
|
+
catalog(tools) {
|
|
1104
|
+
const downstream = this.downstreamSpec.kind === 'http' ? { ...this.downstreamSpec, headers: this.downstreamSpec.headers || {} } : this.downstreamSpec;
|
|
1105
|
+
return (0, mcpToolTrust_1.parseToolCatalog)({ serverId: (0, mcpToolTrust_1.toolDigest)({ server: this.gatewayConfig.mcpServerName || this.gatewayConfig.agentName || 'MCP server', downstream, cwd: process.cwd(), client: this.gatewayConfig.agentClient || '' }), serverName: this.gatewayConfig.mcpServerName || this.gatewayConfig.agentName || 'MCP server', tools });
|
|
1106
|
+
}
|
|
1107
|
+
reportCatalog(catalog) {
|
|
1108
|
+
if (this.reportedCatalog === catalog.catalogHash)
|
|
1109
|
+
return;
|
|
1110
|
+
this.reportedCatalog = catalog.catalogHash;
|
|
1111
|
+
const controller = new AbortController();
|
|
1112
|
+
const timer = setTimeout(() => controller.abort(), 2000);
|
|
1113
|
+
void fetch(`${this.gatewayConfig.apiUrl.replace(/\/$/, '')}/api/cli/tool-catalog`, {
|
|
1114
|
+
method: 'POST', headers: { 'content-type': 'application/json', 'x-shield-id': this.gatewayConfig.shieldId, 'x-shield-key': this.gatewayConfig.shieldKey || '' },
|
|
1115
|
+
body: JSON.stringify({ machineId: (0, machineIdentity_1.getMachineIdentity)().machineId, catalog }), signal: controller.signal,
|
|
1116
|
+
}).then(response => { if (!response.ok)
|
|
1117
|
+
this.reportedCatalog = ''; }).catch(() => { this.reportedCatalog = ''; }).finally(() => clearTimeout(timer));
|
|
1118
|
+
}
|
|
1119
|
+
async checkToolReview(toolName, expectedCatalogHash) {
|
|
1120
|
+
const machineId = (0, machineIdentity_1.getMachineIdentity)().machineId;
|
|
1121
|
+
const bundle = await (0, runtimeConfig_1.getRuntimeBundle)({ apiUrl: this.gatewayConfig.apiUrl, shieldId: this.gatewayConfig.shieldId, shieldKey: this.gatewayConfig.shieldKey, machineId, hotPath: true });
|
|
1122
|
+
try {
|
|
1123
|
+
this.toolTrust ||= new mcpToolReview_1.ToolReviewLease(machineId, this.gatewayConfig.shieldId, this.gatewayConfig.apiUrl);
|
|
1124
|
+
const settings = this.toolTrust.settings(bundle.mcpToolTrust);
|
|
1125
|
+
if (!settings?.enabled)
|
|
1126
|
+
return; // Legacy/unconfigured is not claimed as verified.
|
|
1127
|
+
const catalog = this.catalog(await this.downstream.listTools());
|
|
1128
|
+
this.reportCatalog(catalog);
|
|
1129
|
+
if (expectedCatalogHash && expectedCatalogHash !== catalog.catalogHash)
|
|
1130
|
+
throw new Error('MCP tool definitions changed during this action. Retry so the current version and action are reviewed together.');
|
|
1131
|
+
if (!(0, mcpToolTrust_1.toolCatalogAllowed)(settings, catalog, toolName))
|
|
1132
|
+
throw new Error('This MCP server has new or changed tool definitions. Review this exact version in Action Protection before calling it.');
|
|
1133
|
+
return catalog.catalogHash;
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
const reason = error instanceof Error ? error.message : 'Tool review is unavailable.';
|
|
1137
|
+
const monitoring = (bundle.source === 'server' || bundle.source === 'cache') && (bundle.mode === 'monitor' || bundle.mode === 'shadow');
|
|
1138
|
+
try {
|
|
1139
|
+
(0, telemetry_1.spoolEvent)({ decision: monitoring ? 'warn' : 'block', toolName, operation: 'mcp:tool-review', reason: monitoring ? `[monitor] ${reason}` : reason, ruleId: 'mcp-tool-review', offlineEnforced: true });
|
|
1140
|
+
(0, telemetry_1.triggerFlush)(!monitoring);
|
|
1141
|
+
}
|
|
1142
|
+
catch { /* Evidence failures cannot change the review decision. */ }
|
|
1143
|
+
if (monitoring)
|
|
1144
|
+
return;
|
|
1145
|
+
throw blockError(reason);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1120
1148
|
/** Forget a dead/failed downstream so the next call respawns it. */
|
|
1121
1149
|
resetDownstream(client) {
|
|
1122
1150
|
if (this.downstream === client) {
|
|
@@ -1155,6 +1183,9 @@ class McpGatewayServer {
|
|
|
1155
1183
|
const toolName = String(params.name || '');
|
|
1156
1184
|
if (!toolName)
|
|
1157
1185
|
throw new Error('Missing MCP tool name.');
|
|
1186
|
+
// Outside the legacy policy-service fail-open recovery: review failures
|
|
1187
|
+
// must never forward a call. Matching metadata still runs every policy.
|
|
1188
|
+
const reviewedCatalogHash = await this.checkToolReview(toolName);
|
|
1158
1189
|
// What the server receives is untouched (`forwardArgs`). What the policy
|
|
1159
1190
|
// decision sees is the canonical action: a whole-file write is reduced to
|
|
1160
1191
|
// the lines it adds so a secret already sitting in the file never blocks
|
|
@@ -1196,6 +1227,7 @@ class McpGatewayServer {
|
|
|
1196
1227
|
shieldKey: this.gatewayConfig.shieldKey,
|
|
1197
1228
|
developerName: this.gatewayConfig.developerName,
|
|
1198
1229
|
machineName: os.hostname(),
|
|
1230
|
+
machineId: (0, machineIdentity_1.getMachineIdentity)().machineId,
|
|
1199
1231
|
hotPath: true,
|
|
1200
1232
|
});
|
|
1201
1233
|
// Admin kill-switch: a suspended machine denies every tool call. This
|
|
@@ -1251,7 +1283,7 @@ class McpGatewayServer {
|
|
|
1251
1283
|
snapshot.itemActions = Object.fromEntries(Object.entries(snapshot.itemActions || {}).map(([id, action]) => [id, action === 'mask' ? 'warn' : action]));
|
|
1252
1284
|
snapshot.customBlocks = snapshot.customBlocks.map(rule => rule.action === 'mask' ? { ...rule, action: 'warn' } : rule);
|
|
1253
1285
|
}
|
|
1254
|
-
const requestOutcome = (0, deterministicGuard_1.resolveDeterministicOutcome)(opts => (0, deterministicGuard_1.scanDeterministicToolCall)(toolName, toolArgs, opts), (0, localSafetySnapshot_1.snapshotToScanOptions)(snapshot));
|
|
1286
|
+
const requestOutcome = (0, deterministicGuard_1.resolveDeterministicOutcome)(opts => (0, deterministicGuard_1.scanDeterministicToolCall)(toolName, toolArgs, opts), (0, localSafetySnapshot_1.snapshotToScanOptions)(snapshot, { mcpServerName: this.gatewayConfig.mcpServerName }));
|
|
1255
1287
|
for (const warning of requestOutcome.warnings) {
|
|
1256
1288
|
this.spoolLocalFinding(warning, toolName, operation, 'warn');
|
|
1257
1289
|
process.stderr.write(`FullCourtDefense warning (${warning.itemId}): ${warning.reason}\n`);
|
|
@@ -1260,17 +1292,41 @@ class McpGatewayServer {
|
|
|
1260
1292
|
// human — through the MCP client (elicitation) when it can show a dialog,
|
|
1261
1293
|
// otherwise (or when the client answers for the user) through the OS
|
|
1262
1294
|
// dialog — whenever a human is present. Session memory reuses the IDE
|
|
1263
|
-
// hook's ledger (same
|
|
1295
|
+
// hook's ledger (same action + policy + server + session => remembered). Decline, cancel, timeout
|
|
1264
1296
|
// or no human => block, never a silent allow.
|
|
1265
1297
|
let localBlock = requestOutcome.blockingFinding || requestOutcome.askFinding;
|
|
1266
1298
|
let askNote = '';
|
|
1267
1299
|
if (!requestOutcome.blockingFinding && requestOutcome.askFinding && !reportOnlyMode) {
|
|
1268
1300
|
const ask = requestOutcome.askFinding;
|
|
1269
1301
|
const origin = ask.source === 'custom' ? 'org custom rule' : 'built-in Local Safety rule';
|
|
1270
|
-
const rememberScope = {
|
|
1302
|
+
const rememberScope = {
|
|
1303
|
+
toolName, argsDigest: (0, devConfirm_1.actionDigest)(toolArgs),
|
|
1304
|
+
policyHash: ask.policyHash,
|
|
1305
|
+
authorizationContext: (0, devConfirm_1.actionDigest)({ server: this.gatewayConfig.mcpServerName, downstream: this.downstreamSpec, cwd: process.cwd(), shieldId: this.gatewayConfig.shieldId, client: this.gatewayConfig.agentClient, catalog: reviewedCatalogHash || 'unreviewed' }),
|
|
1306
|
+
operation: operation || (0, actionPolicyEngine_1.inferToolContext)(toolName, toolArgs).operation,
|
|
1307
|
+
policyId: `local-safety:${ask.itemId}`, matchedRule: ask.ruleId,
|
|
1308
|
+
};
|
|
1271
1309
|
const sessionId = runtimeSessionId() || this.gatewaySessionId;
|
|
1310
|
+
const confirmationEvent = `mcp_gateway:${rememberScope.authorizationContext}:${rememberScope.policyHash}`;
|
|
1272
1311
|
const remembered = (0, devConfirm_1.isConfirmationRemembered)(rememberScope, sessionId);
|
|
1273
|
-
|
|
1312
|
+
// Same grant identity the IDE hook uses for this Local Safety item, so one
|
|
1313
|
+
// "Always allow" covers both surfaces.
|
|
1314
|
+
const grantToolName = this.gatewayConfig.mcpServerName ? `mcp__${this.gatewayConfig.mcpServerName}__${toolName}` : toolName;
|
|
1315
|
+
const grantScope = (0, devConfirm_1.grantScopeFor)('mcp', grantToolName, toolArgs, rememberScope.operation, (0, actionPolicyEngine_1.inferToolContext)(toolName, toolArgs).context);
|
|
1316
|
+
const grantRule = { policyId: rememberScope.policyId, policyName: `Local Safety: ${ask.itemId}`, matchedRule: ask.itemId, policyHash: ask.policyHash };
|
|
1317
|
+
const grant = remembered ? undefined : (0, devConfirm_1.findDeveloperGrant)(grantScope, grantRule);
|
|
1318
|
+
if (grant) {
|
|
1319
|
+
(0, telemetry_1.spoolEvent)({
|
|
1320
|
+
decision: 'allow', toolName, operation: rememberScope.operation,
|
|
1321
|
+
reason: `developer granted Always allow for ${(0, devConfirm_1.describeGrantScope)(grant.scope)} — ${ask.reason}`,
|
|
1322
|
+
ruleId: ask.ruleId, category: ask.category, categoryId: ask.categoryId, itemId: ask.itemId, source: ask.source,
|
|
1323
|
+
evidence: ask.evidence, policyHash: ask.policyHash, offlineEnforced: true,
|
|
1324
|
+
approvalScope: 'developer', approvedBy: 'developer',
|
|
1325
|
+
});
|
|
1326
|
+
(0, telemetry_1.triggerFlush)(false);
|
|
1327
|
+
localBlock = undefined;
|
|
1328
|
+
}
|
|
1329
|
+
else if (remembered) {
|
|
1274
1330
|
(0, telemetry_1.spoolEvent)({
|
|
1275
1331
|
decision: 'allow', toolName, operation: rememberScope.operation,
|
|
1276
1332
|
reason: `developer confirmed earlier this session (session memory) — ${ask.reason}`,
|
|
@@ -1284,21 +1340,25 @@ class McpGatewayServer {
|
|
|
1284
1340
|
else if ((0, devConfirm_1.isHumanPresent)()) {
|
|
1285
1341
|
const digest = (0, devConfirm_1.actionDigest)(toolArgs);
|
|
1286
1342
|
const marker = (0, devConfirm_1.raiseDeveloperConfirmation)({
|
|
1287
|
-
event:
|
|
1343
|
+
event: confirmationEvent, ...rememberScope, argsDigest: digest,
|
|
1288
1344
|
policyId: rememberScope.policyId, policyName: `Local Safety: ${ask.itemId}`, matchedRule: ask.ruleId,
|
|
1289
1345
|
sessionId, remember: 'none',
|
|
1290
1346
|
});
|
|
1291
1347
|
process.stderr.write(`FullCourtDefense asking the developer to confirm ${toolName}: ${ask.reason} (${origin} "${ask.itemId}", ${ask.ruleId})\n`);
|
|
1292
|
-
const
|
|
1348
|
+
const alwaysScopeLabel = (0, devConfirm_1.describeGrantScope)(grantScope);
|
|
1349
|
+
const answer = await this.confirmWithDeveloper({ toolName, reason: ask.reason, ruleLabel: `${origin} "${ask.itemId}" (${ask.ruleId})`, evidence: ask.evidence, argsDigest: digest, allowAlways: true, alwaysScopeLabel });
|
|
1293
1350
|
if (answer.answer === 'accept') {
|
|
1294
1351
|
// Settle through the shared ledger so "remember for this session" is
|
|
1295
1352
|
// recorded exactly like an IDE approval would be.
|
|
1296
1353
|
if (answer.remember)
|
|
1297
1354
|
(0, devConfirm_1.raiseDeveloperConfirmation)({ ...marker, remember: 'session' });
|
|
1298
|
-
(0, devConfirm_1.settleDeveloperConfirmation)(
|
|
1355
|
+
(0, devConfirm_1.settleDeveloperConfirmation)(confirmationEvent, toolName, digest);
|
|
1356
|
+
const granted = answer.always && ask.policyHash ? (0, devConfirm_1.recordDeveloperGrant)(grantScope, { ...grantRule, policyHash: ask.policyHash }) : undefined;
|
|
1299
1357
|
(0, telemetry_1.spoolEvent)({
|
|
1300
1358
|
decision: 'allow', toolName, operation: rememberScope.operation,
|
|
1301
|
-
reason:
|
|
1359
|
+
reason: granted
|
|
1360
|
+
? `developer chose Always allow in ${confirmChannelLabel(answer)} — ${alwaysScopeLabel} (30 days, this rule) — ${ask.reason}`
|
|
1361
|
+
: `developer confirmed in ${confirmChannelLabel(answer)}${answer.remember ? ' (remembered for this session)' : ''}${answer.clientAutoAnswered ? ' (the MCP client auto-declined the in-client prompt)' : ''} — ${ask.reason}`,
|
|
1302
1362
|
ruleId: ask.ruleId, category: ask.category, categoryId: ask.categoryId, itemId: ask.itemId, source: ask.source,
|
|
1303
1363
|
evidence: ask.evidence, policyHash: ask.policyHash, offlineEnforced: true,
|
|
1304
1364
|
approvalScope: 'developer', approvedBy: 'developer', confirmLatencyMs: answer.latencyMs,
|
|
@@ -1307,7 +1367,7 @@ class McpGatewayServer {
|
|
|
1307
1367
|
localBlock = undefined;
|
|
1308
1368
|
}
|
|
1309
1369
|
else {
|
|
1310
|
-
(0, devConfirm_1.rejectDeveloperConfirmation)(
|
|
1370
|
+
(0, devConfirm_1.rejectDeveloperConfirmation)(confirmationEvent, toolName, digest);
|
|
1311
1371
|
const no = describeDeveloperNo(answer);
|
|
1312
1372
|
(0, telemetry_1.spoolEvent)({
|
|
1313
1373
|
decision: 'block', toolName, operation: rememberScope.operation,
|
|
@@ -1601,6 +1661,7 @@ class McpGatewayServer {
|
|
|
1601
1661
|
}
|
|
1602
1662
|
}
|
|
1603
1663
|
downstreamAttempted = true;
|
|
1664
|
+
await this.checkToolReview(toolName, reviewedCatalogHash);
|
|
1604
1665
|
let rawResult = await this.downstream.callTool(toolName, forwardArgs);
|
|
1605
1666
|
downstreamRan = true;
|
|
1606
1667
|
downstreamResult = rawResult;
|
|
@@ -1793,6 +1854,7 @@ class McpGatewayServer {
|
|
|
1793
1854
|
if (!isBlockError(error) && !downstreamAttempted) {
|
|
1794
1855
|
// Pre-call bug: forward the tool call now (exactly once).
|
|
1795
1856
|
try {
|
|
1857
|
+
await this.checkToolReview(toolName, reviewedCatalogHash);
|
|
1796
1858
|
const recovered = await this.downstream.callTool(toolName, forwardArgs);
|
|
1797
1859
|
try {
|
|
1798
1860
|
(0, telemetry_1.spoolEvent)({ decision: 'allow', toolName, operation, reason: `gateway error failed open (pre-call): ${message.slice(0, 200)}`, offlineEnforced: true });
|
|
@@ -1878,8 +1940,13 @@ class McpGatewayServer {
|
|
|
1878
1940
|
(0, telemetry_1.triggerFlush)(true);
|
|
1879
1941
|
throw blockError(reason);
|
|
1880
1942
|
}
|
|
1881
|
-
const rememberScope = {
|
|
1943
|
+
const rememberScope = {
|
|
1944
|
+
toolName, operation, argsDigest: (0, devConfirm_1.actionDigest)(toolArgs),
|
|
1945
|
+
policyId: verdict.policyId, matchedRule: verdict.matchedRule, policyHash: (0, devConfirm_1.actionDigest)({ policies }),
|
|
1946
|
+
authorizationContext: (0, devConfirm_1.actionDigest)({ server: this.gatewayConfig.mcpServerName, downstream: this.downstreamSpec, cwd: process.cwd(), shieldId: this.gatewayConfig.shieldId, client: this.gatewayConfig.agentClient }),
|
|
1947
|
+
};
|
|
1882
1948
|
const sessionId = runtimeSessionId() || this.gatewaySessionId;
|
|
1949
|
+
const confirmationEvent = `mcp_gateway:${rememberScope.authorizationContext}:${rememberScope.policyHash}`;
|
|
1883
1950
|
const policyLabel = verdict.policyName ? ` (${verdict.policyName})` : '';
|
|
1884
1951
|
const ruleId = verdict.policyName ? `action-policy:${verdict.policyName}` : undefined;
|
|
1885
1952
|
const remembered = verdict.approval?.remember === 'none' ? undefined : (0, devConfirm_1.isConfirmationRemembered)(rememberScope, sessionId);
|
|
@@ -1894,8 +1961,24 @@ class McpGatewayServer {
|
|
|
1894
1961
|
}
|
|
1895
1962
|
const digest = (0, devConfirm_1.actionDigest)(toolArgs);
|
|
1896
1963
|
const remember = verdict.approval?.remember ?? 'none';
|
|
1964
|
+
// A standing "Always allow" from the FullCourtDefense dialog for this server + tool
|
|
1965
|
+
// + operation (+ destination) under this exact rule. Rules with `remember: none`
|
|
1966
|
+
// never offer it and never honour one.
|
|
1967
|
+
const grantToolName = this.gatewayConfig.mcpServerName ? `mcp__${this.gatewayConfig.mcpServerName}__${toolName}` : toolName;
|
|
1968
|
+
const grantScope = (0, devConfirm_1.grantScopeFor)('mcp', grantToolName, toolArgs, operation, (0, actionPolicyEngine_1.inferToolContext)(toolName, toolArgs).context);
|
|
1969
|
+
const grantRule = { policyId: verdict.policyId, policyName: verdict.policyName, matchedRule: verdict.matchedRule, policyHash: rememberScope.policyHash };
|
|
1970
|
+
const grant = remember === 'none' ? undefined : (0, devConfirm_1.findDeveloperGrant)(grantScope, grantRule);
|
|
1971
|
+
if (grant) {
|
|
1972
|
+
(0, telemetry_1.spoolEvent)({
|
|
1973
|
+
decision: 'allow', toolName, operation,
|
|
1974
|
+
reason: `developer granted Always allow for ${(0, devConfirm_1.describeGrantScope)(grant.scope)}${policyLabel}`,
|
|
1975
|
+
ruleId, offlineEnforced: true, approvalScope: 'developer', approvedBy: 'developer',
|
|
1976
|
+
});
|
|
1977
|
+
(0, telemetry_1.triggerFlush)(false);
|
|
1978
|
+
return true;
|
|
1979
|
+
}
|
|
1897
1980
|
const marker = (0, devConfirm_1.raiseDeveloperConfirmation)({
|
|
1898
|
-
event:
|
|
1981
|
+
event: confirmationEvent, ...rememberScope, argsDigest: digest,
|
|
1899
1982
|
policyId: verdict.policyId, policyName: verdict.policyName, matchedRule: verdict.matchedRule,
|
|
1900
1983
|
sessionId, remember,
|
|
1901
1984
|
});
|
|
@@ -1909,25 +1992,31 @@ class McpGatewayServer {
|
|
|
1909
1992
|
? ' This policy is set to Block; on a developer workstation it asks you instead. An admin can mark it "Hard block" in the console to stop this without asking.'
|
|
1910
1993
|
: '';
|
|
1911
1994
|
process.stderr.write(`FullCourtDefense asking the developer to confirm ${toolName}${policyLabel}: ${verdict.reason || verdict.matchedRule || 'action policy'}\n`);
|
|
1995
|
+
const alwaysScopeLabel = (0, devConfirm_1.describeGrantScope)(grantScope);
|
|
1912
1996
|
const answer = await this.confirmWithDeveloper({
|
|
1913
1997
|
toolName,
|
|
1914
1998
|
reason: `${verdict.reason || `${toolName} needs your confirmation`}.${ceiling}`,
|
|
1915
1999
|
allowRemember: false,
|
|
1916
2000
|
ruleLabel: verdict.policyName ? `Action Policy "${verdict.policyName}"${verdict.matchedRule ? ` — ${verdict.matchedRule}` : ''}` : 'Action Policy',
|
|
1917
2001
|
argsDigest: digest,
|
|
2002
|
+
allowAlways: remember !== 'none',
|
|
2003
|
+
alwaysScopeLabel,
|
|
1918
2004
|
});
|
|
1919
2005
|
if (answer.answer === 'accept') {
|
|
1920
2006
|
// Policy memory limits are authoritative; a client cannot upgrade 'none'.
|
|
1921
|
-
(0, devConfirm_1.settleDeveloperConfirmation)(
|
|
2007
|
+
(0, devConfirm_1.settleDeveloperConfirmation)(confirmationEvent, toolName, digest);
|
|
2008
|
+
const granted = answer.always && remember !== 'none' ? (0, devConfirm_1.recordDeveloperGrant)(grantScope, grantRule) : undefined;
|
|
1922
2009
|
(0, telemetry_1.spoolEvent)({
|
|
1923
2010
|
decision: 'allow', toolName, operation,
|
|
1924
|
-
reason:
|
|
2011
|
+
reason: granted
|
|
2012
|
+
? `developer chose Always allow in ${confirmChannelLabel(answer)} — ${alwaysScopeLabel} (30 days, this rule)${policyLabel}`
|
|
2013
|
+
: `developer confirmed in ${confirmChannelLabel(answer)}${answer.remember ? ' (remembered for this session)' : ''}${answer.clientAutoAnswered ? ' (the MCP client auto-declined the in-client prompt)' : ''}${policyLabel}`,
|
|
1925
2014
|
ruleId, offlineEnforced: true, approvalScope: 'developer', approvedBy: 'developer', confirmLatencyMs: answer.latencyMs,
|
|
1926
2015
|
});
|
|
1927
2016
|
(0, telemetry_1.triggerFlush)(false);
|
|
1928
2017
|
return true;
|
|
1929
2018
|
}
|
|
1930
|
-
(0, devConfirm_1.rejectDeveloperConfirmation)(
|
|
2019
|
+
(0, devConfirm_1.rejectDeveloperConfirmation)(confirmationEvent, toolName, digest);
|
|
1931
2020
|
const no = describeDeveloperNo(answer);
|
|
1932
2021
|
(0, telemetry_1.spoolEvent)({
|
|
1933
2022
|
decision: 'block', toolName, operation,
|
|
@@ -1961,7 +2050,8 @@ class McpGatewayServer {
|
|
|
1961
2050
|
async confirmWithDeveloper(input) {
|
|
1962
2051
|
if (!(0, devConfirm_1.isHumanPresent)())
|
|
1963
2052
|
return { answer: 'unavailable', remember: false, latencyMs: 0, clientAutoAnswered: false };
|
|
1964
|
-
const handoff = input.argsDigest
|
|
2053
|
+
const handoff = input.argsDigest && this.gatewayConfig.mcpServerName
|
|
2054
|
+
? (0, devConfirm_1.consumeConfirmedAction)(`mcp__${this.gatewayConfig.mcpServerName}__${input.toolName}`, input.argsDigest) : undefined;
|
|
1965
2055
|
if (handoff) {
|
|
1966
2056
|
return { answer: 'accept', remember: false, latencyMs: Math.max(0, Date.now() - Date.parse(handoff.confirmedAt)), channel: 'hook_dialog', clientAutoAnswered: false };
|
|
1967
2057
|
}
|
|
@@ -1988,10 +2078,10 @@ class McpGatewayServer {
|
|
|
1988
2078
|
}
|
|
1989
2079
|
async askInOsDialog(input, clientAutoAnswered) {
|
|
1990
2080
|
const evidence = input.evidence ? `\nEvidence: ${input.evidence.slice(0, 240)}` : '';
|
|
1991
|
-
const dialog = await (0, devConfirm_1.confirmNativeActionDetailed)(`Agent: ${this.gatewayConfig.agentName}\nIDE: ${this.gatewayConfig.agentClient}\nDeveloper: ${this.gatewayConfig.developerName || 'Unknown'}\nTool: ${input.toolName}\nRule: ${input.ruleLabel}\nWhy: ${input.reason}${evidence}\n\nYour answer is reported to your security dashboard as your decision.`, OS_DIALOG_TIMEOUT_MS);
|
|
2081
|
+
const dialog = await (0, devConfirm_1.confirmNativeActionDetailed)(`Agent: ${this.gatewayConfig.agentName}\nIDE: ${this.gatewayConfig.agentClient}\nDeveloper: ${this.gatewayConfig.developerName || 'Unknown'}\nTool: ${input.toolName}\nRule: ${input.ruleLabel}\nWhy: ${input.reason}${evidence}\n\nYour answer is reported to your security dashboard as your decision.`, OS_DIALOG_TIMEOUT_MS, { allowAlways: input.allowAlways === true, alwaysScopeLabel: input.alwaysScopeLabel });
|
|
1992
2082
|
process.stderr.write(`FullCourtDefense: dialog for ${input.toolName} ended with "${dialog.outcome}" after ${dialog.latencyMs}ms.\n`);
|
|
1993
|
-
const answer = dialog.outcome === 'allow' ? 'accept' : dialog.outcome === 'deny' ? 'decline' : dialog.outcome;
|
|
1994
|
-
return { answer, remember: false, latencyMs: dialog.latencyMs, channel: 'os_dialog', clientAutoAnswered };
|
|
2083
|
+
const answer = dialog.outcome === 'allow' || dialog.outcome === 'allow_always' ? 'accept' : dialog.outcome === 'deny' ? 'decline' : dialog.outcome;
|
|
2084
|
+
return { answer, remember: false, always: dialog.outcome === 'allow_always', latencyMs: dialog.latencyMs, channel: 'os_dialog', clientAutoAnswered };
|
|
1995
2085
|
}
|
|
1996
2086
|
async elicitDeveloperConfirmation(input) {
|
|
1997
2087
|
const started = Date.now();
|
|
@@ -2010,7 +2100,7 @@ class McpGatewayServer {
|
|
|
2010
2100
|
...(input.allowRemember === false ? {} : { remember: {
|
|
2011
2101
|
type: 'boolean',
|
|
2012
2102
|
title: 'Remember for this session',
|
|
2013
|
-
description: '
|
|
2103
|
+
description: 'Remember this exact action in this session (max 12 hours). Changed arguments, server or policy require a new approval.',
|
|
2014
2104
|
default: false,
|
|
2015
2105
|
} }),
|
|
2016
2106
|
},
|
|
@@ -2083,6 +2173,9 @@ function readJson(file) {
|
|
|
2083
2173
|
function gatewayScriptPath() {
|
|
2084
2174
|
return path.resolve(process.argv[1] || path.join(__dirname, '..', 'index.js'));
|
|
2085
2175
|
}
|
|
2176
|
+
function gatewayRuntime(entry) {
|
|
2177
|
+
return (0, gatewayRuntime_1.resolveGatewayRuntime)({ executable: process.execPath, entry: gatewayScriptPath() }, entry);
|
|
2178
|
+
}
|
|
2086
2179
|
/**
|
|
2087
2180
|
* Resolve which real MCP server an installer should protect: a local stdio
|
|
2088
2181
|
* command (--mcp-command/--mcp-args) or a remote HTTP/SSE URL (--mcp-url,
|
|
@@ -2115,6 +2208,7 @@ function buildGatewayCommandArgs(gatewayConfig, downstream, options = {}) {
|
|
|
2115
2208
|
gatewayScriptPath(),
|
|
2116
2209
|
'mcp-gateway',
|
|
2117
2210
|
...downstreamFlags,
|
|
2211
|
+
...(gatewayConfig.mcpServerName ? ['--mcp-server-name', gatewayConfig.mcpServerName] : []),
|
|
2118
2212
|
'--agent-name', gatewayConfig.agentName,
|
|
2119
2213
|
'--agent-client', gatewayConfig.agentClient,
|
|
2120
2214
|
'--developer-name', gatewayConfig.developerName,
|
|
@@ -2477,9 +2571,10 @@ function isGatewayWrappedEntry(entry) {
|
|
|
2477
2571
|
function wrappedEntryNeedsHeal(entry) {
|
|
2478
2572
|
const args = Array.isArray(entry?.args) ? entry.args.map(String) : [];
|
|
2479
2573
|
const credentialPairStale = args.includes('--shield-id') && !args.includes('--shield-key');
|
|
2480
|
-
const
|
|
2574
|
+
const runtime = gatewayRuntime(entry);
|
|
2575
|
+
const runtimePathStale = (0, discoverPaths_1.normalizedPath)(String(entry?.command || '')) !== (0, discoverPaths_1.normalizedPath)(runtime.executable)
|
|
2481
2576
|
|| !args[0]
|
|
2482
|
-
|| (0, discoverPaths_1.normalizedPath)(args[0]) !== (0, discoverPaths_1.normalizedPath)(
|
|
2577
|
+
|| (0, discoverPaths_1.normalizedPath)(args[0]) !== (0, discoverPaths_1.normalizedPath)(runtime.entry);
|
|
2483
2578
|
return credentialPairStale || runtimePathStale;
|
|
2484
2579
|
}
|
|
2485
2580
|
/** Recover the original downstream server (stdio command or remote URL) from a wrapped entry's args. */
|
|
@@ -2745,6 +2840,7 @@ function healCodexTomlAgentIdentities(file, dryRun) {
|
|
|
2745
2840
|
* entry reported `boazl-claude-desktop`. An explicit --agent-name / FCD_AGENT_NAME still wins.
|
|
2746
2841
|
*/
|
|
2747
2842
|
function applyPerServerAgentName(gatewayConfig, args, serverName) {
|
|
2843
|
+
gatewayConfig = { ...gatewayConfig, mcpServerName: serverName };
|
|
2748
2844
|
if (args.agentName || process.env.FCD_AGENT_NAME)
|
|
2749
2845
|
return gatewayConfig;
|
|
2750
2846
|
if (!serverName || serverName === MANAGED_SERVER_NAME)
|
|
@@ -2766,6 +2862,7 @@ function perServerGatewayConfig(gatewayConfig, agentClient, serverName) {
|
|
|
2766
2862
|
return {
|
|
2767
2863
|
...gatewayConfig,
|
|
2768
2864
|
agentClient,
|
|
2865
|
+
mcpServerName: serverName,
|
|
2769
2866
|
agentName: perServerAgentName(gatewayConfig.developerName, agentClient, serverName),
|
|
2770
2867
|
userObjective: gatewayConfig.userObjectiveExplicit ? gatewayConfig.userObjective : defaultUserObjective(agentClient),
|
|
2771
2868
|
};
|
|
@@ -2801,12 +2898,14 @@ function wrapJsonConfigFile(file, gatewayConfig, agentClient, dryRun) {
|
|
|
2801
2898
|
const downstream = credentialPairStale ? extractFullyUnwrappedDownstream(entry) : null;
|
|
2802
2899
|
if (!credentialPairStale || downstream) {
|
|
2803
2900
|
const perServer = perServerGatewayConfig(gatewayConfig, agentClient, name);
|
|
2804
|
-
|
|
2901
|
+
const runtime = gatewayRuntime(entry);
|
|
2902
|
+
entry.command = runtime.executable;
|
|
2805
2903
|
// Path-only upgrades preserve every downstream/config flag exactly.
|
|
2806
2904
|
// The credential-pair bug requires a safe rebuild from downstream.
|
|
2807
|
-
|
|
2905
|
+
const repairedArgs = credentialPairStale
|
|
2808
2906
|
? buildGatewayCommandArgs(perServer, downstream, INSTALL_GATEWAY_ARGS)
|
|
2809
|
-
:
|
|
2907
|
+
: existingArgs;
|
|
2908
|
+
entry.args = [runtime.entry, ...repairedArgs.slice(1)];
|
|
2810
2909
|
stats.healed.push(name);
|
|
2811
2910
|
changed = true;
|
|
2812
2911
|
continue;
|
|
@@ -3010,13 +3109,21 @@ function transformCodexToml(file, mode, gatewayConfig, dryRun) {
|
|
|
3010
3109
|
}
|
|
3011
3110
|
if (wrappedAlready) {
|
|
3012
3111
|
const existingArgs = section.args || [];
|
|
3013
|
-
const
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
if (
|
|
3112
|
+
const entry = { command: section.command, args: existingArgs };
|
|
3113
|
+
const runtime = gatewayRuntime(entry);
|
|
3114
|
+
const credentialPairStale = existingArgs.includes('--shield-id') && !existingArgs.includes('--shield-key');
|
|
3115
|
+
if (wrappedEntryNeedsHeal(entry)) {
|
|
3116
|
+
const downstream = credentialPairStale ? extractFullyUnwrappedDownstream(entry) : null;
|
|
3117
|
+
// An invalid wrapper cannot be reconstructed without its downstream.
|
|
3118
|
+
// Leave it visible as unhealthy instead of manufacturing a success.
|
|
3119
|
+
if (credentialPairStale && !downstream)
|
|
3120
|
+
continue;
|
|
3017
3121
|
const indent = lines[section.cmdLine].match(/^\s*/)?.[0] || '';
|
|
3018
|
-
lines[section.cmdLine] = `${indent}command = ${JSON.stringify(
|
|
3019
|
-
const
|
|
3122
|
+
lines[section.cmdLine] = `${indent}command = ${JSON.stringify(runtime.executable)}`;
|
|
3123
|
+
const args = credentialPairStale
|
|
3124
|
+
? buildGatewayCommandArgs(perServerGatewayConfig(gatewayConfig, 'codex', section.name), downstream, INSTALL_GATEWAY_ARGS)
|
|
3125
|
+
: existingArgs;
|
|
3126
|
+
const repairedArgs = [runtime.entry, ...args.slice(1)];
|
|
3020
3127
|
const argsLineText = `${indent}args = ${tomlStringArrayLiteral(repairedArgs)}`;
|
|
3021
3128
|
if (section.argsLine !== -1)
|
|
3022
3129
|
lines[section.argsLine] = argsLineText;
|
package/dist/commands/onboard.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.onboardCommand = onboardCommand;
|
|
37
37
|
const child_process_1 = require("child_process");
|
|
38
|
+
const onboardingSummary_1 = require("./onboardingSummary");
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
39
40
|
const os = __importStar(require("os"));
|
|
40
41
|
const path = __importStar(require("path"));
|
|
@@ -669,15 +670,15 @@ async function onboardCommand(args, config) {
|
|
|
669
670
|
// already open still run their OLD (unwrapped) configuration until they
|
|
670
671
|
// restart. Never print an unconditional green "protected" before that.
|
|
671
672
|
const runningClients = dryRun ? [] : detectRunningAiClients();
|
|
672
|
-
console.log(`${GREEN}${BOLD}
|
|
673
|
-
if (runningClients.length > 0) {
|
|
673
|
+
console.log(`${GREEN}${BOLD}${(0, onboardingSummary_1.onboardingVerificationSummary)({ dryRun, firstHeartbeatOk })}${RESET}`);
|
|
674
|
+
if (!dryRun && runningClients.length > 0) {
|
|
674
675
|
console.log('');
|
|
675
676
|
console.log(`${YELLOW}${BOLD} ! ACTION REQUIRED — restart ${runningClients.join(', ')}.${RESET}`);
|
|
676
|
-
console.log(`${YELLOW}
|
|
677
|
+
console.log(`${YELLOW} Restart to load the installed integrations, then check reported coverage and a test action in the console.${RESET}`);
|
|
677
678
|
}
|
|
678
|
-
else {
|
|
679
|
+
else if (!dryRun) {
|
|
679
680
|
console.log('');
|
|
680
|
-
console.log(`${YELLOW}${BOLD} ! One step left:${RESET} ${YELLOW}restart
|
|
681
|
+
console.log(`${YELLOW}${BOLD} ! One step left:${RESET} ${YELLOW}restart AI apps that were open during onboarding so they load the installed integrations. Check reported coverage and a test action in the console.${RESET}`);
|
|
681
682
|
}
|
|
682
683
|
console.log('');
|
|
683
684
|
console.log(`${DIM}Fleet view: ${dashboard}${RESET}`);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.onboardingVerificationSummary = onboardingVerificationSummary;
|
|
4
|
+
/** Describe only the installation and delivery evidence collected by onboard. */
|
|
5
|
+
function onboardingVerificationSummary(input) {
|
|
6
|
+
if (input.dryRun)
|
|
7
|
+
return 'Dry-run checks passed. Installation and reporting were not verified.';
|
|
8
|
+
return 'Installation checks passed. ' + (input.firstHeartbeatOk
|
|
9
|
+
? 'The console received the first machine report. Check Policies for this machine’s current enforcement mode.'
|
|
10
|
+
: 'The first machine report was not delivered. Check the connection and retry; console visibility is not yet confirmed.');
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BotGuardConfig } from '../config';
|
|
2
|
+
import { VerifiableMachineAction } from '../machineActionVerify';
|
|
3
|
+
import { ProtectionProfile } from '../protectionProfile';
|
|
4
|
+
export declare function verifiedProtectionProfile(envelope: VerifiableMachineAction | null | undefined, machineId: string, shieldId: string): ProtectionProfile;
|
|
5
|
+
export declare function protectedRunCommand(config: BotGuardConfig, command: string | undefined, inspect?: boolean): Promise<void>;
|
|
6
|
+
/** Existing machine Activity receives minimized launch outcome evidence. */
|
|
7
|
+
export declare class ContainedLaunchFailure extends Error {
|
|
8
|
+
readonly executionStarted: boolean;
|
|
9
|
+
constructor(message: string, executionStarted: boolean);
|
|
10
|
+
}
|
|
11
|
+
export declare function runProtectedLaunch(profile: ProtectionProfile, command: string, revision: string, launch?: typeof runContainedCommand): Promise<number>;
|
|
12
|
+
export declare function containedExecutionEnvironment(source: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
13
|
+
/** Runtime adapter, shared with real-process OS acceptance tests. */
|
|
14
|
+
export declare function runContainedCommand(value: ProtectionProfile, command: string): Promise<number>;
|