claude-flow-novice 2.18.22 → 2.18.24
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/.claude/CLAUDE.md +17 -0
- package/.claude/cfn-scripts/check-memory.sh +150 -0
- package/.claude/cfn-scripts/run-with-memory-limit.sh +91 -0
- package/.claude/commands/cfn-loop/cfn-loop-cli.md +9 -0
- package/.claude/commands/cfn-loop-task.md +11 -0
- package/.claude/commands/cfn-ruvector/cfn-codebase-reindex.md +23 -4
- package/.claude/commands/cfn-ruvector/cfn-codebase-search.md +10 -2
- package/.claude/commands/cfn-ruvector/cfn-detect-stale-docs.md +22 -4
- package/.claude/hooks/README.md +148 -148
- package/.claude/hooks/cfn-bash-search-hook.sh +87 -0
- package/.claude/hooks/cfn-smart-search-hook.sh +127 -0
- package/.claude/hooks/deprecated/cfn-SessionStart-cfn-load-openai-key.sh +48 -0
- package/.claude/hooks/post-commit-codebase-index +79 -45
- package/.claude/settings.json +20 -11
- package/.claude/skills/CLAUDE.md +70 -0
- package/.claude/skills/cfn-edit-safety/lib/hooks/security-scanner.sh +1 -0
- package/.claude/skills/cfn-local-ruvector-accelerator/SKILL.md +37 -21
- package/.claude/skills/cfn-local-ruvector-accelerator/cfn-integration.sh +47 -6
- package/.claude/skills/cfn-local-ruvector-accelerator/src/cli/index.rs +2 -1
- package/.claude/skills/cfn-local-ruvector-accelerator/src/cli/init.rs +3 -3
- package/.claude/skills/cfn-local-ruvector-accelerator/src/cli/query.rs +1 -1
- package/.claude/skills/cfn-local-ruvector-accelerator/src/lib.rs +1 -0
- package/.claude/skills/cfn-local-ruvector-accelerator/src/paths.rs +4 -2
- package/.claude/skills/cfn-local-ruvector-accelerator/src/search_engine.rs +11 -0
- package/.claude/skills/cfn-local-ruvector-accelerator/test_query_api.sh +102 -102
- package/CLAUDE.md +63 -373
- package/docs/CFN_LOOP_CLI_MODE.md +134 -0
- package/package.json +9 -5
- package/scripts/cfn-init.js +8 -2
- package/scripts/organize-root-files.sh +340 -340
- package/scripts/postinstall.js +120 -3
- package/test-epic-creator-security.sh +202 -202
- package/.claude/hooks/SessionStart:cfn-build-ruvector.sh +0 -28
- package/.claude/hooks/SessionStart:cfn-load-openai-key.sh +0 -35
- /package/.claude/hooks/{SessionStart-cfn-build-ruvector.sh → cfn-SessionStart-cfn-build-ruvector.sh} +0 -0
- /package/.claude/hooks/{cfn-load-cerebras-env.sh → deprecated/cfn-load-cerebras-env.sh} +0 -0
package/scripts/postinstall.js
CHANGED
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|
* CFN Post-install Script
|
|
5
5
|
*
|
|
6
6
|
* This script runs after npm install to properly set up CFN structure.
|
|
7
|
-
* It handles
|
|
7
|
+
* It handles:
|
|
8
8
|
* 1. Preserving existing custom agents in the target project
|
|
9
9
|
* 2. Only updating/replacing the cfn-dev-team folder
|
|
10
|
+
* 3. Setting up local-ruvector for semantic code search
|
|
11
|
+
* 4. Installing git hooks for auto-indexing on commit (handles deleted/renamed files)
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
import fs from 'fs';
|
|
13
15
|
import path from 'path';
|
|
14
16
|
import { fileURLToPath } from 'url';
|
|
17
|
+
import { execSync } from 'child_process';
|
|
15
18
|
|
|
16
19
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
20
|
const __dirname = path.dirname(__filename);
|
|
@@ -22,7 +25,8 @@ const colors = {
|
|
|
22
25
|
reset: '\x1b[0m',
|
|
23
26
|
green: '\x1b[32m',
|
|
24
27
|
yellow: '\x1b[33m',
|
|
25
|
-
cyan: '\x1b[36m'
|
|
28
|
+
cyan: '\x1b[36m',
|
|
29
|
+
white: '\x1b[37m'
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
function log(message, color = 'reset') {
|
|
@@ -103,6 +107,113 @@ function updateSkillsAndCommands(targetDir) {
|
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
|
|
110
|
+
function installGitHooks(targetDir) {
|
|
111
|
+
const gitDir = path.join(targetDir, '.git');
|
|
112
|
+
const hooksDir = path.join(gitDir, 'hooks');
|
|
113
|
+
|
|
114
|
+
// Only install if this is a git repo
|
|
115
|
+
if (!fs.existsSync(gitDir)) {
|
|
116
|
+
log('Not a git repository - skipping hook installation', 'yellow');
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Ensure hooks directory exists
|
|
121
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
122
|
+
|
|
123
|
+
// Install post-commit hook for RuVector indexing
|
|
124
|
+
const hookSource = path.join(targetDir, '.claude', 'hooks', 'post-commit-codebase-index');
|
|
125
|
+
const hookDest = path.join(hooksDir, 'post-commit');
|
|
126
|
+
|
|
127
|
+
if (fs.existsSync(hookSource)) {
|
|
128
|
+
// Check if existing hook is not ours
|
|
129
|
+
if (fs.existsSync(hookDest)) {
|
|
130
|
+
const existingContent = fs.readFileSync(hookDest, 'utf-8');
|
|
131
|
+
if (!existingContent.includes('RuVector')) {
|
|
132
|
+
// Backup existing hook and append ours
|
|
133
|
+
const backupPath = path.join(hooksDir, 'post-commit.backup');
|
|
134
|
+
fs.copyFileSync(hookDest, backupPath);
|
|
135
|
+
log(`Backed up existing post-commit hook to ${backupPath}`, 'yellow');
|
|
136
|
+
|
|
137
|
+
// Append our hook call to existing
|
|
138
|
+
const appendContent = `\n\n# CFN RuVector indexing (added by claude-flow-novice)\n${hookSource}\n`;
|
|
139
|
+
fs.appendFileSync(hookDest, appendContent);
|
|
140
|
+
log('✓ Appended RuVector hook to existing post-commit', 'green');
|
|
141
|
+
} else {
|
|
142
|
+
// Already has our hook, update it
|
|
143
|
+
fs.copyFileSync(hookSource, hookDest);
|
|
144
|
+
fs.chmodSync(hookDest, 0o755);
|
|
145
|
+
log('✓ Updated post-commit hook', 'green');
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
// No existing hook, install ours
|
|
149
|
+
fs.copyFileSync(hookSource, hookDest);
|
|
150
|
+
fs.chmodSync(hookDest, 0o755);
|
|
151
|
+
log('✓ Installed post-commit hook for RuVector indexing', 'green');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function setupLocalRuvector(targetDir) {
|
|
157
|
+
const ruvectorSkillDir = path.join(targetDir, '.claude', 'skills', 'cfn-local-ruvector-accelerator');
|
|
158
|
+
|
|
159
|
+
// Check if local-ruvector binary is available in PATH or ~/.local/bin
|
|
160
|
+
const homeBin = process.env.HOME
|
|
161
|
+
? path.join(process.env.HOME, '.local', 'bin', 'local-ruvector')
|
|
162
|
+
: null;
|
|
163
|
+
|
|
164
|
+
// Check if binary exists in PATH
|
|
165
|
+
let binaryInPath = false;
|
|
166
|
+
try {
|
|
167
|
+
execSync('which local-ruvector', { stdio: 'ignore' });
|
|
168
|
+
binaryInPath = true;
|
|
169
|
+
} catch {
|
|
170
|
+
binaryInPath = false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (binaryInPath || (homeBin && fs.existsSync(homeBin))) {
|
|
174
|
+
log('✓ local-ruvector binary found', 'green');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Check if Rust is available for building
|
|
179
|
+
let hasRust = false;
|
|
180
|
+
try {
|
|
181
|
+
execSync('cargo --version', { stdio: 'ignore' });
|
|
182
|
+
hasRust = true;
|
|
183
|
+
} catch {
|
|
184
|
+
hasRust = false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (hasRust && fs.existsSync(ruvectorSkillDir)) {
|
|
188
|
+
log('Building local-ruvector binary (this may take a minute)...', 'cyan');
|
|
189
|
+
try {
|
|
190
|
+
execSync('cargo build --release', {
|
|
191
|
+
cwd: ruvectorSkillDir,
|
|
192
|
+
stdio: 'inherit'
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Install to ~/.local/bin
|
|
196
|
+
const targetBinary = path.join(ruvectorSkillDir, 'target', 'release', 'local-ruvector');
|
|
197
|
+
if (fs.existsSync(targetBinary) && process.env.HOME) {
|
|
198
|
+
const installDir = path.join(process.env.HOME, '.local', 'bin');
|
|
199
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
200
|
+
fs.copyFileSync(targetBinary, path.join(installDir, 'local-ruvector'));
|
|
201
|
+
fs.chmodSync(path.join(installDir, 'local-ruvector'), 0o755);
|
|
202
|
+
log('✓ local-ruvector installed to ~/.local/bin/', 'green');
|
|
203
|
+
log(' Ensure ~/.local/bin is in your PATH', 'cyan');
|
|
204
|
+
}
|
|
205
|
+
} catch (err) {
|
|
206
|
+
log('Warning: Failed to build local-ruvector: ' + err.message, 'yellow');
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
log('Note: local-ruvector binary not found.', 'yellow');
|
|
210
|
+
log('To enable fast semantic code search:', 'cyan');
|
|
211
|
+
log(' 1. Install Rust: curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh', 'white');
|
|
212
|
+
log(' 2. Build ruvector: npm run ruvector:local:build', 'white');
|
|
213
|
+
log(' 3. Install binary: cp .claude/skills/cfn-local-ruvector-accelerator/target/release/local-ruvector ~/.local/bin/', 'white');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
106
217
|
// Main execution
|
|
107
218
|
function main() {
|
|
108
219
|
log('CFN Post-install Script', 'cyan');
|
|
@@ -127,6 +238,12 @@ function main() {
|
|
|
127
238
|
// Update skills and commands
|
|
128
239
|
updateSkillsAndCommands(process.cwd());
|
|
129
240
|
|
|
241
|
+
// Setup local-ruvector binary
|
|
242
|
+
setupLocalRuvector(process.cwd());
|
|
243
|
+
|
|
244
|
+
// Install git hooks for auto-indexing
|
|
245
|
+
installGitHooks(process.cwd());
|
|
246
|
+
|
|
130
247
|
// Create .cfn-initialized marker
|
|
131
248
|
fs.writeFileSync(path.join(claudeDir, '.cfn-initialized'), new Date().toISOString());
|
|
132
249
|
|
|
@@ -143,4 +260,4 @@ try {
|
|
|
143
260
|
} catch (error) {
|
|
144
261
|
console.error('CFN post-install failed:', error);
|
|
145
262
|
process.exit(1);
|
|
146
|
-
}
|
|
263
|
+
}
|
|
@@ -1,203 +1,203 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
# Test script to validate epic-creator-v2 security fixes
|
|
5
|
-
# Tests command injection, path traversal, and input sanitization
|
|
6
|
-
|
|
7
|
-
# Color codes for output
|
|
8
|
-
readonly GREEN='\033[0;32m'
|
|
9
|
-
readonly RED='\033[0;31m'
|
|
10
|
-
readonly YELLOW='\033[1;33m'
|
|
11
|
-
readonly NC='\033[0m' # No Color
|
|
12
|
-
|
|
13
|
-
# Test counters
|
|
14
|
-
TESTS_RUN=0
|
|
15
|
-
TESTS_PASSED=0
|
|
16
|
-
TESTS_FAILED=0
|
|
17
|
-
|
|
18
|
-
# Logging functions
|
|
19
|
-
log_test() {
|
|
20
|
-
echo -e "${YELLOW}[TEST]${NC} $1"
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
log_pass() {
|
|
24
|
-
echo -e "${GREEN}[PASS]${NC} $1"
|
|
25
|
-
((TESTS_PASSED++))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
log_fail() {
|
|
29
|
-
echo -e "${RED}[FAIL]${NC} $1"
|
|
30
|
-
((TESTS_FAILED++))
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
# Run a test case
|
|
34
|
-
run_test() {
|
|
35
|
-
((TESTS_RUN++))
|
|
36
|
-
log_test "Running: $1"
|
|
37
|
-
|
|
38
|
-
if eval "$2"; then
|
|
39
|
-
log_pass "Test passed: $1"
|
|
40
|
-
else
|
|
41
|
-
log_fail "Test failed: $1"
|
|
42
|
-
fi
|
|
43
|
-
echo
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
# Test command injection protection
|
|
47
|
-
test_command_injection() {
|
|
48
|
-
echo "=== Testing Command Injection Protection ==="
|
|
49
|
-
|
|
50
|
-
# Test 1: Command substitution attempt
|
|
51
|
-
run_test "Command substitution \$(whoami)" \
|
|
52
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
53
|
-
&& ! sanitize_string "test\$(whoami)" 2>/dev/null'
|
|
54
|
-
|
|
55
|
-
# Test 2: Backtick command substitution
|
|
56
|
-
run_test "Backtick command substitution \`whoami\`" \
|
|
57
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
58
|
-
&& ! sanitize_string "test\`whoami\`" 2>/dev/null'
|
|
59
|
-
|
|
60
|
-
# Test 3: Pipe character
|
|
61
|
-
run_test "Pipe character injection" \
|
|
62
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
63
|
-
&& ! sanitize_string "test | ls" 2>/dev/null'
|
|
64
|
-
|
|
65
|
-
# Test 4: Command chaining
|
|
66
|
-
run_test "Command chaining &&" \
|
|
67
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
68
|
-
&& ! sanitize_string "test && rm -rf" 2>/dev/null'
|
|
69
|
-
|
|
70
|
-
# Test 5: Command chaining ||"
|
|
71
|
-
run_test "Command chaining ||" \
|
|
72
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
73
|
-
&& ! sanitize_string "test || rm -rf" 2>/dev/null'
|
|
74
|
-
|
|
75
|
-
# Test 6: Semicolon
|
|
76
|
-
run_test "Semicolon separator" \
|
|
77
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
78
|
-
&& ! sanitize_string "test; rm -rf" 2>/dev/null'
|
|
79
|
-
|
|
80
|
-
# Test 7: Output redirection
|
|
81
|
-
run_test "Output redirection >" \
|
|
82
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
83
|
-
&& ! sanitize_string "test > /etc/passwd" 2>/dev/null'
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
# Test path traversal protection
|
|
87
|
-
test_path_traversal() {
|
|
88
|
-
echo "=== Testing Path Traversal Protection ==="
|
|
89
|
-
|
|
90
|
-
# Test 1: Directory traversal
|
|
91
|
-
run_test "Directory traversal ../etc/passwd" \
|
|
92
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
93
|
-
&& ! validate_path "../../../etc/passwd" 2>/dev/null'
|
|
94
|
-
|
|
95
|
-
# Test 2: Absolute path outside
|
|
96
|
-
run_test "Absolute path outside /etc/passwd" \
|
|
97
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
98
|
-
&& ! validate_path "/etc/passwd" 2>/dev/null'
|
|
99
|
-
|
|
100
|
-
# Test 3: Home directory
|
|
101
|
-
run_test "Home directory ~/" \
|
|
102
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
103
|
-
&& ! validate_path "~/.ssh/id_rsa" 2>/dev/null'
|
|
104
|
-
|
|
105
|
-
# Test 4: Valid relative path
|
|
106
|
-
run_test "Valid relative path" \
|
|
107
|
-
'. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
108
|
-
&& validate_path "./output.json" 2>/dev/null'
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
# Test input validation
|
|
112
|
-
test_input_validation() {
|
|
113
|
-
echo "=== Testing Input Validation ==="
|
|
114
|
-
|
|
115
|
-
# Test 1: Empty input
|
|
116
|
-
run_test "Empty epic description" \
|
|
117
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
118
|
-
&& ! validate_epic_description "" 2>/dev/null'
|
|
119
|
-
|
|
120
|
-
# Test 2: Too short input
|
|
121
|
-
run_test "Too short epic description" \
|
|
122
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
123
|
-
&& ! validate_epic_description "ab" 2>/dev/null'
|
|
124
|
-
|
|
125
|
-
# Test 3: Valid input
|
|
126
|
-
run_test "Valid epic description" \
|
|
127
|
-
'. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
128
|
-
&& validate_epic_description "This is a valid epic description" 2>/dev/null'
|
|
129
|
-
|
|
130
|
-
# Test 4: Input exceeding max length
|
|
131
|
-
run_test "Input exceeding max length" \
|
|
132
|
-
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
133
|
-
&& ! sanitize_string "$(printf "a%.0s" {1..10001})" 2>/dev/null'
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
# Test secure temp file creation
|
|
137
|
-
test_temp_file_creation() {
|
|
138
|
-
echo "=== Testing Secure Temp File Creation ==="
|
|
139
|
-
|
|
140
|
-
# Test 1: Create secure temp file
|
|
141
|
-
run_test "Create secure temp file" \
|
|
142
|
-
'. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
143
|
-
&& temp_file=$(create_secure_temp "test" "tmp") \
|
|
144
|
-
&& [[ -f "$temp_file" ]] \
|
|
145
|
-
&& [[ "$(stat -c %a "$temp_file" 2>/dev/null || stat -f%A "$temp_file" 2>/dev/null)" == "600" ]] \
|
|
146
|
-
&& rm -f "$temp_file"'
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
# Test epic creator with malicious inputs
|
|
150
|
-
test_epic_creator_malicious() {
|
|
151
|
-
echo "=== Testing Epic Creator with Malicious Inputs ==="
|
|
152
|
-
|
|
153
|
-
# Test 1: Command injection in description
|
|
154
|
-
run_test "Epic creator with command injection" \
|
|
155
|
-
'! ./.claude/agents/cfn-dev-team/utility/epic-creator-v2.sh \
|
|
156
|
-
"test\$(whoami) injection" --mode=mvp >/dev/null 2>&1'
|
|
157
|
-
|
|
158
|
-
# Test 2: Path traversal in output
|
|
159
|
-
run_test "Epic creator with path traversal output" \
|
|
160
|
-
'! ./.claude/agents/cfn-dev-team/utility/epic-creator-v2.sh \
|
|
161
|
-
"test epic" --output="../../../etc/passwd" >/dev/null 2>&1'
|
|
162
|
-
|
|
163
|
-
# Test 3: Valid epic creation
|
|
164
|
-
run_test "Valid epic creation" \
|
|
165
|
-
'temp_out=$(mktemp) \
|
|
166
|
-
&& ./.claude/agents/cfn-dev-team/utility/epic-creator-v2.sh \
|
|
167
|
-
"Test epic for validation" --output="$temp_out" >/dev/null 2>&1 \
|
|
168
|
-
&& [[ -f "$temp_out" ]] \
|
|
169
|
-
&& jq . "$temp_out" >/dev/null 2>&1 \
|
|
170
|
-
&& rm -f "$temp_out"'
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
# Main execution
|
|
174
|
-
main() {
|
|
175
|
-
echo "Starting Epic Creator v2 Security Validation Tests"
|
|
176
|
-
echo "=============================================="
|
|
177
|
-
echo
|
|
178
|
-
|
|
179
|
-
# Run all test suites
|
|
180
|
-
test_command_injection
|
|
181
|
-
test_path_traversal
|
|
182
|
-
test_input_validation
|
|
183
|
-
test_temp_file_creation
|
|
184
|
-
test_epic_creator_malicious
|
|
185
|
-
|
|
186
|
-
# Summary
|
|
187
|
-
echo "=============================================="
|
|
188
|
-
echo "Test Summary:"
|
|
189
|
-
echo " Total tests run: $TESTS_RUN"
|
|
190
|
-
echo -e " Passed: ${GREEN}$TESTS_PASSED${NC}"
|
|
191
|
-
echo -e " Failed: ${RED}$TESTS_FAILED${NC}"
|
|
192
|
-
|
|
193
|
-
if [[ $TESTS_FAILED -eq 0 ]]; then
|
|
194
|
-
echo -e "\n${GREEN}✅ All security tests passed!${NC}"
|
|
195
|
-
exit 0
|
|
196
|
-
else
|
|
197
|
-
echo -e "\n${RED}❌ Some security tests failed!${NC}"
|
|
198
|
-
exit 1
|
|
199
|
-
fi
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
# Run main function
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Test script to validate epic-creator-v2 security fixes
|
|
5
|
+
# Tests command injection, path traversal, and input sanitization
|
|
6
|
+
|
|
7
|
+
# Color codes for output
|
|
8
|
+
readonly GREEN='\033[0;32m'
|
|
9
|
+
readonly RED='\033[0;31m'
|
|
10
|
+
readonly YELLOW='\033[1;33m'
|
|
11
|
+
readonly NC='\033[0m' # No Color
|
|
12
|
+
|
|
13
|
+
# Test counters
|
|
14
|
+
TESTS_RUN=0
|
|
15
|
+
TESTS_PASSED=0
|
|
16
|
+
TESTS_FAILED=0
|
|
17
|
+
|
|
18
|
+
# Logging functions
|
|
19
|
+
log_test() {
|
|
20
|
+
echo -e "${YELLOW}[TEST]${NC} $1"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
log_pass() {
|
|
24
|
+
echo -e "${GREEN}[PASS]${NC} $1"
|
|
25
|
+
((TESTS_PASSED++))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
log_fail() {
|
|
29
|
+
echo -e "${RED}[FAIL]${NC} $1"
|
|
30
|
+
((TESTS_FAILED++))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Run a test case
|
|
34
|
+
run_test() {
|
|
35
|
+
((TESTS_RUN++))
|
|
36
|
+
log_test "Running: $1"
|
|
37
|
+
|
|
38
|
+
if eval "$2"; then
|
|
39
|
+
log_pass "Test passed: $1"
|
|
40
|
+
else
|
|
41
|
+
log_fail "Test failed: $1"
|
|
42
|
+
fi
|
|
43
|
+
echo
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Test command injection protection
|
|
47
|
+
test_command_injection() {
|
|
48
|
+
echo "=== Testing Command Injection Protection ==="
|
|
49
|
+
|
|
50
|
+
# Test 1: Command substitution attempt
|
|
51
|
+
run_test "Command substitution \$(whoami)" \
|
|
52
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
53
|
+
&& ! sanitize_string "test\$(whoami)" 2>/dev/null'
|
|
54
|
+
|
|
55
|
+
# Test 2: Backtick command substitution
|
|
56
|
+
run_test "Backtick command substitution \`whoami\`" \
|
|
57
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
58
|
+
&& ! sanitize_string "test\`whoami\`" 2>/dev/null'
|
|
59
|
+
|
|
60
|
+
# Test 3: Pipe character
|
|
61
|
+
run_test "Pipe character injection" \
|
|
62
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
63
|
+
&& ! sanitize_string "test | ls" 2>/dev/null'
|
|
64
|
+
|
|
65
|
+
# Test 4: Command chaining
|
|
66
|
+
run_test "Command chaining &&" \
|
|
67
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
68
|
+
&& ! sanitize_string "test && rm -rf" 2>/dev/null'
|
|
69
|
+
|
|
70
|
+
# Test 5: Command chaining ||"
|
|
71
|
+
run_test "Command chaining ||" \
|
|
72
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
73
|
+
&& ! sanitize_string "test || rm -rf" 2>/dev/null'
|
|
74
|
+
|
|
75
|
+
# Test 6: Semicolon
|
|
76
|
+
run_test "Semicolon separator" \
|
|
77
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
78
|
+
&& ! sanitize_string "test; rm -rf" 2>/dev/null'
|
|
79
|
+
|
|
80
|
+
# Test 7: Output redirection
|
|
81
|
+
run_test "Output redirection >" \
|
|
82
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
83
|
+
&& ! sanitize_string "test > /etc/passwd" 2>/dev/null'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Test path traversal protection
|
|
87
|
+
test_path_traversal() {
|
|
88
|
+
echo "=== Testing Path Traversal Protection ==="
|
|
89
|
+
|
|
90
|
+
# Test 1: Directory traversal
|
|
91
|
+
run_test "Directory traversal ../etc/passwd" \
|
|
92
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
93
|
+
&& ! validate_path "../../../etc/passwd" 2>/dev/null'
|
|
94
|
+
|
|
95
|
+
# Test 2: Absolute path outside
|
|
96
|
+
run_test "Absolute path outside /etc/passwd" \
|
|
97
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
98
|
+
&& ! validate_path "/etc/passwd" 2>/dev/null'
|
|
99
|
+
|
|
100
|
+
# Test 3: Home directory
|
|
101
|
+
run_test "Home directory ~/" \
|
|
102
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
103
|
+
&& ! validate_path "~/.ssh/id_rsa" 2>/dev/null'
|
|
104
|
+
|
|
105
|
+
# Test 4: Valid relative path
|
|
106
|
+
run_test "Valid relative path" \
|
|
107
|
+
'. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
108
|
+
&& validate_path "./output.json" 2>/dev/null'
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Test input validation
|
|
112
|
+
test_input_validation() {
|
|
113
|
+
echo "=== Testing Input Validation ==="
|
|
114
|
+
|
|
115
|
+
# Test 1: Empty input
|
|
116
|
+
run_test "Empty epic description" \
|
|
117
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
118
|
+
&& ! validate_epic_description "" 2>/dev/null'
|
|
119
|
+
|
|
120
|
+
# Test 2: Too short input
|
|
121
|
+
run_test "Too short epic description" \
|
|
122
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
123
|
+
&& ! validate_epic_description "ab" 2>/dev/null'
|
|
124
|
+
|
|
125
|
+
# Test 3: Valid input
|
|
126
|
+
run_test "Valid epic description" \
|
|
127
|
+
'. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
128
|
+
&& validate_epic_description "This is a valid epic description" 2>/dev/null'
|
|
129
|
+
|
|
130
|
+
# Test 4: Input exceeding max length
|
|
131
|
+
run_test "Input exceeding max length" \
|
|
132
|
+
'!. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
133
|
+
&& ! sanitize_string "$(printf "a%.0s" {1..10001})" 2>/dev/null'
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Test secure temp file creation
|
|
137
|
+
test_temp_file_creation() {
|
|
138
|
+
echo "=== Testing Secure Temp File Creation ==="
|
|
139
|
+
|
|
140
|
+
# Test 1: Create secure temp file
|
|
141
|
+
run_test "Create secure temp file" \
|
|
142
|
+
'. ./.claude/skills/cfn-epic-creator/security-utils.sh \
|
|
143
|
+
&& temp_file=$(create_secure_temp "test" "tmp") \
|
|
144
|
+
&& [[ -f "$temp_file" ]] \
|
|
145
|
+
&& [[ "$(stat -c %a "$temp_file" 2>/dev/null || stat -f%A "$temp_file" 2>/dev/null)" == "600" ]] \
|
|
146
|
+
&& rm -f "$temp_file"'
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Test epic creator with malicious inputs
|
|
150
|
+
test_epic_creator_malicious() {
|
|
151
|
+
echo "=== Testing Epic Creator with Malicious Inputs ==="
|
|
152
|
+
|
|
153
|
+
# Test 1: Command injection in description
|
|
154
|
+
run_test "Epic creator with command injection" \
|
|
155
|
+
'! ./.claude/agents/cfn-dev-team/utility/epic-creator-v2.sh \
|
|
156
|
+
"test\$(whoami) injection" --mode=mvp >/dev/null 2>&1'
|
|
157
|
+
|
|
158
|
+
# Test 2: Path traversal in output
|
|
159
|
+
run_test "Epic creator with path traversal output" \
|
|
160
|
+
'! ./.claude/agents/cfn-dev-team/utility/epic-creator-v2.sh \
|
|
161
|
+
"test epic" --output="../../../etc/passwd" >/dev/null 2>&1'
|
|
162
|
+
|
|
163
|
+
# Test 3: Valid epic creation
|
|
164
|
+
run_test "Valid epic creation" \
|
|
165
|
+
'temp_out=$(mktemp) \
|
|
166
|
+
&& ./.claude/agents/cfn-dev-team/utility/epic-creator-v2.sh \
|
|
167
|
+
"Test epic for validation" --output="$temp_out" >/dev/null 2>&1 \
|
|
168
|
+
&& [[ -f "$temp_out" ]] \
|
|
169
|
+
&& jq . "$temp_out" >/dev/null 2>&1 \
|
|
170
|
+
&& rm -f "$temp_out"'
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Main execution
|
|
174
|
+
main() {
|
|
175
|
+
echo "Starting Epic Creator v2 Security Validation Tests"
|
|
176
|
+
echo "=============================================="
|
|
177
|
+
echo
|
|
178
|
+
|
|
179
|
+
# Run all test suites
|
|
180
|
+
test_command_injection
|
|
181
|
+
test_path_traversal
|
|
182
|
+
test_input_validation
|
|
183
|
+
test_temp_file_creation
|
|
184
|
+
test_epic_creator_malicious
|
|
185
|
+
|
|
186
|
+
# Summary
|
|
187
|
+
echo "=============================================="
|
|
188
|
+
echo "Test Summary:"
|
|
189
|
+
echo " Total tests run: $TESTS_RUN"
|
|
190
|
+
echo -e " Passed: ${GREEN}$TESTS_PASSED${NC}"
|
|
191
|
+
echo -e " Failed: ${RED}$TESTS_FAILED${NC}"
|
|
192
|
+
|
|
193
|
+
if [[ $TESTS_FAILED -eq 0 ]]; then
|
|
194
|
+
echo -e "\n${GREEN}✅ All security tests passed!${NC}"
|
|
195
|
+
exit 0
|
|
196
|
+
else
|
|
197
|
+
echo -e "\n${RED}❌ Some security tests failed!${NC}"
|
|
198
|
+
exit 1
|
|
199
|
+
fi
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
# Run main function
|
|
203
203
|
main "$@"
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# SessionStart hook: Build RuVector Rust binary if missing
|
|
3
|
-
# This ensures RuVector is compiled on cfn init
|
|
4
|
-
|
|
5
|
-
RUVECTOR_DIR="$(dirname "$(dirname "$(dirname "$0")")")/skills/cfn-local-ruvector-accelerator"
|
|
6
|
-
BINARY="$RUVECTOR_DIR/target/release/local-ruvector"
|
|
7
|
-
|
|
8
|
-
# Only build if binary doesn't exist
|
|
9
|
-
if [ ! -f "$BINARY" ]; then
|
|
10
|
-
echo "[cfn-build-ruvector] Binary not found, building..."
|
|
11
|
-
|
|
12
|
-
# Check if Cargo is available
|
|
13
|
-
if ! command -v cargo &> /dev/null; then
|
|
14
|
-
echo "[cfn-build-ruvector] WARNING: Cargo not installed, skipping RuVector build"
|
|
15
|
-
exit 0
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
|
-
# Build release binary
|
|
19
|
-
cd "$RUVECTOR_DIR" && cargo build --release --quiet 2>/dev/null
|
|
20
|
-
|
|
21
|
-
if [ -f "$BINARY" ]; then
|
|
22
|
-
echo "[cfn-build-ruvector] ✅ RuVector binary built successfully"
|
|
23
|
-
else
|
|
24
|
-
echo "[cfn-build-ruvector] WARNING: Build failed, RuVector unavailable"
|
|
25
|
-
fi
|
|
26
|
-
else
|
|
27
|
-
echo "[cfn-build-ruvector] ✅ RuVector binary already exists"
|
|
28
|
-
fi
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# SessionStart hook: Load OpenAI API key from root .env file
|
|
4
|
-
# This ensures OPENAI_API_KEY is available for embedding generation
|
|
5
|
-
|
|
6
|
-
set -e
|
|
7
|
-
|
|
8
|
-
# Path to root .env file
|
|
9
|
-
ROOT_ENV="${PROJECT_ROOT:-.}/.env"
|
|
10
|
-
|
|
11
|
-
# Check if .env exists
|
|
12
|
-
if [[ ! -f "$ROOT_ENV" ]]; then
|
|
13
|
-
echo "⚠️ Warning: $ROOT_ENV not found. OpenAI embeddings will not work." >&2
|
|
14
|
-
exit 0
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# Extract OPENAI_API_KEY from .env
|
|
18
|
-
if grep -q "^OPENAI_API_KEY=" "$ROOT_ENV"; then
|
|
19
|
-
# Export the key for this session
|
|
20
|
-
export OPENAI_API_KEY=$(grep "^OPENAI_API_KEY=" "$ROOT_ENV" | cut -d'=' -f2- | tr -d '"')
|
|
21
|
-
|
|
22
|
-
# Verify key is set
|
|
23
|
-
if [[ -n "$OPENAI_API_KEY" ]]; then
|
|
24
|
-
echo "✅ Loaded OPENAI_API_KEY from root .env" >&2
|
|
25
|
-
else
|
|
26
|
-
echo "⚠️ Warning: OPENAI_API_KEY found but empty in $ROOT_ENV" >&2
|
|
27
|
-
fi
|
|
28
|
-
else
|
|
29
|
-
echo "⚠️ Warning: OPENAI_API_KEY not found in $ROOT_ENV. OpenAI embeddings will not work." >&2
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
# Make it available to subprocesses
|
|
33
|
-
export OPENAI_API_KEY
|
|
34
|
-
|
|
35
|
-
exit 0
|
/package/.claude/hooks/{SessionStart-cfn-build-ruvector.sh → cfn-SessionStart-cfn-build-ruvector.sh}
RENAMED
|
File without changes
|
|
File without changes
|