@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
223 lines • 7.64 kB
TypeScript
/**
* Danger Zone Enforcer
*
* Provides programmatic enforcement for DANGER_ZONE safety tier.
* Maintains a list of blocked agent execution contexts and prevents
* further tool execution until verification is completed.
*
* This addresses Issue #110 - the semantic-only approach is insufficient
* for the highest risk tier, as a compromised LLM could ignore warnings.
*
* Issue #402: Refactored from singleton to DI-managed class with
* file-based persistence. Blocks survive server restarts via
* ~/.dollhouse/security/blocked-agents.json.
*
* @since v2.0.0 - Agentic Loop Completion (Epic #380)
* @since v2.1.0 - File-based persistence (Issue #402)
*/
import type { FileOperationsService } from '../services/FileOperationsService.js';
/**
* Audit context captured when a danger zone block occurs (Issue #404).
* Provides full execution context for post-hoc investigation of blocks.
*
* NOTE: The DangerZoneBlocker interface in types.ts has a structurally
* identical inline type. Keep both in sync when modifying fields.
*/
export interface DangerZoneAuditContext {
stepNumber?: number;
currentStepDescription?: string;
currentStepOutcome?: string;
nextActionHint?: string;
riskScore?: number;
goalDescription?: string;
goalId?: string;
safetyFactors?: string[];
}
/**
* Result of a block check
*/
export interface BlockCheckResult {
/** Whether the context is blocked */
blocked: boolean;
/** Reason for blocking (if blocked) */
reason?: string;
/** How to resolve the block */
resolution?: string;
/** Verification ID if verification is required */
verificationId?: string;
}
/**
* Metrics for danger zone enforcement
*/
export interface DangerZoneMetrics {
/** Current number of blocked agents */
currentBlockedCount: number;
/** Total blocks since startup */
totalBlocksSinceStartup: number;
/** Total unblocks since startup */
totalUnblocksSinceStartup: number;
/** Total clearAll calls since startup */
totalClearAllCalls: number;
/** Average block duration in milliseconds (for unblocked agents) */
averageBlockDurationMs: number;
/** Longest block duration in milliseconds */
longestBlockDurationMs: number;
}
/**
* DI-managed class for danger zone enforcement with file-based persistence.
*
* Thread-safety note: This uses a Map which is not inherently thread-safe,
* but in a Node.js single-threaded environment this is acceptable.
* For multi-process deployments, consider Redis or similar.
*
* Persistence: Blocks are persisted to ~/.dollhouse/security/blocked-agents.json.
* The in-memory Map is the hot path for check(); disk is the durable backing store.
* Disk writes are fire-and-forget — disk failure does not block enforcement.
*/
export declare class DangerZoneEnforcer {
private blockedContexts;
private totalBlocksSinceStartup;
private totalUnblocksSinceStartup;
private totalClearAllCalls;
private blockDurations;
private adminToken;
private readonly fileOps;
private readonly securityDir;
private readonly persistPath;
constructor(fileOps: FileOperationsService, securityDir?: string);
/**
* Load persisted blocks from disk.
* Call once after construction to restore state from a previous session.
* If the file is missing or corrupt, starts with empty blocks.
*
* @example
* ```ts
* const enforcer = new DangerZoneEnforcer(fileOps);
* await enforcer.initialize(); // restores blocks from ~/.dollhouse/security/blocked-agents.json
* ```
*/
initialize(): Promise<void>;
/**
* Block an agent context due to danger zone trigger
*
* @param agentName - Name of the agent to block
* @param reason - Why the agent is blocked
* @param triggeredPatterns - Patterns that caused the block
* @param verificationId - Optional verification ID for unblocking
* @param auditContext - Optional execution context for audit trail (Issue #404)
* @throws Error if agentName is invalid
*
* @example
* ```ts
* enforcer.block('code-reviewer', 'Danger zone pattern matched', ['rm -rf'], 'verify-abc');
* enforcer.check('code-reviewer').blocked; // true
* ```
*/
block(agentName: string, reason: string, triggeredPatterns: string[], verificationId?: string, auditContext?: DangerZoneAuditContext): void;
/**
* Unblock an agent context after verification
*
* @param agentName - Name of the agent to unblock
* @param verificationId - Verification ID that was completed
* @returns Whether the unblock was successful
* @throws Error if agentName is invalid
*
* @example
* ```ts
* enforcer.block('code-reviewer', 'Blocked', ['rm -rf'], 'verify-abc');
*
* enforcer.unblock('code-reviewer', 'wrong-id'); // false — mismatch
* enforcer.unblock('code-reviewer', 'verify-abc'); // true — success
* ```
*/
unblock(agentName: string, verificationId?: string): boolean;
/**
* Check if an agent context is blocked
*
* @param agentName - Name of the agent to check
* @returns Block check result
* @throws Error if agentName is invalid
*
* @example
* ```ts
* const result = enforcer.check('code-reviewer');
* if (result.blocked) {
* console.log(result.reason); // why it was blocked
* console.log(result.resolution); // how to unblock
* }
* ```
*/
check(agentName: string): BlockCheckResult;
/**
* Check if any agent is currently blocked
* Useful for diagnostics
*
* @example
* ```ts
* if (enforcer.hasBlockedAgents()) {
* console.log('Blocked agents:', enforcer.getBlockedAgents());
* }
* ```
*/
hasBlockedAgents(): boolean;
/**
* Get list of all blocked agents
* Useful for admin/diagnostic purposes
*
* @example
* ```ts
* const agents = enforcer.getBlockedAgents(); // ['code-reviewer', 'data-agent']
* ```
*/
getBlockedAgents(): string[];
/**
* Clear all blocks (for testing or admin reset)
*
* When DOLLHOUSE_DANGER_ZONE_ADMIN_TOKEN is set, requires matching token.
* Without environment variable, clearAll is unrestricted (for testing).
*
* @param adminToken - Admin token for authorization (required if env var is set)
* @returns Whether the clear was successful
*
* @example
* ```ts
* // Without admin token configured
* enforcer.clearAll(); // true
*
* // With admin token configured
* enforcer.clearAll('wrong-token'); // false
* enforcer.clearAll('correct-token'); // true
* ```
*/
clearAll(adminToken?: string): boolean;
/**
* Get metrics for danger zone enforcement
* Useful for monitoring and diagnostics
*
* @example
* ```ts
* const metrics = enforcer.getMetrics();
* console.log(metrics.averageBlockDurationMs); // rolling window (see METRICS_WINDOW_SIZE)
* ```
*/
getMetrics(): DangerZoneMetrics;
/**
* Set admin token programmatically (for testing)
* @internal
*/
setAdminToken(token: string | null): void;
/**
* Reset metrics (for testing)
* @internal
*/
resetMetrics(): void;
/**
* Fire-and-forget persistence. Disk failure does not block enforcement.
*/
private persistAsync;
/**
* Write current block state to disk.
*/
private persist;
}
//# sourceMappingURL=DangerZoneEnforcer.d.ts.map