@zenuml/core 3.32.5 → 3.32.7

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.
Files changed (37) hide show
  1. package/.claude/commands/README.md +162 -0
  2. package/.claude/commands/code-review.md +322 -0
  3. package/.claude/commands/create-docs.md +309 -0
  4. package/.claude/commands/full-context.md +121 -0
  5. package/.claude/commands/gemini-consult.md +164 -0
  6. package/.claude/commands/handoff.md +146 -0
  7. package/.claude/commands/refactor.md +188 -0
  8. package/.claude/commands/update-docs.md +314 -0
  9. package/.claude/hooks/README.md +270 -0
  10. package/.claude/hooks/config/sensitive-patterns.json +86 -0
  11. package/.claude/hooks/gemini-context-injector.sh +129 -0
  12. package/.claude/hooks/mcp-security-scan.sh +147 -0
  13. package/.claude/hooks/notify.sh +103 -0
  14. package/.claude/hooks/setup/hook-setup.md +96 -0
  15. package/.claude/hooks/setup/settings.json.template +63 -0
  16. package/.claude/hooks/sounds/complete.wav +0 -0
  17. package/.claude/hooks/sounds/input-needed.wav +0 -0
  18. package/.claude/hooks/subagent-context-injector.sh +65 -0
  19. package/.devcontainer/devcontainer.json +21 -0
  20. package/.storybook/main.ts +25 -0
  21. package/.storybook/preview.ts +29 -0
  22. package/MCP-ASSISTANT-RULES.md +85 -0
  23. package/dist/zenuml.esm.mjs +6461 -6404
  24. package/dist/zenuml.js +73 -73
  25. package/docs/CONTEXT-tier2-component.md +96 -0
  26. package/docs/CONTEXT-tier3-feature.md +162 -0
  27. package/docs/README.md +207 -0
  28. package/docs/ai-context/deployment-infrastructure.md +21 -0
  29. package/docs/ai-context/docs-overview.md +89 -0
  30. package/docs/ai-context/handoff.md +174 -0
  31. package/docs/ai-context/project-structure.md +160 -0
  32. package/docs/ai-context/system-integration.md +21 -0
  33. package/docs/open-issues/example-api-performance-issue.md +79 -0
  34. package/eslint.config.mjs +26 -26
  35. package/package.json +10 -3
  36. package/playwright.config.ts +1 -1
  37. package/tailwind.config.js +0 -4
