@paulduvall/claude-dev-toolkit 0.0.1-alpha.2 → 0.0.1-alpha.21
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/LICENSE +21 -0
- package/README.md +88 -37
- package/bin/claude-commands +307 -65
- package/commands/active/xarchitecture.md +393 -0
- package/commands/active/xconfig.md +127 -0
- package/commands/active/xcontinue.md +92 -0
- package/commands/active/xdebug.md +130 -0
- package/commands/active/xdocs.md +178 -0
- package/commands/active/xexplore.md +94 -0
- package/commands/active/xgit.md +149 -0
- package/commands/active/xpipeline.md +152 -0
- package/commands/active/xquality.md +96 -0
- package/commands/active/xrefactor.md +198 -0
- package/commands/active/xrelease.md +142 -0
- package/commands/active/xsecurity.md +92 -0
- package/commands/active/xspec.md +174 -0
- package/commands/active/xtdd.md +151 -0
- package/commands/active/xtest.md +89 -0
- package/commands/active/xverify.md +80 -0
- package/commands/experiments/xact.md +742 -0
- package/commands/experiments/xanalytics.md +113 -0
- package/commands/experiments/xanalyze.md +70 -0
- package/commands/experiments/xapi.md +161 -0
- package/commands/experiments/xatomic.md +112 -0
- package/commands/experiments/xaws.md +85 -0
- package/commands/experiments/xcicd.md +337 -0
- package/commands/experiments/xcommit.md +122 -0
- package/commands/experiments/xcompliance.md +182 -0
- package/commands/experiments/xconstraints.md +89 -0
- package/commands/experiments/xcoverage.md +90 -0
- package/commands/experiments/xdb.md +102 -0
- package/commands/experiments/xdesign.md +121 -0
- package/commands/experiments/xdevcontainer.md +238 -0
- package/commands/experiments/xevaluate.md +111 -0
- package/commands/experiments/xfootnote.md +12 -0
- package/commands/experiments/xgenerate.md +117 -0
- package/commands/experiments/xgovernance.md +149 -0
- package/commands/experiments/xgreen.md +66 -0
- package/commands/experiments/xiac.md +118 -0
- package/commands/experiments/xincident.md +137 -0
- package/commands/experiments/xinfra.md +115 -0
- package/commands/experiments/xknowledge.md +115 -0
- package/commands/experiments/xmaturity.md +120 -0
- package/commands/experiments/xmetrics.md +118 -0
- package/commands/experiments/xmonitoring.md +128 -0
- package/commands/experiments/xnew.md +903 -0
- package/commands/experiments/xobservable.md +114 -0
- package/commands/experiments/xoidc.md +165 -0
- package/commands/experiments/xoptimize.md +115 -0
- package/commands/experiments/xperformance.md +112 -0
- package/commands/experiments/xplanning.md +131 -0
- package/commands/experiments/xpolicy.md +115 -0
- package/commands/experiments/xproduct.md +98 -0
- package/commands/experiments/xreadiness.md +75 -0
- package/commands/experiments/xred.md +55 -0
- package/commands/experiments/xrisk.md +128 -0
- package/commands/experiments/xrules.md +124 -0
- package/commands/experiments/xsandbox.md +120 -0
- package/commands/experiments/xscan.md +102 -0
- package/commands/experiments/xsetup.md +123 -0
- package/commands/experiments/xtemplate.md +116 -0
- package/commands/experiments/xtrace.md +212 -0
- package/commands/experiments/xux.md +171 -0
- package/commands/experiments/xvalidate.md +104 -0
- package/commands/experiments/xworkflow.md +113 -0
- package/hooks/.smellrc.example.json +19 -0
- package/hooks/README.md +263 -0
- package/hooks/check-commit-signing.py +127 -0
- package/hooks/check-complexity.py +38 -0
- package/hooks/check-security.py +37 -0
- package/hooks/claude-wrapper.sh +29 -0
- package/hooks/config.py +110 -0
- package/hooks/file-logger.sh +100 -0
- package/hooks/lib/argument-parser.sh +427 -0
- package/hooks/lib/config-constants.sh +230 -0
- package/hooks/lib/context-manager.sh +560 -0
- package/hooks/lib/error-handler.sh +423 -0
- package/hooks/lib/execution-engine.sh +444 -0
- package/hooks/lib/execution-results.sh +113 -0
- package/hooks/lib/execution-simulation.sh +114 -0
- package/hooks/lib/field-validators.sh +104 -0
- package/hooks/lib/file-utils.sh +398 -0
- package/hooks/lib/subagent-discovery.sh +468 -0
- package/hooks/lib/subagent-validator.sh +407 -0
- package/hooks/lib/validation-reporter.sh +134 -0
- package/hooks/on-error-debug.sh +226 -0
- package/hooks/pre-commit-quality.sh +204 -0
- package/hooks/pre-commit-test-runner.sh +132 -0
- package/hooks/pre-write-security.sh +115 -0
- package/hooks/prevent-credential-exposure.sh +279 -0
- package/hooks/security_bandit.py +177 -0
- package/hooks/security_checks.py +97 -0
- package/hooks/security_secrets.py +81 -0
- package/hooks/security_trojan.py +61 -0
- package/hooks/settings.example.json +52 -0
- package/hooks/smell_checks.py +238 -0
- package/hooks/smell_javascript.py +231 -0
- package/hooks/smell_python.py +110 -0
- package/hooks/smell_ruff.py +70 -0
- package/hooks/smell_types.py +72 -0
- package/hooks/subagent-trigger-simple.sh +202 -0
- package/hooks/subagent-trigger.sh +253 -0
- package/hooks/suppression.py +82 -0
- package/hooks/tab-color.sh +70 -0
- package/hooks/verify-before-edit.sh +135 -0
- package/lib/backup-restore-command.js +140 -0
- package/lib/base/base-command.js +252 -0
- package/lib/base/command-result.js +184 -0
- package/lib/config/constants.js +255 -0
- package/lib/config.js +48 -6
- package/lib/configure-command.js +428 -0
- package/lib/dependency-validator.js +64 -5
- package/lib/hook-installer-core.js +2 -2
- package/lib/installation-instruction-generator.js +213 -495
- package/lib/installer.js +134 -56
- package/lib/oidc-command.js +740 -0
- package/lib/services/backup-list-service.js +226 -0
- package/lib/services/backup-service.js +230 -0
- package/lib/services/command-installer-service.js +217 -0
- package/lib/services/logger-service.js +201 -0
- package/lib/services/package-manager-service.js +319 -0
- package/lib/services/platform-instruction-service.js +294 -0
- package/lib/services/recovery-instruction-service.js +348 -0
- package/lib/services/restore-service.js +221 -0
- package/lib/setup-command.js +359 -0
- package/lib/setup-wizard.js +155 -262
- package/lib/uninstall-command.js +100 -0
- package/lib/utils/claude-path-config.js +184 -0
- package/lib/utils/file-system-utils.js +152 -0
- package/lib/utils.js +8 -4
- package/lib/verify-command.js +430 -0
- package/package.json +7 -3
- package/scripts/postinstall.js +172 -157
- package/subagents/debug-specialist.md +7 -0
- package/templates/README.md +115 -0
- package/templates/basic-settings.json +30 -0
- package/templates/comprehensive-settings.json +57 -0
- package/templates/global-claude.md +344 -0
- package/templates/hybrid-hook-config.yaml +132 -0
- package/templates/security-focused-settings.json +62 -0
- package/templates/subagent-hooks.yaml +188 -0
- package/lib/package-manager-service.js +0 -270
- package/subagents/debug-context.md +0 -197
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# Subagent Validator Module for Subagent-Hook Integration
|
|
5
|
+
#
|
|
6
|
+
# This module provides comprehensive validation functionality for subagents,
|
|
7
|
+
# including format validation, content validation, and security checks.
|
|
8
|
+
|
|
9
|
+
# Include guard
|
|
10
|
+
[[ -n "${_SUBAGENT_VALIDATOR_LOADED:-}" ]] && return 0
|
|
11
|
+
_SUBAGENT_VALIDATOR_LOADED=1
|
|
12
|
+
|
|
13
|
+
# Source required modules
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
source "$SCRIPT_DIR/config-constants.sh"
|
|
16
|
+
source "$SCRIPT_DIR/file-utils.sh"
|
|
17
|
+
source "$SCRIPT_DIR/error-handler.sh"
|
|
18
|
+
source "$SCRIPT_DIR/field-validators.sh"
|
|
19
|
+
source "$SCRIPT_DIR/validation-reporter.sh"
|
|
20
|
+
|
|
21
|
+
##################################
|
|
22
|
+
# Basic Validation Functions
|
|
23
|
+
##################################
|
|
24
|
+
|
|
25
|
+
validate_subagent_file() {
|
|
26
|
+
local subagent_file="$1"
|
|
27
|
+
local validation_mode="${2:-strict}"
|
|
28
|
+
|
|
29
|
+
if [[ -z "$subagent_file" ]]; then
|
|
30
|
+
log_error "Subagent file path is required"
|
|
31
|
+
return $EXIT_VALIDATION_FAILED
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
log_debug "Validating subagent file: $subagent_file (mode: $validation_mode)"
|
|
35
|
+
|
|
36
|
+
# Basic file validation
|
|
37
|
+
if ! validate_file_existence "$subagent_file"; then
|
|
38
|
+
return $EXIT_VALIDATION_FAILED
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
if ! validate_file_security "$subagent_file"; then
|
|
42
|
+
return $EXIT_SECURITY_VIOLATION
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if ! validate_file_format "$subagent_file"; then
|
|
46
|
+
return $EXIT_VALIDATION_FAILED
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if ! validate_yaml_frontmatter "$subagent_file"; then
|
|
50
|
+
return $EXIT_VALIDATION_FAILED
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if [[ "$validation_mode" == "strict" ]]; then
|
|
54
|
+
if ! validate_subagent_content "$subagent_file"; then
|
|
55
|
+
return $EXIT_VALIDATION_FAILED
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if ! validate_subagent_metadata "$subagent_file"; then
|
|
59
|
+
return $EXIT_VALIDATION_FAILED
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
log_debug "Subagent file validation passed: $subagent_file"
|
|
64
|
+
return $EXIT_SUCCESS
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
validate_file_existence() {
|
|
68
|
+
local file_path="$1"
|
|
69
|
+
|
|
70
|
+
if [[ ! -f "$file_path" ]]; then
|
|
71
|
+
handle_missing_subagent "$(basename "$file_path" "$SUBAGENT_FILE_EXTENSION")"
|
|
72
|
+
return $EXIT_SUBAGENT_NOT_FOUND
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if [[ ! -r "$file_path" ]]; then
|
|
76
|
+
log_error "Subagent file not readable: $file_path"
|
|
77
|
+
return $EXIT_VALIDATION_FAILED
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
return $EXIT_SUCCESS
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
validate_file_security() {
|
|
84
|
+
local file_path="$1"
|
|
85
|
+
|
|
86
|
+
# Validate file permissions
|
|
87
|
+
if ! validate_file_permissions "$file_path"; then
|
|
88
|
+
handle_security_violation "insecure_file_permissions" \
|
|
89
|
+
"File has insecure permissions" "$file_path"
|
|
90
|
+
return $EXIT_SECURITY_VIOLATION
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# Validate path safety
|
|
94
|
+
if ! validate_path_safety "$file_path"; then
|
|
95
|
+
handle_security_violation "unsafe_file_path" \
|
|
96
|
+
"File path contains unsafe elements" "$file_path"
|
|
97
|
+
return $EXIT_SECURITY_VIOLATION
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
return $EXIT_SUCCESS
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
validate_file_format() {
|
|
104
|
+
local file_path="$1"
|
|
105
|
+
|
|
106
|
+
# Check file extension
|
|
107
|
+
if ! file_has_extension "$file_path" "$SUBAGENT_FILE_EXTENSION"; then
|
|
108
|
+
log_error "Invalid file extension: $file_path (expected: $SUBAGENT_FILE_EXTENSION)"
|
|
109
|
+
return $EXIT_VALIDATION_FAILED
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# Check file size
|
|
113
|
+
local file_content
|
|
114
|
+
if ! file_content=$(read_file_with_size_limit "$file_path"); then
|
|
115
|
+
log_error "File too large or unreadable: $file_path"
|
|
116
|
+
return $EXIT_VALIDATION_FAILED
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# Check if file appears to be binary
|
|
120
|
+
if file "$file_path" 2>/dev/null | grep -q "binary"; then
|
|
121
|
+
log_error "File appears to be binary: $file_path"
|
|
122
|
+
return $EXIT_VALIDATION_FAILED
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
return $EXIT_SUCCESS
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
##################################
|
|
129
|
+
# YAML Frontmatter Validation
|
|
130
|
+
##################################
|
|
131
|
+
|
|
132
|
+
validate_yaml_frontmatter() {
|
|
133
|
+
local file_path="$1"
|
|
134
|
+
|
|
135
|
+
local content
|
|
136
|
+
if ! content=$(read_file_safely "$file_path"); then
|
|
137
|
+
log_error "Failed to read file for frontmatter validation: $file_path"
|
|
138
|
+
return $EXIT_VALIDATION_FAILED
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Check for YAML frontmatter start
|
|
142
|
+
if ! echo "$content" | head -1 | grep -q "$YAML_FRONTMATTER_START"; then
|
|
143
|
+
log_error "Missing YAML frontmatter start marker in: $file_path"
|
|
144
|
+
return $EXIT_VALIDATION_FAILED
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# Find frontmatter end
|
|
148
|
+
local frontmatter_end_found=false
|
|
149
|
+
local line_count=0
|
|
150
|
+
|
|
151
|
+
while IFS= read -r line; do
|
|
152
|
+
((line_count++))
|
|
153
|
+
|
|
154
|
+
# Skip first line (start marker)
|
|
155
|
+
if [[ $line_count -eq 1 ]]; then
|
|
156
|
+
continue
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
if [[ "$line" == "---" ]]; then
|
|
160
|
+
frontmatter_end_found=true
|
|
161
|
+
break
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# Prevent infinite search
|
|
165
|
+
if [[ $line_count -gt 100 ]]; then
|
|
166
|
+
break
|
|
167
|
+
fi
|
|
168
|
+
done <<< "$content"
|
|
169
|
+
|
|
170
|
+
if [[ "$frontmatter_end_found" != true ]]; then
|
|
171
|
+
log_error "Missing YAML frontmatter end marker in: $file_path"
|
|
172
|
+
return $EXIT_VALIDATION_FAILED
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
log_debug "YAML frontmatter structure valid: $file_path"
|
|
176
|
+
return $EXIT_SUCCESS
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
extract_frontmatter_field() {
|
|
180
|
+
local file_path="$1"
|
|
181
|
+
local field_name="$2"
|
|
182
|
+
local required="${3:-false}"
|
|
183
|
+
|
|
184
|
+
if [[ -z "$file_path" ]] || [[ -z "$field_name" ]]; then
|
|
185
|
+
log_error "File path and field name are required"
|
|
186
|
+
return $EXIT_VALIDATION_FAILED
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
local content
|
|
190
|
+
if ! content=$(read_file_safely "$file_path"); then
|
|
191
|
+
log_error "Failed to read file: $file_path"
|
|
192
|
+
return $EXIT_VALIDATION_FAILED
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
local in_frontmatter=false
|
|
196
|
+
local field_value=""
|
|
197
|
+
|
|
198
|
+
while IFS= read -r line; do
|
|
199
|
+
if [[ "$line" == "---" ]]; then
|
|
200
|
+
if [[ "$in_frontmatter" == true ]]; then
|
|
201
|
+
break # End of frontmatter
|
|
202
|
+
else
|
|
203
|
+
in_frontmatter=true
|
|
204
|
+
continue
|
|
205
|
+
fi
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
if [[ "$in_frontmatter" == true ]]; then
|
|
209
|
+
if [[ "$line" =~ ^${field_name}:[[:space:]]*(.*)$ ]]; then
|
|
210
|
+
field_value="${BASH_REMATCH[1]}"
|
|
211
|
+
# Remove quotes if present
|
|
212
|
+
field_value="${field_value#\"}"
|
|
213
|
+
field_value="${field_value%\"}"
|
|
214
|
+
break
|
|
215
|
+
fi
|
|
216
|
+
fi
|
|
217
|
+
done <<< "$content"
|
|
218
|
+
|
|
219
|
+
if [[ -z "$field_value" ]] && [[ "$required" == true ]]; then
|
|
220
|
+
log_error "Required field missing: $field_name in $file_path"
|
|
221
|
+
return $EXIT_VALIDATION_FAILED
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
echo "$field_value"
|
|
225
|
+
return $EXIT_SUCCESS
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
##################################
|
|
229
|
+
# Content Validation Functions
|
|
230
|
+
##################################
|
|
231
|
+
|
|
232
|
+
validate_subagent_metadata() {
|
|
233
|
+
local file_path="$1"
|
|
234
|
+
|
|
235
|
+
log_debug "Validating subagent metadata: $file_path"
|
|
236
|
+
|
|
237
|
+
# Validate required fields
|
|
238
|
+
local required_fields=("name" "description")
|
|
239
|
+
local field
|
|
240
|
+
|
|
241
|
+
for field in "${required_fields[@]}"; do
|
|
242
|
+
local field_value
|
|
243
|
+
if ! field_value=$(extract_frontmatter_field "$file_path" "$field" true); then
|
|
244
|
+
return $EXIT_VALIDATION_FAILED
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
case "$field" in
|
|
248
|
+
"name")
|
|
249
|
+
if ! validate_subagent_name_field "$field_value"; then
|
|
250
|
+
log_error "Invalid name field in: $file_path"
|
|
251
|
+
return $EXIT_VALIDATION_FAILED
|
|
252
|
+
fi
|
|
253
|
+
;;
|
|
254
|
+
"description")
|
|
255
|
+
if ! validate_description_field "$field_value"; then
|
|
256
|
+
log_error "Invalid description field in: $file_path"
|
|
257
|
+
return $EXIT_VALIDATION_FAILED
|
|
258
|
+
fi
|
|
259
|
+
;;
|
|
260
|
+
esac
|
|
261
|
+
done
|
|
262
|
+
|
|
263
|
+
# Validate optional fields if present
|
|
264
|
+
local optional_fields=("version" "tools" "tags")
|
|
265
|
+
for field in "${optional_fields[@]}"; do
|
|
266
|
+
local field_value
|
|
267
|
+
if field_value=$(extract_frontmatter_field "$file_path" "$field" false); then
|
|
268
|
+
if [[ -n "$field_value" ]]; then
|
|
269
|
+
case "$field" in
|
|
270
|
+
"version")
|
|
271
|
+
validate_version_field "$field_value" || {
|
|
272
|
+
log_warning "Invalid version field in: $file_path"
|
|
273
|
+
}
|
|
274
|
+
;;
|
|
275
|
+
"tools")
|
|
276
|
+
validate_tools_field "$field_value" || {
|
|
277
|
+
log_warning "Invalid tools field in: $file_path"
|
|
278
|
+
}
|
|
279
|
+
;;
|
|
280
|
+
"tags")
|
|
281
|
+
validate_tags_field "$field_value" || {
|
|
282
|
+
log_warning "Invalid tags field in: $file_path"
|
|
283
|
+
}
|
|
284
|
+
;;
|
|
285
|
+
esac
|
|
286
|
+
fi
|
|
287
|
+
fi
|
|
288
|
+
done
|
|
289
|
+
|
|
290
|
+
log_debug "Subagent metadata validation passed: $file_path"
|
|
291
|
+
return $EXIT_SUCCESS
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
validate_subagent_content() {
|
|
295
|
+
local file_path="$1"
|
|
296
|
+
|
|
297
|
+
log_debug "Validating subagent content: $file_path"
|
|
298
|
+
|
|
299
|
+
local content
|
|
300
|
+
if ! content=$(read_file_safely "$file_path"); then
|
|
301
|
+
log_error "Failed to read file for content validation: $file_path"
|
|
302
|
+
return $EXIT_VALIDATION_FAILED
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
# Check for minimum content after frontmatter
|
|
306
|
+
local in_frontmatter=false
|
|
307
|
+
local frontmatter_ended=false
|
|
308
|
+
local content_lines=0
|
|
309
|
+
|
|
310
|
+
while IFS= read -r line; do
|
|
311
|
+
if [[ "$line" == "---" ]]; then
|
|
312
|
+
if [[ "$in_frontmatter" == true ]]; then
|
|
313
|
+
frontmatter_ended=true
|
|
314
|
+
else
|
|
315
|
+
in_frontmatter=true
|
|
316
|
+
fi
|
|
317
|
+
continue
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
if [[ "$frontmatter_ended" == true ]]; then
|
|
321
|
+
# Count non-empty lines
|
|
322
|
+
if [[ -n "${line// }" ]]; then
|
|
323
|
+
((content_lines++))
|
|
324
|
+
fi
|
|
325
|
+
fi
|
|
326
|
+
done <<< "$content"
|
|
327
|
+
|
|
328
|
+
if [[ $content_lines -lt 3 ]]; then
|
|
329
|
+
log_error "Insufficient content after frontmatter in: $file_path"
|
|
330
|
+
return $EXIT_VALIDATION_FAILED
|
|
331
|
+
fi
|
|
332
|
+
|
|
333
|
+
if ! validate_content_security "$content" "$file_path"; then
|
|
334
|
+
return $EXIT_SECURITY_VIOLATION
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
log_debug "Subagent content validation passed: $file_path"
|
|
338
|
+
return $EXIT_SUCCESS
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
##################################
|
|
342
|
+
# Field Validation Functions
|
|
343
|
+
##################################
|
|
344
|
+
# See: field-validators.sh
|
|
345
|
+
|
|
346
|
+
##################################
|
|
347
|
+
# Security Validation Functions
|
|
348
|
+
##################################
|
|
349
|
+
|
|
350
|
+
validate_content_security() {
|
|
351
|
+
local content="$1"
|
|
352
|
+
local file_path="$2"
|
|
353
|
+
|
|
354
|
+
log_debug "Performing security validation on content"
|
|
355
|
+
|
|
356
|
+
# Check for suspicious patterns (excluding legitimate markdown)
|
|
357
|
+
local suspicious_patterns=(
|
|
358
|
+
'rm\s+-rf\s+/'
|
|
359
|
+
'curl\s+.*\|\s*sh'
|
|
360
|
+
'wget\s+.*\|\s*sh'
|
|
361
|
+
'eval\s*\$\('
|
|
362
|
+
'`[^`]*\$\([^`]*`'
|
|
363
|
+
'exec\s+["\047].*[;&]'
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
local pattern
|
|
367
|
+
for pattern in "${suspicious_patterns[@]}"; do
|
|
368
|
+
if echo "$content" | grep -qE "$pattern"; then
|
|
369
|
+
handle_security_violation "suspicious_content" \
|
|
370
|
+
"Suspicious pattern detected: $pattern" "$file_path"
|
|
371
|
+
return $EXIT_SECURITY_VIOLATION
|
|
372
|
+
fi
|
|
373
|
+
done
|
|
374
|
+
|
|
375
|
+
# Check for potential credential exposure
|
|
376
|
+
local credential_patterns=(
|
|
377
|
+
'password\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
|
|
378
|
+
'token\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
|
|
379
|
+
'api[_-]?key\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
|
|
380
|
+
'secret\s*[:=]\s*["\047]?[^"\047[:space:]]+["\047]?'
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
for pattern in "${credential_patterns[@]}"; do
|
|
384
|
+
if echo "$content" | grep -qiE "$pattern"; then
|
|
385
|
+
handle_security_violation "potential_credential_exposure" \
|
|
386
|
+
"Potential credential pattern detected: $pattern" "$file_path"
|
|
387
|
+
return $EXIT_SECURITY_VIOLATION
|
|
388
|
+
fi
|
|
389
|
+
done
|
|
390
|
+
|
|
391
|
+
log_debug "Content security validation passed"
|
|
392
|
+
return $EXIT_SUCCESS
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
##################################
|
|
396
|
+
# Batch Validation & Reporting
|
|
397
|
+
##################################
|
|
398
|
+
# See: validation-reporter.sh
|
|
399
|
+
|
|
400
|
+
##################################
|
|
401
|
+
# Initialization
|
|
402
|
+
##################################
|
|
403
|
+
|
|
404
|
+
initialize_subagent_validator() {
|
|
405
|
+
log_debug "Subagent validator module initialized"
|
|
406
|
+
return $EXIT_SUCCESS
|
|
407
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# Validation Reporter Module
|
|
5
|
+
#
|
|
6
|
+
# Provides validation reporting and batch validation functions
|
|
7
|
+
# for subagent definitions.
|
|
8
|
+
# Extracted from subagent-validator.sh.
|
|
9
|
+
|
|
10
|
+
# Include guard
|
|
11
|
+
[[ -n "${_VALIDATION_REPORTER_LOADED:-}" ]] && return 0
|
|
12
|
+
_VALIDATION_REPORTER_LOADED=1
|
|
13
|
+
|
|
14
|
+
# Source required modules
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
source "$SCRIPT_DIR/config-constants.sh"
|
|
17
|
+
source "$SCRIPT_DIR/error-handler.sh"
|
|
18
|
+
|
|
19
|
+
##################################
|
|
20
|
+
# Batch Validation Functions
|
|
21
|
+
##################################
|
|
22
|
+
|
|
23
|
+
validate_all_subagents() {
|
|
24
|
+
local directory="${1:-$SUBAGENTS_DIR}"
|
|
25
|
+
local validation_mode="${2:-strict}"
|
|
26
|
+
local validation_results=()
|
|
27
|
+
local total_count=0
|
|
28
|
+
local passed_count=0
|
|
29
|
+
local failed_count=0
|
|
30
|
+
|
|
31
|
+
log_info "Validating all subagents in: $directory"
|
|
32
|
+
|
|
33
|
+
if [[ ! -d "$directory" ]]; then
|
|
34
|
+
log_error "Directory not found: $directory"
|
|
35
|
+
return $EXIT_GENERAL_ERROR
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
find "$directory" -name "*$SUBAGENT_FILE_EXTENSION" -type f 2>/dev/null | while read -r file; do
|
|
39
|
+
((total_count++))
|
|
40
|
+
local filename
|
|
41
|
+
filename=$(basename "$file")
|
|
42
|
+
|
|
43
|
+
if validate_subagent_file "$file" "$validation_mode" 2>/dev/null; then
|
|
44
|
+
((passed_count++))
|
|
45
|
+
validation_results+=("PASS: $filename")
|
|
46
|
+
log_debug "Validation passed: $filename"
|
|
47
|
+
else
|
|
48
|
+
((failed_count++))
|
|
49
|
+
validation_results+=("FAIL: $filename")
|
|
50
|
+
log_debug "Validation failed: $filename"
|
|
51
|
+
fi
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
# Output results
|
|
55
|
+
log_info "Validation Summary:"
|
|
56
|
+
log_info " Total subagents: $total_count"
|
|
57
|
+
log_info " Passed: $passed_count"
|
|
58
|
+
log_info " Failed: $failed_count"
|
|
59
|
+
|
|
60
|
+
# Detailed results in debug mode
|
|
61
|
+
if is_debug_mode 2>/dev/null; then
|
|
62
|
+
for result in "${validation_results[@]}"; do
|
|
63
|
+
log_debug " $result"
|
|
64
|
+
done
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
if [[ $failed_count -gt 0 ]]; then
|
|
68
|
+
return $EXIT_VALIDATION_FAILED
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
return $EXIT_SUCCESS
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
##################################
|
|
75
|
+
# Validation Reporting Functions
|
|
76
|
+
##################################
|
|
77
|
+
|
|
78
|
+
generate_validation_report() {
|
|
79
|
+
local directory="${1:-$SUBAGENTS_DIR}"
|
|
80
|
+
local output_format="${2:-text}"
|
|
81
|
+
|
|
82
|
+
log_info "Generating validation report for: $directory"
|
|
83
|
+
|
|
84
|
+
case "$output_format" in
|
|
85
|
+
"json")
|
|
86
|
+
generate_json_validation_report "$directory"
|
|
87
|
+
;;
|
|
88
|
+
"text"|*)
|
|
89
|
+
generate_text_validation_report "$directory"
|
|
90
|
+
;;
|
|
91
|
+
esac
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
generate_text_validation_report() {
|
|
95
|
+
local directory="$1"
|
|
96
|
+
|
|
97
|
+
echo "Subagent Validation Report"
|
|
98
|
+
echo "========================="
|
|
99
|
+
echo "Directory: $directory"
|
|
100
|
+
echo "Generated: $(date)"
|
|
101
|
+
echo ""
|
|
102
|
+
|
|
103
|
+
local total=0 passed=0 failed=0
|
|
104
|
+
|
|
105
|
+
find "$directory" -name "*$SUBAGENT_FILE_EXTENSION" -type f 2>/dev/null | while read -r file; do
|
|
106
|
+
((total++))
|
|
107
|
+
local filename name
|
|
108
|
+
filename=$(basename "$file")
|
|
109
|
+
name=$(basename "$file" "$SUBAGENT_FILE_EXTENSION")
|
|
110
|
+
|
|
111
|
+
echo -n "Validating $name... "
|
|
112
|
+
|
|
113
|
+
if validate_subagent_file "$file" "strict" 2>/dev/null; then
|
|
114
|
+
((passed++))
|
|
115
|
+
echo "PASSED"
|
|
116
|
+
else
|
|
117
|
+
((failed++))
|
|
118
|
+
echo "FAILED"
|
|
119
|
+
validate_subagent_file "$file" "strict" 2>&1 | sed "s/^/ Error: /"
|
|
120
|
+
fi
|
|
121
|
+
echo ""
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
echo "Summary:"
|
|
125
|
+
echo " Total: $total"
|
|
126
|
+
echo " Passed: $passed"
|
|
127
|
+
echo " Failed: $failed"
|
|
128
|
+
|
|
129
|
+
if [[ $failed -eq 0 ]]; then
|
|
130
|
+
echo " Status: ALL VALID"
|
|
131
|
+
else
|
|
132
|
+
echo " Status: ISSUES FOUND"
|
|
133
|
+
fi
|
|
134
|
+
}
|