claude-flow-novice 2.18.21 → 2.18.23

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.
@@ -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 the cfn-dev-team agent installation correctly by:
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 "$@"