@@ -0,0 +1,270 @@
1
+ # Claude Code Hooks
2
+
3
+ This directory contains battle-tested hooks that enhance your Claude Code development experience with automated security scanning, intelligent context injection, and pleasant audio feedback.
4
+
5
+ ## Architecture
6
+
7
+ ```
8
+ Claude Code Lifecycle
9
+
10
+ ├── PreToolUse ──────► Security Scanner
11
+ │ ├── Context Injector (Gemini)
12
+ │ └── Context Injector (Subagents)
13
+
14
+ ├── Tool Execution
15
+
16
+ ├── PostToolUse
17
+
18
+ ├── Notification ────────► Audio Feedback
19
+
20
+ └── Stop/SubagentStop ───► Completion Sound
21
+ ```
22
+
23
+ These hooks execute at specific points in Claude Code's lifecycle, providing deterministic control over AI behavior.
24
+
25
+ ## Available Hooks
26
+
27
+ ### 1. Gemini Context Injector (`gemini-context-injector.sh`)
28
+
29
+ **Purpose**: Automatically includes your project documentation and assistant rules when starting new Gemini consultation sessions, ensuring the AI has complete context about your codebase and project standards.
30
+
31
+ **Trigger**: `PreToolUse` for `mcp__gemini__consult_gemini`
32
+
33
+ **Features**:
34
+ - Detects new Gemini consultation sessions (no session_id)
35
+ - Automatically attaches two key files:
36
+ - `docs/ai-context/project-structure.md` - Complete project structure and tech stack
37
+ - `MCP-ASSISTANT-RULES.md` - Project-specific coding standards and guidelines
38
+ - Preserves existing file attachments
39
+ - Session-aware (only injects on new sessions)
40
+ - Logs all injection events for debugging
41
+ - Fails gracefully if either file is missing
42
+ - Handles partial availability (will attach whichever files exist)
43
+
44
+ **Customization**:
45
+ - Copy `docs/MCP-ASSISTANT-RULES.md` template to your project root
46
+ - Customize it with your project-specific standards, principles, and constraints
47
+ - The hook will automatically include it in Gemini consultations
48
+
49
+ ### 2. MCP Security Scanner (`mcp-security-scan.sh`)
50
+
51
+ **Purpose**: Prevents accidental exposure of secrets, API keys, and sensitive data when using MCP servers like Gemini or Context7.
52
+
53
+ **Trigger**: `PreToolUse` for all MCP tools (`mcp__.*`)
54
+
55
+ **Features**:
56
+ - Pattern-based detection for API keys, passwords, and secrets
57
+ - Scans code context, problem descriptions, and attached files
58
+ - File content scanning with size limits
59
+ - Configurable pattern matching via `config/sensitive-patterns.json`
60
+ - Whitelisting for placeholder values
61
+ - Command injection protection for Context7
62
+ - Comprehensive logging of security events to `.claude/logs/`
63
+
64
+ **Customization**: Edit `config/sensitive-patterns.json` to:
65
+ - Add custom API key patterns
66
+ - Modify credential detection rules
67
+ - Update sensitive file patterns
68
+ - Extend the whitelist for your placeholders
69
+
70
+ ### 3. Subagent Context Injector (`subagent-context-injector.sh`)
71
+
72
+ **Purpose**: Automatically includes core project documentation in all sub-agent Task prompts, ensuring consistent context across multi-agent workflows.
73
+
74
+ **Trigger**: `PreToolUse` for `Task` tool
75
+
76
+ **Features**:
77
+ - Intercepts all Task tool calls before execution
78
+ - Prepends references to three core documentation files:
79
+ - `docs/CLAUDE.md` - Project overview, coding standards, AI instructions
80
+ - `docs/ai-context/project-structure.md` - Complete file tree and tech stack
81
+ - `docs/ai-context/docs-overview.md` - Documentation architecture
82
+ - Passes through non-Task tools unchanged
83
+ - Preserves original task prompt by prepending context
84
+ - Enables consistent knowledge across all sub-agents
85
+ - Eliminates need for manual context inclusion in Task prompts
86
+
87
+ **Benefits**:
88
+ - Every sub-agent starts with the same foundational knowledge
89
+ - No manual context specification needed in each Task prompt
90
+ - Token-efficient through @ references instead of content duplication
91
+ - Update context in one place, affects all sub-agents
92
+ - Clean operation with simple pass-through for non-Task tools
93
+
94
+ ### 4. Notification System (`notify.sh`)
95
+
96
+ **Purpose**: Provides pleasant audio feedback when Claude Code needs your attention or completes tasks.
97
+
98
+ **Triggers**:
99
+ - `Notification` events (all notifications including input needed)
100
+ - `Stop` events (main task completion)
101
+
102
+ **Features**:
103
+ - Cross-platform audio support (macOS, Linux, Windows)
104
+ - Non-blocking audio playback (runs in background)
105
+ - Multiple audio playback fallbacks
106
+ - Pleasant notification sounds
107
+ - Two notification types:
108
+ - `input`: When Claude needs user input
109
+ - `complete`: When Claude completes tasks
110
+
111
+ ## Installation
112
+
113
+ 1. **Copy the hooks to your project**:
114
+ ```bash
115
+ cp -r hooks your-project/.claude/
116
+ ```
117
+
118
+ 2. **Configure hooks in your project**:
119
+ ```bash
120
+ cp hooks/setup/settings.json.template your-project/.claude/settings.json
121
+ ```
122
+ Then edit the WORKSPACE path in the settings file.
123
+
124
+ 3. **Test the hooks**:
125
+ ```bash
126
+ # Test notification
127
+ .claude/hooks/notify.sh input
128
+ .claude/hooks/notify.sh complete
129
+
130
+ # View logs
131
+ tail -f .claude/logs/context-injection.log
132
+ tail -f .claude/logs/security-scan.log
133
+ ```
134
+
135
+ ## Hook Configuration
136
+
137
+ Add to your Claude Code `settings.json`:
138
+
139
+ ```json
140
+ {
141
+ "hooks": {
142
+ "PreToolUse": [
143
+ {
144
+ "matcher": "mcp__gemini__consult_gemini",
145
+ "hooks": [
146
+ {
147
+ "type": "command",
148
+ "command": "${WORKSPACE}/.claude/hooks/gemini-context-injector.sh"
149
+ }
150
+ ]
151
+ },
152
+ {
153
+ "matcher": "mcp__.*",
154
+ "hooks": [
155
+ {
156
+ "type": "command",
157
+ "command": "${WORKSPACE}/.claude/hooks/mcp-security-scan.sh"
158
+ }
159
+ ]
160
+ },
161
+ {
162
+ "matcher": "Task",
163
+ "hooks": [
164
+ {
165
+ "type": "command",
166
+ "command": "${WORKSPACE}/.claude/hooks/subagent-context-injector.sh"
167
+ }
168
+ ]
169
+ }
170
+ ],
171
+ "Notification": [
172
+ {
173
+ "matcher": ".*",
174
+ "hooks": [
175
+ {
176
+ "type": "command",
177
+ "command": "${WORKSPACE}/.claude/hooks/notify.sh input"
178
+ }
179
+ ]
180
+ }
181
+ ],
182
+ "Stop": [
183
+ {
184
+ "matcher": ".*",
185
+ "hooks": [
186
+ {
187
+ "type": "command",
188
+ "command": "${WORKSPACE}/.claude/hooks/notify.sh complete"
189
+ }
190
+ ]
191
+ }
192
+ ]
193
+ }
194
+ }
195
+ ```
196
+
197
+ See `hooks/setup/settings.json.template` for the complete configuration including all hooks and MCP servers.
198
+
199
+ ## Security Model
200
+
201
+ 1. **Execution Context**: Hooks run with full user permissions
202
+ 2. **Blocking Behavior**: Exit code 2 blocks tool execution
203
+ 3. **Data Flow**: Hooks can modify tool inputs via JSON transformation
204
+ 4. **Isolation**: Each hook runs in its own process
205
+ 5. **Logging**: All security events logged to `.claude/logs/`
206
+
207
+ ## Integration with MCP Servers
208
+
209
+ The hooks system complements MCP server integrations:
210
+
211
+ - **Gemini Consultation**: Context injector ensures both project structure and MCP assistant rules are included
212
+ - **Context7 Documentation**: Security scanner protects library ID inputs
213
+ - **All MCP Tools**: Universal security scanning before external calls
214
+
215
+ ## Best Practices
216
+
217
+ 1. **Hook Design**:
218
+ - Fail gracefully - never break the main workflow
219
+ - Log important events for debugging
220
+ - Use exit codes appropriately (0=success, 2=block)
221
+ - Keep execution time minimal
222
+
223
+ 2. **Security**:
224
+ - Regularly update sensitive patterns
225
+ - Review security logs periodically
226
+ - Test hooks in safe environments first
227
+ - Never log sensitive data in hooks
228
+
229
+ 3. **Configuration**:
230
+ - Use `${WORKSPACE}` variable for portability
231
+ - Keep hooks executable (`chmod +x`)
232
+ - Version control hook configurations
233
+ - Document custom modifications
234
+
235
+ ## Troubleshooting
236
+
237
+ ### Hooks not executing
238
+ - Check file permissions: `chmod +x *.sh`
239
+ - Verify paths in settings.json
240
+ - Check Claude Code logs for errors
241
+
242
+ ### Security scanner too restrictive
243
+ - Review patterns in `config/sensitive-patterns.json`
244
+ - Add legitimate patterns to the whitelist
245
+ - Check logs for what triggered the block
246
+
247
+ ### No sound playing
248
+ - Verify sound files exist in `sounds/` directory
249
+ - Test audio playback: `.claude/hooks/notify.sh input`
250
+ - Check system audio settings
251
+ - Ensure you have an audio player installed (afplay, paplay, aplay, pw-play, play, ffplay, or PowerShell on Windows)
252
+
253
+ ## Hook Setup Command
254
+
255
+ For comprehensive setup verification and testing, use:
256
+
257
+ ```
258
+ /hook-setup
259
+ ```
260
+
261
+ This command uses multi-agent orchestration to verify installation, check configuration, and run comprehensive tests. See [hook-setup.md](setup/hook-setup.md) for details.
262
+
263
+ ## Extension Points
264
+
265
+ The kit is designed for extensibility:
266
+
267
+ 1. **Custom Hooks**: Add new scripts following the existing patterns
268
+ 2. **Event Handlers**: Configure hooks for any Claude Code event
269
+ 3. **Pattern Updates**: Modify security patterns for your needs
270
+ 4. **Sound Customization**: Replace audio files with your preferences
@@ -0,0 +1,86 @@
1
+ {
2
+ "patterns": {
3
+ "api_keys": [],
4
+ "credentials": [
5
+ "password\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?",
6
+ "passwd\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?",
7
+ "secret\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?",
8
+ "private[_-]?key\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?",
9
+ "access[_-]?key\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?",
10
+ "auth[_-]?token\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?",
11
+ "api[_-]?key\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?",
12
+ "client[_-]?secret\\s*[:=]\\s*[\"']?[^\\s\"']+[\"']?"
13
+ ],
14
+ "sensitive_files": [
15
+ ".env",
16
+ ".env.local",
17
+ ".env.production",
18
+ ".env.development",
19
+ ".env.staging",
20
+ "credentials.json",
21
+ "google-credentials.json",
22
+ "service-account.json",
23
+ "private.key",
24
+ "id_rsa",
25
+ "id_ed25519",
26
+ "id_dsa",
27
+ "id_ecdsa",
28
+ ".pem",
29
+ ".key",
30
+ ".p12",
31
+ ".pfx",
32
+ "keystore",
33
+ ".jks"
34
+ ],
35
+ "regex_patterns": [
36
+ "sk-[a-zA-Z0-9]{32,}",
37
+ "sk-proj-[a-zA-Z0-9]{32,}",
38
+ "AIza[0-9A-Za-z\\-_]{35}",
39
+ "gsk_[a-zA-Z0-9]{32,}",
40
+ "AKIA[0-9A-Z]{16}",
41
+ "aws_secret_access_key\\s*=\\s*[a-zA-Z0-9/+=]{40}",
42
+ "(postgres|postgresql|mysql|mongodb|redis)://[^:]+:[^@]+@[^/]+",
43
+ "-----BEGIN.*(RSA|DSA|EC|OPENSSH|PGP).*PRIVATE KEY-----",
44
+ "Bearer\\s+[a-zA-Z0-9\\-_]+\\.[a-zA-Z0-9\\-_]+\\.[a-zA-Z0-9\\-_]+",
45
+ "[A-Z_]+(KEY|TOKEN|SECRET|PASSWORD|PASSWD)\\s*=\\s*[\"']?[^\\s\"']+[\"']?",
46
+ "(api[_-]?key|access[_-]?token|auth[_-]?token)\\s*[:=]\\s*[\"']?[a-zA-Z0-9_\\-]{20,}[\"']?",
47
+ "(password|secret|key)\\s*[:=]\\s*[\"']?[A-Za-z0-9+/]{40,}={0,2}[\"']?",
48
+ "ghp_[a-zA-Z0-9]{36}",
49
+ "gho_[a-zA-Z0-9]{36}",
50
+ "github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}",
51
+ "glpat-[a-zA-Z0-9\\-_]{20}",
52
+ "xoxb-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24}",
53
+ "sq0atp-[0-9A-Za-z\\-_]{22}",
54
+ "sq0csp-[0-9A-Za-z\\-_]{43}",
55
+ "SK[a-z0-9]{32}"
56
+ ]
57
+ },
58
+ "whitelist": {
59
+ "allowed_mentions": [
60
+ "GOOGLE_API_KEY=your_google_api_key_here",
61
+ "GROQ_API_KEY=your_groq_api_key_here",
62
+ "OPENAI_API_KEY=your_openai_api_key_here",
63
+ "GEMINI_API_KEY=your_gemini_api_key_here",
64
+ "AWS_ACCESS_KEY_ID=your_access_key_here",
65
+ "api_key=settings.api_key",
66
+ "api_key=process.env.API_KEY",
67
+ "api_key=YOUR_API_KEY",
68
+ "password=your_password_here",
69
+ "password=<your_password>",
70
+ "password=${PASSWORD}",
71
+ "token=your_token_here",
72
+ "token=<auth_token>",
73
+ "secret=your_secret_here",
74
+ "Bearer YOUR_TOKEN_HERE",
75
+ "Bearer <token>",
76
+ "postgres://user:password@localhost",
77
+ "mysql://root:password@localhost",
78
+ "mongodb://user:password@localhost",
79
+ "redis://user:password@localhost",
80
+ "connection_string = \"your_connection_string_here\"",
81
+ "API_KEY=<your_api_key>",
82
+ "SECRET_KEY=<your_secret_key>",
83
+ "DATABASE_URL=<your_database_url>"
84
+ ]
85
+ }
86
+ }
@@ -0,0 +1,129 @@
1
+ #!/bin/bash
2
+ # Gemini Context Injector Hook
3
+ # Automatically adds project context files to new Gemini consultation sessions:
4
+ # - docs/ai-context/project-structure.md
5
+ # - MCP-ASSISTANT-RULES.md
6
+ #
7
+ # This hook enhances Gemini consultations by automatically including your project's
8
+ # structure documentation and assistant rules, ensuring the AI has complete context.
9
+
10
+ set -euo pipefail
11
+
12
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
14
+ PROJECT_STRUCTURE_FILE="$PROJECT_ROOT/docs/ai-context/project-structure.md"
15
+ MCP_RULES_FILE="$PROJECT_ROOT/MCP-ASSISTANT-RULES.md"
16
+ LOG_FILE="$SCRIPT_DIR/../logs/context-injection.log"
17
+
18
+ # Ensure log directory exists
19
+ mkdir -p "$(dirname "$LOG_FILE")"
20
+
21
+ # Read input from stdin
22
+ INPUT_JSON=$(cat)
23
+
24
+ # Function to log injection events
25
+ log_injection_event() {
26
+ local event_type="$1"
27
+ local details="$2"
28
+ local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
29
+ echo "{\"timestamp\": \"$timestamp\", \"event\": \"$event_type\", \"details\": \"$details\"}" >> "$LOG_FILE"
30
+ }
31
+
32
+ # Main logic
33
+ main() {
34
+ # Extract tool information from stdin
35
+ local tool_name=$(echo "$INPUT_JSON" | jq -r '.tool_name // ""')
36
+
37
+ # Only process Gemini consultation requests
38
+ if [[ "$tool_name" != "mcp__gemini__consult_gemini" ]]; then
39
+ echo '{"continue": true}'
40
+ exit 0
41
+ fi
42
+
43
+ # Extract tool arguments
44
+ local tool_args=$(echo "$INPUT_JSON" | jq -r '.tool_input // "{}"')
45
+
46
+ # Check if this is a new session (no session_id provided)
47
+ local session_id=$(echo "$tool_args" | jq -r '.session_id // ""' 2>/dev/null || echo "")
48
+
49
+ if [[ -z "$session_id" || "$session_id" == "null" ]]; then
50
+ log_injection_event "new_session_detected" "preparing_context_injection"
51
+
52
+ # Check if required files exist
53
+ local missing_files=""
54
+ if [[ ! -f "$PROJECT_STRUCTURE_FILE" ]]; then
55
+ missing_files="$missing_files project_structure.md"
56
+ fi
57
+ if [[ ! -f "$MCP_RULES_FILE" ]]; then
58
+ missing_files="$missing_files MCP-ASSISTANT-RULES.md"
59
+ fi
60
+
61
+ # If either file is missing, log warning but continue
62
+ if [[ -n "$missing_files" ]]; then
63
+ log_injection_event "warning" "missing_files:$missing_files"
64
+ fi
65
+
66
+ # If both files are missing, exit early
67
+ if [[ ! -f "$PROJECT_STRUCTURE_FILE" ]] && [[ ! -f "$MCP_RULES_FILE" ]]; then
68
+ echo '{"continue": true}'
69
+ exit 0
70
+ fi
71
+
72
+ # Extract current attached_files if any
73
+ local current_files=$(echo "$tool_args" | jq -c '.attached_files // []' 2>/dev/null || echo "[]")
74
+
75
+ # Check if files are already included
76
+ local has_project_structure=$(echo "$current_files" | jq -e ".[] | select(. == \"$PROJECT_STRUCTURE_FILE\")" > /dev/null 2>&1 && echo "true" || echo "false")
77
+ local has_mcp_rules=$(echo "$current_files" | jq -e ".[] | select(. == \"$MCP_RULES_FILE\")" > /dev/null 2>&1 && echo "true" || echo "false")
78
+
79
+ # If both files exist and are already included, skip
80
+ if [[ -f "$PROJECT_STRUCTURE_FILE" ]] && [[ "$has_project_structure" == "true" ]] && \
81
+ [[ -f "$MCP_RULES_FILE" ]] && [[ "$has_mcp_rules" == "true" ]]; then
82
+ log_injection_event "skipped" "all_required_files_already_included"
83
+ echo '{"continue": true}'
84
+ exit 0
85
+ fi
86
+
87
+ # Add missing files to attached_files
88
+ local modified_args="$tool_args"
89
+ local files_added=""
90
+
91
+ if [[ -f "$PROJECT_STRUCTURE_FILE" ]] && [[ "$has_project_structure" == "false" ]]; then
92
+ modified_args=$(echo "$modified_args" | jq --arg file "$PROJECT_STRUCTURE_FILE" '
93
+ .attached_files = ((.attached_files // []) + [$file])
94
+ ' 2>/dev/null)
95
+ files_added="$files_added project_structure.md"
96
+ fi
97
+
98
+ if [[ -f "$MCP_RULES_FILE" ]] && [[ "$has_mcp_rules" == "false" ]]; then
99
+ modified_args=$(echo "$modified_args" | jq --arg file "$MCP_RULES_FILE" '
100
+ .attached_files = ((.attached_files // []) + [$file])
101
+ ' 2>/dev/null)
102
+ files_added="$files_added MCP-ASSISTANT-RULES.md"
103
+ fi
104
+
105
+ if [[ -n "$modified_args" ]] && [[ "$modified_args" != "$tool_args" ]]; then
106
+ log_injection_event "context_injected" "added_files:$files_added"
107
+
108
+ # Update the input JSON with modified tool_input
109
+ local output_json=$(echo "$INPUT_JSON" | jq --argjson new_args "$modified_args" '.tool_input = $new_args')
110
+
111
+ # Return the modified input to stdout
112
+ echo "$output_json"
113
+ exit 0
114
+ else
115
+ log_injection_event "error" "failed_to_modify_arguments"
116
+ # Continue without modification on error
117
+ echo '{"continue": true}'
118
+ exit 0
119
+ fi
120
+ else
121
+ log_injection_event "existing_session" "session_id:$session_id"
122
+ # For existing sessions, continue without modification
123
+ echo '{"continue": true}'
124
+ exit 0
125
+ fi
126
+ }
127
+
128
+ # Run main function
129
+ main
@@ -0,0 +1,147 @@
1
+ #!/bin/bash
2
+ # MCP Security Scanner Hook
3
+ # Scans MCP requests for sensitive data before sending to external services
4
+ #
5
+ # This hook protects against accidental exposure of secrets, API keys, and other
6
+ # sensitive information when using MCP servers like Gemini or Context7.
7
+
8
+ set -euo pipefail
9
+
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ PATTERNS_FILE="$SCRIPT_DIR/config/sensitive-patterns.json"
12
+ LOG_FILE="$SCRIPT_DIR/../logs/security-scan.log"
13
+
14
+ # Ensure log directory exists
15
+ mkdir -p "$(dirname "$LOG_FILE")"
16
+
17
+ # Read input from stdin
18
+ INPUT_JSON=$(cat)
19
+
20
+ # Function to log security events
21
+ log_security_event() {
22
+ local event_type="$1"
23
+ local details="$2"
24
+ local tool_name="${3:-unknown}"
25
+ local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
26
+ echo "{\"timestamp\": \"$timestamp\", \"tool\": \"$tool_name\", \"event\": \"$event_type\", \"details\": \"$details\"}" >> "$LOG_FILE"
27
+ }
28
+
29
+ # Function to check if content matches sensitive patterns
30
+ check_sensitive_content() {
31
+ local content="$1"
32
+ local pattern_type="$2"
33
+
34
+ # Get patterns from JSON config
35
+ local patterns=$(jq -r ".patterns.$pattern_type[]" "$PATTERNS_FILE" 2>/dev/null || echo "")
36
+
37
+ for pattern in $patterns; do
38
+ if echo "$content" | grep -qiE "$pattern"; then
39
+ # Check whitelist
40
+ local whitelisted=false
41
+ local whitelist_patterns=$(jq -r '.whitelist.allowed_mentions[]' "$PATTERNS_FILE" 2>/dev/null || echo "")
42
+
43
+ for whitelist in $whitelist_patterns; do
44
+ if echo "$content" | grep -qF "$whitelist"; then
45
+ whitelisted=true
46
+ break
47
+ fi
48
+ done
49
+
50
+ if [[ "$whitelisted" == "false" ]]; then
51
+ return 0 # Found sensitive data
52
+ fi
53
+ fi
54
+ done
55
+
56
+ return 1 # No sensitive data found
57
+ }
58
+
59
+ # Function to scan file content
60
+ scan_file_content() {
61
+ local file_path="$1"
62
+
63
+ # Check if file name itself is sensitive
64
+ local filename=$(basename "$file_path")
65
+ if check_sensitive_content "$filename" "sensitive_files"; then
66
+ return 0 # Sensitive file
67
+ fi
68
+
69
+ # Don't scan files that don't exist or are too large
70
+ if [[ ! -f "$file_path" ]] || [[ $(stat -f%z "$file_path" 2>/dev/null || stat -c%s "$file_path" 2>/dev/null || echo "999999999") -gt 1048576 ]]; then
71
+ return 1
72
+ fi
73
+
74
+ # Read and scan file content
75
+ local content=$(cat "$file_path" 2>/dev/null || echo "")
76
+
77
+ # Check all pattern types
78
+ for pattern_type in api_keys credentials regex_patterns; do
79
+ if check_sensitive_content "$content" "$pattern_type"; then
80
+ return 0 # Found sensitive data
81
+ fi
82
+ done
83
+
84
+ return 1
85
+ }
86
+
87
+ # Main scanning logic
88
+ main() {
89
+ # Extract tool information from stdin
90
+ local tool_name=$(echo "$INPUT_JSON" | jq -r '.tool_name // ""')
91
+ local tool_args=$(echo "$INPUT_JSON" | jq -r '.tool_input // "{}"')
92
+
93
+ log_security_event "scan_started" "$tool_name" "$tool_name"
94
+
95
+ # Check code_context for sensitive data
96
+ local code_context=$(echo "$tool_args" | jq -r '.code_context // ""' 2>/dev/null || echo "")
97
+ if [[ -n "$code_context" ]]; then
98
+ for pattern_type in api_keys credentials regex_patterns; do
99
+ if check_sensitive_content "$code_context" "$pattern_type"; then
100
+ log_security_event "blocked" "sensitive_data_in_code_context" "$tool_name"
101
+ echo '{"decision": "block", "reason": "Security Alert: Detected sensitive data in code_context. Found patterns matching actual credentials (API keys, passwords, or secrets with values). For discussions about security topics, use placeholders like YOUR_API_KEY, <password>, or example values instead of real credentials."}'
102
+ exit 2
103
+ fi
104
+ done
105
+ fi
106
+
107
+ # Check problem_description for sensitive data
108
+ local problem_desc=$(echo "$tool_args" | jq -r '.problem_description // ""' 2>/dev/null || echo "")
109
+ if [[ -n "$problem_desc" ]]; then
110
+ for pattern_type in api_keys credentials regex_patterns; do
111
+ if check_sensitive_content "$problem_desc" "$pattern_type"; then
112
+ log_security_event "blocked" "sensitive_data_in_problem_description" "$tool_name"
113
+ echo '{"decision": "block", "reason": "Security Alert: Detected sensitive data in problem description. Found patterns matching actual credentials (API keys, passwords, connection strings, or tokens with values). For security discussions, use placeholders: YOUR_API_KEY, <password>, postgres://user:password@localhost, or example-token-here."}'
114
+ exit 2
115
+ fi
116
+ done
117
+ fi
118
+
119
+ # Check attached files
120
+ local attached_files=$(echo "$tool_args" | jq -r '.attached_files[]?' 2>/dev/null || echo "")
121
+ for file in $attached_files; do
122
+ if scan_file_content "$file"; then
123
+ log_security_event "blocked" "sensitive_file_attached:$file" "$tool_name"
124
+ echo "{\"decision\": \"block\", \"reason\": \"Security Alert: Detected sensitive content in attached file $file. Found credentials, private keys, or environment files. Remove actual secrets and use placeholders like YOUR_SECRET_HERE or example values for demonstrations.\"}"
125
+ exit 2
126
+ fi
127
+ done
128
+
129
+ # Check specific question for Context7
130
+ if [[ "$tool_name" == "mcp__context7__get-library-docs" ]]; then
131
+ local library_id=$(echo "$tool_args" | jq -r '.context7CompatibleLibraryID // ""' 2>/dev/null || echo "")
132
+ # Basic check to prevent injection attacks
133
+ if echo "$library_id" | grep -qE '(\$|`|;|&&|\|\||>|<)'; then
134
+ log_security_event "blocked" "suspicious_library_id" "$tool_name"
135
+ echo '{"decision": "block", "reason": "Security Alert: Detected suspicious characters in library ID that could indicate command injection. Please use only alphanumeric characters, hyphens, underscores, and forward slashes."}'
136
+ exit 2
137
+ fi
138
+ fi
139
+
140
+ log_security_event "scan_completed" "no_sensitive_data_found" "$tool_name"
141
+
142
+ # All checks passed, allow the tool to continue
143
+ # No output needed when allowing - just exit 0
144
+ }
145
+
146
+ # Run main function
147
+ main