@the-bearded-bear/claude-craft 8.2.4 → 8.2.5
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/Dev/scripts/pack-repo-fallback.sh +23 -6
- package/cli/lib/update.js +62 -20
- package/package.json +1 -1
|
@@ -39,27 +39,44 @@ if [[ "$FORMAT" != "markdown" && "$FORMAT" != "plain" ]]; then
|
|
|
39
39
|
exit 1
|
|
40
40
|
fi
|
|
41
41
|
|
|
42
|
+
# Validate --output: relative path only, no traversal, no shell metachars
|
|
43
|
+
if [[ "$OUTPUT" = /* ]] || [[ "$OUTPUT" == *".."* ]] || [[ "$OUTPUT" =~ [[:space:]\;\|\&\$\`\(\)\<\>] ]]; then
|
|
44
|
+
echo "❌ Invalid --output: must be a relative path without '..' or shell metacharacters" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Validate --exclude and --include: no shell metachars (prevents eval/grep injection)
|
|
49
|
+
if [[ -n "$EXCLUDE_EXTRA" && "$EXCLUDE_EXTRA" =~ [[:space:]\;\|\&\$\`\(\)\<\>] ]]; then
|
|
50
|
+
echo "❌ Invalid --exclude: shell metacharacters are not allowed" >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
if [[ -n "$INCLUDE" && "$INCLUDE" =~ [[:space:]\;\|\&\$\`\(\)\<\>] ]]; then
|
|
54
|
+
echo "❌ Invalid --include: shell metacharacters are not allowed" >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
42
58
|
echo "📦 Pack repo (fallback shell) → $OUTPUT"
|
|
43
59
|
echo " Format: $FORMAT | Root: $(pwd)"
|
|
44
60
|
|
|
45
|
-
# Build find
|
|
46
|
-
|
|
61
|
+
# Build find args as an array (no eval, no injection)
|
|
62
|
+
FIND_ARGS=()
|
|
47
63
|
for excl in "${DEFAULT_EXCLUDES[@]}"; do
|
|
48
|
-
|
|
64
|
+
FIND_ARGS+=(-not -path "*/$excl/*" -not -path "*/$excl")
|
|
49
65
|
done
|
|
50
66
|
if [[ -n "$EXCLUDE_EXTRA" ]]; then
|
|
51
|
-
|
|
67
|
+
FIND_ARGS+=(-not -path "*$EXCLUDE_EXTRA*")
|
|
52
68
|
fi
|
|
53
69
|
|
|
54
70
|
# Collect files — respect .gitignore si disponible
|
|
55
71
|
if command -v git &>/dev/null && git rev-parse --git-dir &>/dev/null; then
|
|
56
72
|
FILES=$(git ls-files --cached --others --exclude-standard 2>/dev/null | grep -Ev "\.($BINARY_EXTS)$" || true)
|
|
57
73
|
else
|
|
58
|
-
FILES=$(
|
|
74
|
+
FILES=$(find . -type f "${FIND_ARGS[@]}" | grep -Ev "\.($BINARY_EXTS)$" | sed 's|^\./||')
|
|
59
75
|
fi
|
|
60
76
|
|
|
61
77
|
if [[ -n "$INCLUDE" ]]; then
|
|
62
|
-
|
|
78
|
+
# timeout on grep to prevent ReDoS
|
|
79
|
+
FILES=$(echo "$FILES" | timeout 5 grep -E "$INCLUDE" || true)
|
|
63
80
|
fi
|
|
64
81
|
|
|
65
82
|
FILE_COUNT=$(echo "$FILES" | grep -c . || echo 0)
|
package/cli/lib/update.js
CHANGED
|
@@ -5,11 +5,46 @@
|
|
|
5
5
|
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
import path from 'path';
|
|
8
|
-
import {
|
|
8
|
+
import { spawnSync } from 'child_process';
|
|
9
9
|
import c from './colors.js';
|
|
10
10
|
import { listDirs } from './fs-utils.js';
|
|
11
11
|
import { TECH_REGISTRY } from './tech-registry.js';
|
|
12
12
|
|
|
13
|
+
// Security: reject paths into system directories to prevent accidental or malicious
|
|
14
|
+
// installation outside the user's expected workspace.
|
|
15
|
+
const FORBIDDEN_SYSTEM_DIRS = [
|
|
16
|
+
'/',
|
|
17
|
+
'/etc',
|
|
18
|
+
'/usr',
|
|
19
|
+
'/bin',
|
|
20
|
+
'/sbin',
|
|
21
|
+
'/boot',
|
|
22
|
+
'/lib',
|
|
23
|
+
'/var',
|
|
24
|
+
'/root',
|
|
25
|
+
'/proc',
|
|
26
|
+
'/sys',
|
|
27
|
+
'/dev',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function assertSafeTarget(targetPath) {
|
|
31
|
+
const resolved = path.resolve(targetPath);
|
|
32
|
+
for (const forbidden of FORBIDDEN_SYSTEM_DIRS) {
|
|
33
|
+
if (resolved === forbidden || resolved.startsWith(forbidden + path.sep)) {
|
|
34
|
+
throw new Error(`Refusing to operate on system directory: ${resolved}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return resolved;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Security: enforce allowlist on language code (prevents argument injection via --lang).
|
|
41
|
+
function assertSafeLang(lang) {
|
|
42
|
+
if (!/^[a-z]{2}$/.test(lang)) {
|
|
43
|
+
throw new Error(`Invalid --lang value: "${lang}" (expected 2-letter lowercase code)`);
|
|
44
|
+
}
|
|
45
|
+
return lang;
|
|
46
|
+
}
|
|
47
|
+
|
|
13
48
|
/**
|
|
14
49
|
* Run the update command against a target directory.
|
|
15
50
|
* @param {string} targetPath - Absolute path to the project directory
|
|
@@ -19,11 +54,14 @@ import { TECH_REGISTRY } from './tech-registry.js';
|
|
|
19
54
|
* @param {string} cliRoot - Path to the CLI package root
|
|
20
55
|
*/
|
|
21
56
|
function runUpdate(targetPath, options, cliRoot) {
|
|
22
|
-
|
|
23
|
-
const
|
|
57
|
+
// Security: validate inputs before any side effect (CWE-78, CWE-22).
|
|
58
|
+
const safeTarget = assertSafeTarget(targetPath);
|
|
59
|
+
const lang = assertSafeLang(options.lang || 'en');
|
|
60
|
+
|
|
61
|
+
const claudeDir = path.join(safeTarget, '.claude');
|
|
24
62
|
|
|
25
63
|
console.log(`\n${c.bold}Claude Craft Update${c.reset}`);
|
|
26
|
-
console.log(`${c.dim}Directory: ${
|
|
64
|
+
console.log(`${c.dim}Directory: ${safeTarget}${c.reset}\n`);
|
|
27
65
|
|
|
28
66
|
// Verify existing installation
|
|
29
67
|
if (!fs.existsSync(claudeDir)) {
|
|
@@ -60,16 +98,17 @@ function runUpdate(targetPath, options, cliRoot) {
|
|
|
60
98
|
|
|
61
99
|
if (fs.existsSync(commonScript)) {
|
|
62
100
|
console.log(` ${c.cyan}Refreshing common rules...${c.reset}`);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
101
|
+
// Security: spawnSync with argv array — no shell interpretation, no injection.
|
|
102
|
+
const result = spawnSync('bash', [commonScript, `--lang=${lang}`, '--force', safeTarget], {
|
|
103
|
+
encoding: 'utf8',
|
|
104
|
+
timeout: 60_000,
|
|
105
|
+
stdio: 'pipe',
|
|
106
|
+
});
|
|
107
|
+
if (result.status === 0) {
|
|
69
108
|
console.log(` ${c.green}[OK]${c.reset} Common rules updated`);
|
|
70
109
|
updated++;
|
|
71
|
-
}
|
|
72
|
-
console.log(` ${c.red}[FAIL]${c.reset} Common rules: ${
|
|
110
|
+
} else {
|
|
111
|
+
console.log(` ${c.red}[FAIL]${c.reset} Common rules: ${result.stderr || result.error?.message || 'unknown'}`);
|
|
73
112
|
}
|
|
74
113
|
}
|
|
75
114
|
|
|
@@ -84,16 +123,19 @@ function runUpdate(targetPath, options, cliRoot) {
|
|
|
84
123
|
}
|
|
85
124
|
|
|
86
125
|
console.log(` ${c.cyan}Refreshing ${entry.displayName}...${c.reset}`);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
126
|
+
// Security: spawnSync with argv array — no shell interpretation, no injection.
|
|
127
|
+
const result = spawnSync('bash', [script, `--lang=${lang}`, '--force', safeTarget], {
|
|
128
|
+
encoding: 'utf8',
|
|
129
|
+
timeout: 60_000,
|
|
130
|
+
stdio: 'pipe',
|
|
131
|
+
});
|
|
132
|
+
if (result.status === 0) {
|
|
93
133
|
console.log(` ${c.green}[OK]${c.reset} ${entry.displayName} updated`);
|
|
94
134
|
updated++;
|
|
95
|
-
}
|
|
96
|
-
console.log(
|
|
135
|
+
} else {
|
|
136
|
+
console.log(
|
|
137
|
+
` ${c.red}[FAIL]${c.reset} ${entry.displayName}: ${result.stderr || result.error?.message || 'unknown'}`
|
|
138
|
+
);
|
|
97
139
|
}
|
|
98
140
|
}
|
|
99
141
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-bearded-bear/claude-craft",
|
|
3
|
-
"version": "8.2.
|
|
3
|
+
"version": "8.2.5",
|
|
4
4
|
"description": "A comprehensive framework for AI-assisted development with Claude Code. Install standardized rules, agents, and commands for your projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "cli/index.js",
|