@riotprompt/riotprompt 0.0.21 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -0
- package/MIGRATION.md +235 -0
- package/README.md +2 -0
- package/SECURITY.md +132 -0
- package/dist/builder.js +6 -0
- package/dist/builder.js.map +1 -1
- package/dist/cli.js +481 -22
- package/dist/context-manager.js +1 -1
- package/dist/conversation-logger.d.ts +17 -1
- package/dist/conversation-logger.js +21 -17
- package/dist/conversation-logger.js.map +1 -1
- package/dist/conversation.js +1 -1
- package/dist/error-handling.d.ts +52 -0
- package/dist/error-handling.js +132 -0
- package/dist/error-handling.js.map +1 -0
- package/dist/formatter.js +1 -1
- package/dist/iteration-strategy.js +1 -1
- package/dist/loader.js +60 -12
- package/dist/loader.js.map +1 -1
- package/dist/logger.d.ts +52 -0
- package/dist/logger.js +114 -14
- package/dist/logger.js.map +1 -1
- package/dist/logging-config.d.ts +84 -0
- package/dist/logging-config.js +116 -0
- package/dist/logging-config.js.map +1 -0
- package/dist/message-builder.js +1 -1
- package/dist/model-config.js +1 -1
- package/dist/override.js +10 -4
- package/dist/override.js.map +1 -1
- package/dist/recipes.js +6 -0
- package/dist/recipes.js.map +1 -1
- package/dist/reflection.js +1 -1
- package/dist/riotprompt.d.ts +9 -0
- package/dist/riotprompt.js +8 -0
- package/dist/riotprompt.js.map +1 -1
- package/dist/security/audit-logger.d.ts +61 -0
- package/dist/security/audit-logger.js +281 -0
- package/dist/security/audit-logger.js.map +1 -0
- package/dist/security/cli-security.d.ts +143 -0
- package/dist/security/cli-security.js +302 -0
- package/dist/security/cli-security.js.map +1 -0
- package/dist/security/defaults.d.ts +31 -0
- package/dist/security/defaults.js +72 -0
- package/dist/security/defaults.js.map +1 -0
- package/dist/security/events.d.ts +8 -0
- package/dist/security/index.d.ts +27 -0
- package/dist/security/index.js +22 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/path-guard.d.ts +161 -0
- package/dist/security/path-guard.js +327 -0
- package/dist/security/path-guard.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +117 -0
- package/dist/security/rate-limiter.js +165 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/security/serialization-schemas.d.ts +183 -0
- package/dist/security/serialization-schemas.js +174 -0
- package/dist/security/serialization-schemas.js.map +1 -0
- package/dist/security/timeout-guard.d.ts +123 -0
- package/dist/security/timeout-guard.js +223 -0
- package/dist/security/timeout-guard.js.map +1 -0
- package/dist/security/types.d.ts +86 -0
- package/dist/security/types.js +80 -0
- package/dist/security/types.js.map +1 -0
- package/dist/token-budget.js +1 -1
- package/dist/tools.js +1 -1
- package/guide/index.md +2 -0
- package/guide/integration.md +1109 -0
- package/guide/security.md +237 -0
- package/package.json +17 -11
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-logger.js","sources":["../../src/security/audit-logger.ts"],"sourcesContent":["import { SecurityEvent, SecurityEventType } from './events';\nimport { Logger, DEFAULT_LOGGER, wrapLogger } from '../logger';\n\nexport interface AuditLoggerConfig {\n enabled: boolean;\n logLevel: 'all' | 'warning' | 'error' | 'critical';\n includeContext: boolean;\n maxContextSize: number;\n onEvent?: (event: SecurityEvent) => void;\n}\n\nconst DEFAULT_CONFIG: AuditLoggerConfig = {\n enabled: true,\n logLevel: 'warning',\n includeContext: true,\n maxContextSize: 1000,\n};\n\nexport class SecurityAuditLogger {\n private config: AuditLoggerConfig;\n private logger: Logger;\n private eventCount: Map<SecurityEventType, number> = new Map();\n\n constructor(config: Partial<AuditLoggerConfig> = {}, logger?: Logger) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.logger = wrapLogger(logger || DEFAULT_LOGGER, 'SecurityAudit');\n }\n\n /**\n * Log a security event\n */\n log(event: Omit<SecurityEvent, 'timestamp'>): void {\n if (!this.config.enabled) return;\n\n const fullEvent: SecurityEvent = {\n ...event,\n timestamp: new Date(),\n context: this.sanitizeContext(event.context),\n };\n\n // Track event counts\n const count = this.eventCount.get(event.type) || 0;\n this.eventCount.set(event.type, count + 1);\n\n // Always call event handler for monitoring (before log level filter)\n this.config.onEvent?.(fullEvent);\n\n // Check log level for actual logging output\n if (!this.shouldLog(event.severity)) return;\n\n // Log the event\n const logMessage = this.formatEvent(fullEvent);\n \n switch (event.severity) {\n case 'critical':\n this.logger.error(`[CRITICAL] ${logMessage}`);\n break;\n case 'error':\n this.logger.error(logMessage);\n break;\n case 'warning':\n this.logger.warn(logMessage);\n break;\n case 'info':\n this.logger.info(logMessage);\n break;\n }\n }\n\n /**\n * Convenience methods for common events\n */\n pathTraversalBlocked(path: string, reason: string): void {\n this.log({\n type: 'path_traversal_blocked',\n severity: 'warning',\n message: `Path traversal attempt blocked: ${reason}`,\n context: { attemptedPath: this.sanitizePath(path) },\n });\n }\n\n pathValidationFailed(path: string, reason: string): void {\n this.log({\n type: 'path_validation_failed',\n severity: 'warning',\n message: `Path validation failed: ${reason}`,\n context: { attemptedPath: this.sanitizePath(path) },\n });\n }\n\n toolValidationFailed(toolName: string, reason: string): void {\n this.log({\n type: 'tool_validation_failed',\n severity: 'warning',\n message: `Tool parameter validation failed for \"${toolName}\": ${reason}`,\n context: { toolName },\n });\n }\n\n toolExecutionBlocked(toolName: string, reason: string): void {\n this.log({\n type: 'tool_execution_blocked',\n severity: 'error',\n message: `Tool execution blocked for \"${toolName}\": ${reason}`,\n context: { toolName },\n });\n }\n\n toolTimeout(toolName: string, timeoutMs: number): void {\n this.log({\n type: 'tool_timeout',\n severity: 'warning',\n message: `Tool \"${toolName}\" timed out after ${timeoutMs}ms`,\n context: { toolName, timeoutMs },\n });\n }\n\n secretRedacted(source: string): void {\n this.log({\n type: 'secret_redacted',\n severity: 'info',\n message: `Sensitive data redacted from ${source}`,\n context: { source },\n });\n }\n\n apiKeyUsed(provider: string): void {\n this.log({\n type: 'api_key_used',\n severity: 'info',\n message: `API key accessed for provider: ${provider}`,\n context: { provider },\n });\n }\n\n deserializationFailed(source: string, reason: string): void {\n this.log({\n type: 'deserialization_failed',\n severity: 'warning',\n message: `Deserialization failed from ${source}: ${reason}`,\n context: { source },\n });\n }\n\n regexTimeout(pattern: string, timeoutMs: number): void {\n this.log({\n type: 'regex_timeout',\n severity: 'warning',\n message: `Regex operation timed out after ${timeoutMs}ms`,\n context: { patternLength: pattern.length, timeoutMs },\n });\n }\n\n requestTimeout(operation: string, timeoutMs: number): void {\n this.log({\n type: 'request_timeout',\n severity: 'warning',\n message: `Operation \"${operation}\" timed out after ${timeoutMs}ms`,\n context: { operation, timeoutMs },\n });\n }\n\n rateLimitExceeded(resource: string, limit: number): void {\n this.log({\n type: 'rate_limit_exceeded',\n severity: 'warning',\n message: `Rate limit exceeded for ${resource}: limit is ${limit}`,\n context: { resource, limit },\n });\n }\n\n /**\n * Get event statistics\n */\n getStats(): Map<SecurityEventType, number> {\n return new Map(this.eventCount);\n }\n\n /**\n * Get total event count\n */\n getTotalEventCount(): number {\n let total = 0;\n for (const count of this.eventCount.values()) {\n total += count;\n }\n return total;\n }\n\n /**\n * Reset statistics\n */\n resetStats(): void {\n this.eventCount.clear();\n }\n\n /**\n * Check if any events of a specific type have been logged\n */\n hasEventsOfType(type: SecurityEventType): boolean {\n return (this.eventCount.get(type) || 0) > 0;\n }\n\n /**\n * Get count for a specific event type\n */\n getEventCount(type: SecurityEventType): number {\n return this.eventCount.get(type) || 0;\n }\n\n private shouldLog(severity: SecurityEvent['severity']): boolean {\n const levels = ['info', 'warning', 'error', 'critical'];\n const configLevel = levels.indexOf(this.config.logLevel === 'all' ? 'info' : this.config.logLevel);\n const eventLevel = levels.indexOf(severity);\n return eventLevel >= configLevel;\n }\n\n private formatEvent(event: SecurityEvent): string {\n let message = `[${event.type}] ${event.message}`;\n if (this.config.includeContext && event.context) {\n message += ` | Context: ${JSON.stringify(event.context)}`;\n }\n return message;\n }\n\n private sanitizeContext(context?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (!context || !this.config.includeContext) return undefined;\n\n const sanitized: Record<string, unknown> = {};\n let size = 0;\n\n for (const [key, value] of Object.entries(context)) {\n const stringValue = String(value);\n if (size + stringValue.length > this.config.maxContextSize) break;\n \n // Never log sensitive-looking values\n if (this.looksLikeSensitiveKey(key)) {\n sanitized[key] = '[REDACTED]';\n } else {\n sanitized[key] = value;\n }\n size += stringValue.length;\n }\n\n return sanitized;\n }\n\n private sanitizePath(path: string): string {\n // Only show last component and length\n const parts = path.split(/[/\\\\]/);\n const lastPart = parts[parts.length - 1];\n return `.../${lastPart} (${path.length} chars)`;\n }\n\n private looksLikeSensitiveKey(key: string): boolean {\n const sensitivePatterns = [\n /key/i, /secret/i, /password/i, /token/i, /auth/i, /credential/i\n ];\n return sensitivePatterns.some(p => p.test(key));\n }\n}\n\n// Global instance for convenience\nlet globalAuditLogger: SecurityAuditLogger | null = null;\n\nexport function getAuditLogger(): SecurityAuditLogger {\n if (!globalAuditLogger) {\n globalAuditLogger = new SecurityAuditLogger();\n }\n return globalAuditLogger;\n}\n\nexport function configureAuditLogger(config: Partial<AuditLoggerConfig>, logger?: Logger): void {\n globalAuditLogger = new SecurityAuditLogger(config, logger);\n}\n\nexport function resetAuditLogger(): void {\n globalAuditLogger = null;\n}\n\n"],"names":["DEFAULT_CONFIG","enabled","logLevel","includeContext","maxContextSize","SecurityAuditLogger","log","event","config","fullEvent","timestamp","Date","context","sanitizeContext","count","eventCount","get","type","set","onEvent","shouldLog","severity","logMessage","formatEvent","logger","error","warn","info","pathTraversalBlocked","path","reason","message","attemptedPath","sanitizePath","pathValidationFailed","toolValidationFailed","toolName","toolExecutionBlocked","toolTimeout","timeoutMs","secretRedacted","source","apiKeyUsed","provider","deserializationFailed","regexTimeout","pattern","patternLength","length","requestTimeout","operation","rateLimitExceeded","resource","limit","getStats","Map","getTotalEventCount","total","values","resetStats","clear","hasEventsOfType","getEventCount","levels","configLevel","indexOf","eventLevel","JSON","stringify","undefined","sanitized","size","key","value","Object","entries","stringValue","String","looksLikeSensitiveKey","parts","split","lastPart","sensitivePatterns","some","p","test","wrapLogger","DEFAULT_LOGGER","globalAuditLogger","getAuditLogger","configureAuditLogger","resetAuditLogger"],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { PathGuard, PathSecurityConfig } from './path-guard';
|
|
3
|
+
/**
|
|
4
|
+
* CLI Security configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface CLISecurityConfig {
|
|
7
|
+
/** Enable CLI security validation */
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
/** Path security configuration */
|
|
10
|
+
paths: Partial<PathSecurityConfig>;
|
|
11
|
+
/** Allowed file extensions for input files */
|
|
12
|
+
allowedExtensions: string[];
|
|
13
|
+
/** Maximum string length for inputs */
|
|
14
|
+
maxStringLength: number;
|
|
15
|
+
/** Allow null bytes in strings */
|
|
16
|
+
allowNullBytes: boolean;
|
|
17
|
+
/** Allow control characters in strings */
|
|
18
|
+
allowControlChars: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Default CLI security configuration
|
|
22
|
+
*/
|
|
23
|
+
export declare const DEFAULT_CLI_SECURITY: CLISecurityConfig;
|
|
24
|
+
/**
|
|
25
|
+
* String validation result
|
|
26
|
+
*/
|
|
27
|
+
export interface StringValidationResult {
|
|
28
|
+
valid: boolean;
|
|
29
|
+
sanitized?: string;
|
|
30
|
+
error?: string;
|
|
31
|
+
violation?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* CLIValidator provides security validation for CLI inputs.
|
|
35
|
+
*
|
|
36
|
+
* Features:
|
|
37
|
+
* - Path validation with traversal prevention
|
|
38
|
+
* - String sanitization
|
|
39
|
+
* - Extension filtering
|
|
40
|
+
* - Audit logging
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const validator = new CLIValidator();
|
|
45
|
+
*
|
|
46
|
+
* // Validate a path argument
|
|
47
|
+
* const pathResult = validator.validatePath('../../../etc/passwd');
|
|
48
|
+
* if (!pathResult.valid) {
|
|
49
|
+
* console.error(pathResult.error);
|
|
50
|
+
* process.exit(1);
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* // Validate a string argument
|
|
54
|
+
* const stringResult = validator.validateString(userInput);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare class CLIValidator {
|
|
58
|
+
private config;
|
|
59
|
+
private pathGuard;
|
|
60
|
+
private auditLogger;
|
|
61
|
+
constructor(config?: Partial<CLISecurityConfig>);
|
|
62
|
+
/**
|
|
63
|
+
* Validate a path argument
|
|
64
|
+
*
|
|
65
|
+
* @param inputPath - The path to validate
|
|
66
|
+
* @param options - Additional validation options
|
|
67
|
+
* @returns Validation result
|
|
68
|
+
*/
|
|
69
|
+
validatePath(inputPath: string, options?: {
|
|
70
|
+
checkExtension?: boolean;
|
|
71
|
+
operation?: string;
|
|
72
|
+
}): {
|
|
73
|
+
valid: boolean;
|
|
74
|
+
normalizedPath?: string;
|
|
75
|
+
error?: string;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Validate a string argument
|
|
79
|
+
*
|
|
80
|
+
* @param input - The string to validate
|
|
81
|
+
* @returns Validation result with sanitized string
|
|
82
|
+
*/
|
|
83
|
+
validateString(input: string): StringValidationResult;
|
|
84
|
+
/**
|
|
85
|
+
* Validate a numeric argument
|
|
86
|
+
*
|
|
87
|
+
* @param input - The number to validate
|
|
88
|
+
* @param options - Validation options
|
|
89
|
+
* @returns Validation result
|
|
90
|
+
*/
|
|
91
|
+
validateNumber(input: number, options?: {
|
|
92
|
+
min?: number;
|
|
93
|
+
max?: number;
|
|
94
|
+
integer?: boolean;
|
|
95
|
+
allowNaN?: boolean;
|
|
96
|
+
allowInfinity?: boolean;
|
|
97
|
+
}): {
|
|
98
|
+
valid: boolean;
|
|
99
|
+
error?: string;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Create a Zod schema for secure path validation
|
|
103
|
+
*/
|
|
104
|
+
securePathSchema(options?: {
|
|
105
|
+
checkExtension?: boolean;
|
|
106
|
+
}): z.ZodString;
|
|
107
|
+
/**
|
|
108
|
+
* Create a Zod schema for secure string validation
|
|
109
|
+
*/
|
|
110
|
+
secureStringSchema(): z.ZodString;
|
|
111
|
+
/**
|
|
112
|
+
* Create a Zod schema for secure number validation
|
|
113
|
+
*/
|
|
114
|
+
secureNumberSchema(options?: {
|
|
115
|
+
min?: number;
|
|
116
|
+
max?: number;
|
|
117
|
+
integer?: boolean;
|
|
118
|
+
}): z.ZodNumber;
|
|
119
|
+
/**
|
|
120
|
+
* Get the underlying PathGuard
|
|
121
|
+
*/
|
|
122
|
+
getPathGuard(): PathGuard;
|
|
123
|
+
/**
|
|
124
|
+
* Add a base path for path validation
|
|
125
|
+
*/
|
|
126
|
+
addBasePath(basePath: string): void;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create a CLI validator with RiotPrompt defaults
|
|
130
|
+
*/
|
|
131
|
+
export declare function createRiotPromptValidator(basePaths?: string[]): CLIValidator;
|
|
132
|
+
/**
|
|
133
|
+
* Get the global CLI validator
|
|
134
|
+
*/
|
|
135
|
+
export declare function getCLIValidator(): CLIValidator;
|
|
136
|
+
/**
|
|
137
|
+
* Configure the global CLI validator
|
|
138
|
+
*/
|
|
139
|
+
export declare function configureCLIValidator(config: Partial<CLISecurityConfig>): void;
|
|
140
|
+
/**
|
|
141
|
+
* Reset the global CLI validator
|
|
142
|
+
*/
|
|
143
|
+
export declare function resetCLIValidator(): void;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { PathGuard } from './path-guard.js';
|
|
3
|
+
import { getAuditLogger } from './audit-logger.js';
|
|
4
|
+
|
|
5
|
+
function _define_property(obj, key, value) {
|
|
6
|
+
if (key in obj) {
|
|
7
|
+
Object.defineProperty(obj, key, {
|
|
8
|
+
value: value,
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true
|
|
12
|
+
});
|
|
13
|
+
} else {
|
|
14
|
+
obj[key] = value;
|
|
15
|
+
}
|
|
16
|
+
return obj;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Default CLI security configuration
|
|
20
|
+
*/ const DEFAULT_CLI_SECURITY = {
|
|
21
|
+
enabled: true,
|
|
22
|
+
paths: {
|
|
23
|
+
enabled: true,
|
|
24
|
+
allowAbsolute: false,
|
|
25
|
+
allowSymlinks: false,
|
|
26
|
+
denyPatterns: [
|
|
27
|
+
'\\.\\.',
|
|
28
|
+
'~',
|
|
29
|
+
'\\$\\{',
|
|
30
|
+
'\\$\\('
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
allowedExtensions: [
|
|
34
|
+
'.md',
|
|
35
|
+
'.json',
|
|
36
|
+
'.xml',
|
|
37
|
+
'.yaml',
|
|
38
|
+
'.yml',
|
|
39
|
+
'.txt'
|
|
40
|
+
],
|
|
41
|
+
maxStringLength: 10000,
|
|
42
|
+
allowNullBytes: false,
|
|
43
|
+
allowControlChars: false
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* CLIValidator provides security validation for CLI inputs.
|
|
47
|
+
*
|
|
48
|
+
* Features:
|
|
49
|
+
* - Path validation with traversal prevention
|
|
50
|
+
* - String sanitization
|
|
51
|
+
* - Extension filtering
|
|
52
|
+
* - Audit logging
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const validator = new CLIValidator();
|
|
57
|
+
*
|
|
58
|
+
* // Validate a path argument
|
|
59
|
+
* const pathResult = validator.validatePath('../../../etc/passwd');
|
|
60
|
+
* if (!pathResult.valid) {
|
|
61
|
+
* console.error(pathResult.error);
|
|
62
|
+
* process.exit(1);
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* // Validate a string argument
|
|
66
|
+
* const stringResult = validator.validateString(userInput);
|
|
67
|
+
* ```
|
|
68
|
+
*/ class CLIValidator {
|
|
69
|
+
/**
|
|
70
|
+
* Validate a path argument
|
|
71
|
+
*
|
|
72
|
+
* @param inputPath - The path to validate
|
|
73
|
+
* @param options - Additional validation options
|
|
74
|
+
* @returns Validation result
|
|
75
|
+
*/ validatePath(inputPath, options = {}) {
|
|
76
|
+
if (!this.config.enabled) {
|
|
77
|
+
return {
|
|
78
|
+
valid: true,
|
|
79
|
+
normalizedPath: inputPath
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// First, validate with PathGuard
|
|
83
|
+
const pathResult = this.pathGuard.validate(inputPath, options.operation || 'cli');
|
|
84
|
+
if (!pathResult.valid) {
|
|
85
|
+
return pathResult;
|
|
86
|
+
}
|
|
87
|
+
// Check extension if requested
|
|
88
|
+
if (options.checkExtension && this.config.allowedExtensions.length > 0) {
|
|
89
|
+
const ext = inputPath.toLowerCase().split('.').pop();
|
|
90
|
+
const hasAllowedExt = this.config.allowedExtensions.some((allowed)=>inputPath.toLowerCase().endsWith(allowed));
|
|
91
|
+
if (!hasAllowedExt) {
|
|
92
|
+
this.auditLogger.log({
|
|
93
|
+
type: 'path_traversal_blocked',
|
|
94
|
+
severity: 'warning',
|
|
95
|
+
message: `Invalid file extension: .${ext}`,
|
|
96
|
+
context: {
|
|
97
|
+
attemptedPath: inputPath
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
valid: false,
|
|
102
|
+
error: `Invalid file extension. Allowed: ${this.config.allowedExtensions.join(', ')}`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return pathResult;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validate a string argument
|
|
110
|
+
*
|
|
111
|
+
* @param input - The string to validate
|
|
112
|
+
* @returns Validation result with sanitized string
|
|
113
|
+
*/ validateString(input) {
|
|
114
|
+
if (!this.config.enabled) {
|
|
115
|
+
return {
|
|
116
|
+
valid: true,
|
|
117
|
+
sanitized: input
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Check length
|
|
121
|
+
if (input.length > this.config.maxStringLength) {
|
|
122
|
+
return {
|
|
123
|
+
valid: false,
|
|
124
|
+
error: `String too long (max ${this.config.maxStringLength} characters)`,
|
|
125
|
+
violation: 'length'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Check for null bytes
|
|
129
|
+
if (!this.config.allowNullBytes && input.includes('\0')) {
|
|
130
|
+
this.auditLogger.log({
|
|
131
|
+
type: 'path_validation_failed',
|
|
132
|
+
severity: 'warning',
|
|
133
|
+
message: 'Null byte detected in input'
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
valid: false,
|
|
137
|
+
error: 'Input contains invalid characters (null byte)',
|
|
138
|
+
violation: 'null_byte'
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// Check for control characters (except common whitespace)
|
|
142
|
+
// Note: null bytes are handled separately above
|
|
143
|
+
if (!this.config.allowControlChars) {
|
|
144
|
+
// eslint-disable-next-line no-control-regex
|
|
145
|
+
const controlCharRegex = /[\x01-\x08\x0B\x0C\x0E-\x1F\x7F]/;
|
|
146
|
+
if (controlCharRegex.test(input)) {
|
|
147
|
+
this.auditLogger.log({
|
|
148
|
+
type: 'path_validation_failed',
|
|
149
|
+
severity: 'warning',
|
|
150
|
+
message: 'Control character detected in input'
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
valid: false,
|
|
154
|
+
error: 'Input contains invalid control characters',
|
|
155
|
+
violation: 'control_char'
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
valid: true,
|
|
161
|
+
sanitized: input
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Validate a numeric argument
|
|
166
|
+
*
|
|
167
|
+
* @param input - The number to validate
|
|
168
|
+
* @param options - Validation options
|
|
169
|
+
* @returns Validation result
|
|
170
|
+
*/ validateNumber(input, options = {}) {
|
|
171
|
+
if (!this.config.enabled) {
|
|
172
|
+
return {
|
|
173
|
+
valid: true
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// Check NaN
|
|
177
|
+
if (Number.isNaN(input)) {
|
|
178
|
+
if (!options.allowNaN) {
|
|
179
|
+
return {
|
|
180
|
+
valid: false,
|
|
181
|
+
error: 'Value cannot be NaN'
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// If NaN is allowed, skip other checks since they don't apply
|
|
185
|
+
return {
|
|
186
|
+
valid: true
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// Check Infinity (only for non-NaN values)
|
|
190
|
+
if (!options.allowInfinity && !Number.isFinite(input)) {
|
|
191
|
+
return {
|
|
192
|
+
valid: false,
|
|
193
|
+
error: 'Value cannot be infinite'
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Check integer
|
|
197
|
+
if (options.integer && !Number.isInteger(input)) {
|
|
198
|
+
return {
|
|
199
|
+
valid: false,
|
|
200
|
+
error: 'Value must be an integer'
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// Check min
|
|
204
|
+
if (options.min !== undefined && input < options.min) {
|
|
205
|
+
return {
|
|
206
|
+
valid: false,
|
|
207
|
+
error: `Value must be at least ${options.min}`
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
// Check max
|
|
211
|
+
if (options.max !== undefined && input > options.max) {
|
|
212
|
+
return {
|
|
213
|
+
valid: false,
|
|
214
|
+
error: `Value must be at most ${options.max}`
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
valid: true
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Create a Zod schema for secure path validation
|
|
223
|
+
*/ securePathSchema(options = {}) {
|
|
224
|
+
return z.string().refine((val)=>this.validatePath(val, options).valid, {
|
|
225
|
+
message: 'Invalid path'
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Create a Zod schema for secure string validation
|
|
230
|
+
*/ secureStringSchema() {
|
|
231
|
+
return z.string().refine((val)=>this.validateString(val).valid, {
|
|
232
|
+
message: 'Invalid string'
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Create a Zod schema for secure number validation
|
|
237
|
+
*/ secureNumberSchema(options = {}) {
|
|
238
|
+
return z.number().refine((val)=>this.validateNumber(val, options).valid, {
|
|
239
|
+
message: 'Invalid number'
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get the underlying PathGuard
|
|
244
|
+
*/ getPathGuard() {
|
|
245
|
+
return this.pathGuard;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Add a base path for path validation
|
|
249
|
+
*/ addBasePath(basePath) {
|
|
250
|
+
this.pathGuard.addBasePath(basePath);
|
|
251
|
+
}
|
|
252
|
+
constructor(config = {}){
|
|
253
|
+
_define_property(this, "config", void 0);
|
|
254
|
+
_define_property(this, "pathGuard", void 0);
|
|
255
|
+
_define_property(this, "auditLogger", void 0);
|
|
256
|
+
this.config = {
|
|
257
|
+
...DEFAULT_CLI_SECURITY,
|
|
258
|
+
...config,
|
|
259
|
+
paths: {
|
|
260
|
+
...DEFAULT_CLI_SECURITY.paths,
|
|
261
|
+
...config.paths
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
this.pathGuard = new PathGuard(this.config.paths);
|
|
265
|
+
this.auditLogger = getAuditLogger();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Create a CLI validator with RiotPrompt defaults
|
|
270
|
+
*/ function createRiotPromptValidator(basePaths) {
|
|
271
|
+
const validator = new CLIValidator({
|
|
272
|
+
paths: {
|
|
273
|
+
basePaths: basePaths || [
|
|
274
|
+
process.cwd()
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
return validator;
|
|
279
|
+
}
|
|
280
|
+
// Global instance
|
|
281
|
+
let globalCLIValidator = null;
|
|
282
|
+
/**
|
|
283
|
+
* Get the global CLI validator
|
|
284
|
+
*/ function getCLIValidator() {
|
|
285
|
+
if (!globalCLIValidator) {
|
|
286
|
+
globalCLIValidator = new CLIValidator();
|
|
287
|
+
}
|
|
288
|
+
return globalCLIValidator;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Configure the global CLI validator
|
|
292
|
+
*/ function configureCLIValidator(config) {
|
|
293
|
+
globalCLIValidator = new CLIValidator(config);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Reset the global CLI validator
|
|
297
|
+
*/ function resetCLIValidator() {
|
|
298
|
+
globalCLIValidator = null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export { CLIValidator, DEFAULT_CLI_SECURITY, configureCLIValidator, createRiotPromptValidator, getCLIValidator, resetCLIValidator };
|
|
302
|
+
//# sourceMappingURL=cli-security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-security.js","sources":["../../src/security/cli-security.ts"],"sourcesContent":["/**\n * RiotPrompt - CLI Security\n *\n * Provides security validation for CLI inputs using the existing\n * security infrastructure.\n */\n\nimport { z } from 'zod';\nimport { PathGuard, type PathSecurityConfig } from './path-guard';\nimport { getAuditLogger, SecurityAuditLogger } from './audit-logger';\n\n/**\n * CLI Security configuration\n */\nexport interface CLISecurityConfig {\n /** Enable CLI security validation */\n enabled: boolean;\n /** Path security configuration */\n paths: Partial<PathSecurityConfig>;\n /** Allowed file extensions for input files */\n allowedExtensions: string[];\n /** Maximum string length for inputs */\n maxStringLength: number;\n /** Allow null bytes in strings */\n allowNullBytes: boolean;\n /** Allow control characters in strings */\n allowControlChars: boolean;\n}\n\n/**\n * Default CLI security configuration\n */\nexport const DEFAULT_CLI_SECURITY: CLISecurityConfig = {\n enabled: true,\n paths: {\n enabled: true,\n allowAbsolute: false,\n allowSymlinks: false,\n denyPatterns: [\n '\\\\.\\\\.', // Parent directory\n '~', // Home directory expansion\n '\\\\$\\\\{', // Variable expansion\n '\\\\$\\\\(', // Command substitution\n ],\n },\n allowedExtensions: ['.md', '.json', '.xml', '.yaml', '.yml', '.txt'],\n maxStringLength: 10000,\n allowNullBytes: false,\n allowControlChars: false,\n};\n\n/**\n * String validation result\n */\nexport interface StringValidationResult {\n valid: boolean;\n sanitized?: string;\n error?: string;\n violation?: string;\n}\n\n/**\n * CLIValidator provides security validation for CLI inputs.\n *\n * Features:\n * - Path validation with traversal prevention\n * - String sanitization\n * - Extension filtering\n * - Audit logging\n *\n * @example\n * ```typescript\n * const validator = new CLIValidator();\n *\n * // Validate a path argument\n * const pathResult = validator.validatePath('../../../etc/passwd');\n * if (!pathResult.valid) {\n * console.error(pathResult.error);\n * process.exit(1);\n * }\n *\n * // Validate a string argument\n * const stringResult = validator.validateString(userInput);\n * ```\n */\nexport class CLIValidator {\n private config: CLISecurityConfig;\n private pathGuard: PathGuard;\n private auditLogger: SecurityAuditLogger;\n\n constructor(config: Partial<CLISecurityConfig> = {}) {\n this.config = {\n ...DEFAULT_CLI_SECURITY,\n ...config,\n paths: { ...DEFAULT_CLI_SECURITY.paths, ...config.paths },\n };\n this.pathGuard = new PathGuard(this.config.paths);\n this.auditLogger = getAuditLogger();\n }\n\n /**\n * Validate a path argument\n *\n * @param inputPath - The path to validate\n * @param options - Additional validation options\n * @returns Validation result\n */\n validatePath(inputPath: string, options: {\n checkExtension?: boolean;\n operation?: string;\n } = {}): { valid: boolean; normalizedPath?: string; error?: string } {\n if (!this.config.enabled) {\n return { valid: true, normalizedPath: inputPath };\n }\n\n // First, validate with PathGuard\n const pathResult = this.pathGuard.validate(inputPath, options.operation || 'cli');\n if (!pathResult.valid) {\n return pathResult;\n }\n\n // Check extension if requested\n if (options.checkExtension && this.config.allowedExtensions.length > 0) {\n const ext = inputPath.toLowerCase().split('.').pop();\n const hasAllowedExt = this.config.allowedExtensions.some(\n allowed => inputPath.toLowerCase().endsWith(allowed)\n );\n\n if (!hasAllowedExt) {\n this.auditLogger.log({\n type: 'path_traversal_blocked',\n severity: 'warning',\n message: `Invalid file extension: .${ext}`,\n context: { attemptedPath: inputPath },\n });\n return {\n valid: false,\n error: `Invalid file extension. Allowed: ${this.config.allowedExtensions.join(', ')}`,\n };\n }\n }\n\n return pathResult;\n }\n\n /**\n * Validate a string argument\n *\n * @param input - The string to validate\n * @returns Validation result with sanitized string\n */\n validateString(input: string): StringValidationResult {\n if (!this.config.enabled) {\n return { valid: true, sanitized: input };\n }\n\n // Check length\n if (input.length > this.config.maxStringLength) {\n return {\n valid: false,\n error: `String too long (max ${this.config.maxStringLength} characters)`,\n violation: 'length',\n };\n }\n\n // Check for null bytes\n if (!this.config.allowNullBytes && input.includes('\\0')) {\n this.auditLogger.log({\n type: 'path_validation_failed',\n severity: 'warning',\n message: 'Null byte detected in input',\n });\n return {\n valid: false,\n error: 'Input contains invalid characters (null byte)',\n violation: 'null_byte',\n };\n }\n\n // Check for control characters (except common whitespace)\n // Note: null bytes are handled separately above\n if (!this.config.allowControlChars) {\n // eslint-disable-next-line no-control-regex\n const controlCharRegex = /[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/;\n if (controlCharRegex.test(input)) {\n this.auditLogger.log({\n type: 'path_validation_failed',\n severity: 'warning',\n message: 'Control character detected in input',\n });\n return {\n valid: false,\n error: 'Input contains invalid control characters',\n violation: 'control_char',\n };\n }\n }\n\n return { valid: true, sanitized: input };\n }\n\n /**\n * Validate a numeric argument\n *\n * @param input - The number to validate\n * @param options - Validation options\n * @returns Validation result\n */\n validateNumber(input: number, options: {\n min?: number;\n max?: number;\n integer?: boolean;\n allowNaN?: boolean;\n allowInfinity?: boolean;\n } = {}): { valid: boolean; error?: string } {\n if (!this.config.enabled) {\n return { valid: true };\n }\n\n // Check NaN\n if (Number.isNaN(input)) {\n if (!options.allowNaN) {\n return { valid: false, error: 'Value cannot be NaN' };\n }\n // If NaN is allowed, skip other checks since they don't apply\n return { valid: true };\n }\n\n // Check Infinity (only for non-NaN values)\n if (!options.allowInfinity && !Number.isFinite(input)) {\n return { valid: false, error: 'Value cannot be infinite' };\n }\n\n // Check integer\n if (options.integer && !Number.isInteger(input)) {\n return { valid: false, error: 'Value must be an integer' };\n }\n\n // Check min\n if (options.min !== undefined && input < options.min) {\n return { valid: false, error: `Value must be at least ${options.min}` };\n }\n\n // Check max\n if (options.max !== undefined && input > options.max) {\n return { valid: false, error: `Value must be at most ${options.max}` };\n }\n\n return { valid: true };\n }\n\n /**\n * Create a Zod schema for secure path validation\n */\n securePathSchema(options: {\n checkExtension?: boolean;\n } = {}) {\n return z.string().refine(\n (val: string) => this.validatePath(val, options).valid,\n { message: 'Invalid path' }\n );\n }\n\n /**\n * Create a Zod schema for secure string validation\n */\n secureStringSchema() {\n return z.string().refine(\n (val: string) => this.validateString(val).valid,\n { message: 'Invalid string' }\n );\n }\n\n /**\n * Create a Zod schema for secure number validation\n */\n secureNumberSchema(options: {\n min?: number;\n max?: number;\n integer?: boolean;\n } = {}) {\n return z.number().refine(\n (val: number) => this.validateNumber(val, options).valid,\n { message: 'Invalid number' }\n );\n }\n\n /**\n * Get the underlying PathGuard\n */\n getPathGuard(): PathGuard {\n return this.pathGuard;\n }\n\n /**\n * Add a base path for path validation\n */\n addBasePath(basePath: string): void {\n this.pathGuard.addBasePath(basePath);\n }\n}\n\n/**\n * Create a CLI validator with RiotPrompt defaults\n */\nexport function createRiotPromptValidator(basePaths?: string[]): CLIValidator {\n const validator = new CLIValidator({\n paths: {\n basePaths: basePaths || [process.cwd()],\n },\n });\n return validator;\n}\n\n// Global instance\nlet globalCLIValidator: CLIValidator | null = null;\n\n/**\n * Get the global CLI validator\n */\nexport function getCLIValidator(): CLIValidator {\n if (!globalCLIValidator) {\n globalCLIValidator = new CLIValidator();\n }\n return globalCLIValidator;\n}\n\n/**\n * Configure the global CLI validator\n */\nexport function configureCLIValidator(config: Partial<CLISecurityConfig>): void {\n globalCLIValidator = new CLIValidator(config);\n}\n\n/**\n * Reset the global CLI validator\n */\nexport function resetCLIValidator(): void {\n globalCLIValidator = null;\n}\n\n"],"names":["DEFAULT_CLI_SECURITY","enabled","paths","allowAbsolute","allowSymlinks","denyPatterns","allowedExtensions","maxStringLength","allowNullBytes","allowControlChars","CLIValidator","validatePath","inputPath","options","config","valid","normalizedPath","pathResult","pathGuard","validate","operation","checkExtension","length","ext","toLowerCase","split","pop","hasAllowedExt","some","allowed","endsWith","auditLogger","log","type","severity","message","context","attemptedPath","error","join","validateString","input","sanitized","violation","includes","controlCharRegex","test","validateNumber","Number","isNaN","allowNaN","allowInfinity","isFinite","integer","isInteger","min","undefined","max","securePathSchema","z","string","refine","val","secureStringSchema","secureNumberSchema","number","getPathGuard","addBasePath","basePath","PathGuard","getAuditLogger","createRiotPromptValidator","basePaths","validator","process","cwd","globalCLIValidator","getCLIValidator","configureCLIValidator","resetCLIValidator"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SecurityConfig, PathSecurityConfig, ToolSecurityConfig, SecretSecurityConfig, LogSecurityConfig, TimeoutConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Deep partial type for recursive partial objects
|
|
4
|
+
*/
|
|
5
|
+
export type DeepPartial<T> = {
|
|
6
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* User configuration with all fields optional (including nested)
|
|
10
|
+
*/
|
|
11
|
+
export type UserSecurityConfig = {
|
|
12
|
+
paths?: Partial<PathSecurityConfig>;
|
|
13
|
+
tools?: Partial<ToolSecurityConfig>;
|
|
14
|
+
secrets?: Partial<SecretSecurityConfig>;
|
|
15
|
+
logging?: Partial<LogSecurityConfig>;
|
|
16
|
+
timeouts?: Partial<TimeoutConfig>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Secure default configuration
|
|
20
|
+
* All security features enabled by default
|
|
21
|
+
*/
|
|
22
|
+
export declare const SECURE_DEFAULTS: SecurityConfig;
|
|
23
|
+
/**
|
|
24
|
+
* Permissive configuration for development/testing
|
|
25
|
+
* Security features disabled for convenience
|
|
26
|
+
*/
|
|
27
|
+
export declare const PERMISSIVE_DEFAULTS: SecurityConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Merge user configuration with defaults
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergeSecurityConfig(userConfig: UserSecurityConfig | undefined, defaults?: SecurityConfig): SecurityConfig;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { SecurityConfigSchema } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Secure default configuration
|
|
5
|
+
* All security features enabled by default
|
|
6
|
+
*/ const SECURE_DEFAULTS = SecurityConfigSchema.parse({});
|
|
7
|
+
/**
|
|
8
|
+
* Permissive configuration for development/testing
|
|
9
|
+
* Security features disabled for convenience
|
|
10
|
+
*/ const PERMISSIVE_DEFAULTS = {
|
|
11
|
+
paths: {
|
|
12
|
+
enabled: false,
|
|
13
|
+
basePaths: [],
|
|
14
|
+
allowAbsolute: true,
|
|
15
|
+
allowSymlinks: true,
|
|
16
|
+
denyPatterns: []
|
|
17
|
+
},
|
|
18
|
+
tools: {
|
|
19
|
+
enabled: false,
|
|
20
|
+
validateParams: false,
|
|
21
|
+
sandboxExecution: false,
|
|
22
|
+
maxExecutionTime: 0,
|
|
23
|
+
maxConcurrentCalls: 0,
|
|
24
|
+
deniedTools: []
|
|
25
|
+
},
|
|
26
|
+
secrets: {
|
|
27
|
+
enabled: false,
|
|
28
|
+
redactInLogs: false,
|
|
29
|
+
redactInErrors: false,
|
|
30
|
+
patterns: [],
|
|
31
|
+
customPatterns: []
|
|
32
|
+
},
|
|
33
|
+
logging: {
|
|
34
|
+
enabled: false,
|
|
35
|
+
auditSecurityEvents: false,
|
|
36
|
+
sanitizeStackTraces: false,
|
|
37
|
+
maxContentLength: Number.MAX_SAFE_INTEGER
|
|
38
|
+
},
|
|
39
|
+
timeouts: {
|
|
40
|
+
enabled: false,
|
|
41
|
+
defaultTimeout: 0,
|
|
42
|
+
llmTimeout: 0,
|
|
43
|
+
toolTimeout: 0,
|
|
44
|
+
fileTimeout: 0
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Merge user configuration with defaults
|
|
49
|
+
*/ function mergeSecurityConfig(userConfig, defaults = SECURE_DEFAULTS) {
|
|
50
|
+
if (!userConfig) return defaults;
|
|
51
|
+
// Deep merge each section
|
|
52
|
+
const merged = {
|
|
53
|
+
paths: mergeSection(defaults.paths, userConfig.paths),
|
|
54
|
+
tools: mergeSection(defaults.tools, userConfig.tools),
|
|
55
|
+
secrets: mergeSection(defaults.secrets, userConfig.secrets),
|
|
56
|
+
logging: mergeSection(defaults.logging, userConfig.logging),
|
|
57
|
+
timeouts: mergeSection(defaults.timeouts, userConfig.timeouts)
|
|
58
|
+
};
|
|
59
|
+
return merged;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Helper to merge a single section
|
|
63
|
+
*/ function mergeSection(defaultSection, userSection) {
|
|
64
|
+
if (!userSection) return defaultSection;
|
|
65
|
+
return {
|
|
66
|
+
...defaultSection,
|
|
67
|
+
...userSection
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { PERMISSIVE_DEFAULTS, SECURE_DEFAULTS, mergeSecurityConfig };
|
|
72
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sources":["../../src/security/defaults.ts"],"sourcesContent":["import { \n SecurityConfig, \n SecurityConfigSchema,\n PathSecurityConfig,\n ToolSecurityConfig,\n SecretSecurityConfig,\n LogSecurityConfig,\n TimeoutConfig,\n} from './types';\n\n/**\n * Deep partial type for recursive partial objects\n */\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];\n};\n\n/**\n * User configuration with all fields optional (including nested)\n */\nexport type UserSecurityConfig = {\n paths?: Partial<PathSecurityConfig>;\n tools?: Partial<ToolSecurityConfig>;\n secrets?: Partial<SecretSecurityConfig>;\n logging?: Partial<LogSecurityConfig>;\n timeouts?: Partial<TimeoutConfig>;\n};\n\n/**\n * Secure default configuration\n * All security features enabled by default\n */\nexport const SECURE_DEFAULTS: SecurityConfig = SecurityConfigSchema.parse({});\n\n/**\n * Permissive configuration for development/testing\n * Security features disabled for convenience\n */\nexport const PERMISSIVE_DEFAULTS: SecurityConfig = {\n paths: { \n enabled: false, \n basePaths: [], \n allowAbsolute: true, \n allowSymlinks: true, \n denyPatterns: [] \n },\n tools: { \n enabled: false, \n validateParams: false, \n sandboxExecution: false, \n maxExecutionTime: 0, \n maxConcurrentCalls: 0, \n deniedTools: [] \n },\n secrets: { \n enabled: false, \n redactInLogs: false, \n redactInErrors: false, \n patterns: [], \n customPatterns: [] \n },\n logging: { \n enabled: false, \n auditSecurityEvents: false, \n sanitizeStackTraces: false, \n maxContentLength: Number.MAX_SAFE_INTEGER \n },\n timeouts: { \n enabled: false, \n defaultTimeout: 0, \n llmTimeout: 0, \n toolTimeout: 0, \n fileTimeout: 0 \n },\n};\n\n/**\n * Merge user configuration with defaults\n */\nexport function mergeSecurityConfig(\n userConfig: UserSecurityConfig | undefined,\n defaults: SecurityConfig = SECURE_DEFAULTS\n): SecurityConfig {\n if (!userConfig) return defaults;\n \n // Deep merge each section\n const merged: SecurityConfig = {\n paths: mergeSection(defaults.paths, userConfig.paths),\n tools: mergeSection(defaults.tools, userConfig.tools),\n secrets: mergeSection(defaults.secrets, userConfig.secrets),\n logging: mergeSection(defaults.logging, userConfig.logging),\n timeouts: mergeSection(defaults.timeouts, userConfig.timeouts),\n };\n \n return merged;\n}\n\n/**\n * Helper to merge a single section\n */\nfunction mergeSection<T extends Record<string, unknown>>(\n defaultSection: T,\n userSection: Partial<T> | undefined\n): T {\n if (!userSection) return defaultSection;\n return { ...defaultSection, ...userSection };\n}\n"],"names":["SECURE_DEFAULTS","SecurityConfigSchema","parse","PERMISSIVE_DEFAULTS","paths","enabled","basePaths","allowAbsolute","allowSymlinks","denyPatterns","tools","validateParams","sandboxExecution","maxExecutionTime","maxConcurrentCalls","deniedTools","secrets","redactInLogs","redactInErrors","patterns","customPatterns","logging","auditSecurityEvents","sanitizeStackTraces","maxContentLength","Number","MAX_SAFE_INTEGER","timeouts","defaultTimeout","llmTimeout","toolTimeout","fileTimeout","mergeSecurityConfig","userConfig","defaults","merged","mergeSection","defaultSection","userSection"],"mappings":";;AA4BA;;;AAGC,IACM,MAAMA,eAAAA,GAAkCC,qBAAqBC,KAAK,CAAC,EAAC;AAE3E;;;UAIaC,mBAAAA,GAAsC;IAC/CC,KAAAA,EAAO;QACHC,OAAAA,EAAS,KAAA;AACTC,QAAAA,SAAAA,EAAW,EAAE;QACbC,aAAAA,EAAe,IAAA;QACfC,aAAAA,EAAe,IAAA;AACfC,QAAAA,YAAAA,EAAc;AAClB,KAAA;IACAC,KAAAA,EAAO;QACHL,OAAAA,EAAS,KAAA;QACTM,cAAAA,EAAgB,KAAA;QAChBC,gBAAAA,EAAkB,KAAA;QAClBC,gBAAAA,EAAkB,CAAA;QAClBC,kBAAAA,EAAoB,CAAA;AACpBC,QAAAA,WAAAA,EAAa;AACjB,KAAA;IACAC,OAAAA,EAAS;QACLX,OAAAA,EAAS,KAAA;QACTY,YAAAA,EAAc,KAAA;QACdC,cAAAA,EAAgB,KAAA;AAChBC,QAAAA,QAAAA,EAAU,EAAE;AACZC,QAAAA,cAAAA,EAAgB;AACpB,KAAA;IACAC,OAAAA,EAAS;QACLhB,OAAAA,EAAS,KAAA;QACTiB,mBAAAA,EAAqB,KAAA;QACrBC,mBAAAA,EAAqB,KAAA;AACrBC,QAAAA,gBAAAA,EAAkBC,OAAOC;AAC7B,KAAA;IACAC,QAAAA,EAAU;QACNtB,OAAAA,EAAS,KAAA;QACTuB,cAAAA,EAAgB,CAAA;QAChBC,UAAAA,EAAY,CAAA;QACZC,WAAAA,EAAa,CAAA;QACbC,WAAAA,EAAa;AACjB;AACJ;AAEA;;AAEC,IACM,SAASC,mBAAAA,CACZC,UAA0C,EAC1CC,WAA2BlC,eAAe,EAAA;IAE1C,IAAI,CAACiC,YAAY,OAAOC,QAAAA;;AAGxB,IAAA,MAAMC,MAAAA,GAAyB;AAC3B/B,QAAAA,KAAAA,EAAOgC,YAAAA,CAAaF,QAAAA,CAAS9B,KAAK,EAAE6B,WAAW7B,KAAK,CAAA;AACpDM,QAAAA,KAAAA,EAAO0B,YAAAA,CAAaF,QAAAA,CAASxB,KAAK,EAAEuB,WAAWvB,KAAK,CAAA;AACpDM,QAAAA,OAAAA,EAASoB,YAAAA,CAAaF,QAAAA,CAASlB,OAAO,EAAEiB,WAAWjB,OAAO,CAAA;AAC1DK,QAAAA,OAAAA,EAASe,YAAAA,CAAaF,QAAAA,CAASb,OAAO,EAAEY,WAAWZ,OAAO,CAAA;AAC1DM,QAAAA,QAAAA,EAAUS,YAAAA,CAAaF,QAAAA,CAASP,QAAQ,EAAEM,WAAWN,QAAQ;AACjE,KAAA;IAEA,OAAOQ,MAAAA;AACX;AAEA;;AAEC,IACD,SAASC,YAAAA,CACLC,cAAiB,EACjBC,WAAmC,EAAA;IAEnC,IAAI,CAACA,aAAa,OAAOD,cAAAA;IACzB,OAAO;AAAE,QAAA,GAAGA,cAAc;AAAE,QAAA,GAAGC;AAAY,KAAA;AAC/C;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type SecurityEventType = 'path_validation_failed' | 'path_traversal_blocked' | 'tool_validation_failed' | 'tool_execution_blocked' | 'tool_timeout' | 'secret_redacted' | 'api_key_used' | 'deserialization_failed' | 'regex_timeout' | 'regex_blocked' | 'input_validation_failed' | 'request_timeout' | 'rate_limit_exceeded';
|
|
2
|
+
export interface SecurityEvent {
|
|
3
|
+
type: SecurityEventType;
|
|
4
|
+
timestamp: Date;
|
|
5
|
+
severity: 'info' | 'warning' | 'error' | 'critical';
|
|
6
|
+
message: string;
|
|
7
|
+
context?: Record<string, unknown>;
|
|
8
|
+
}
|