@claude-flow/cli 3.32.38 → 3.32.40
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/.proven-config-version +1 -0
- package/.claude/agents/v3/security-architect-aidefence.md +1 -1
- package/.claude/agents/v3/security-architect.md +2 -2
- package/.claude/helpers/.helpers-version +1 -1
- package/.claude/helpers/helpers.manifest.json +2 -2
- package/.claude/helpers/statusline.cjs +0 -0
- package/.claude/proven-config.json +42 -0
- package/catalog-manifest.json +2 -2
- package/dist/src/commands/announcements.js +0 -0
- package/dist/src/commands/security.js +91 -8
- package/dist/src/funnel/insights.js +1 -1
- package/dist/src/funnel/messages.js +1 -1
- package/dist/src/init/claudemd-generator.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319
|
|
@@ -140,7 +140,7 @@ hooks:
|
|
|
140
140
|
# ═══════════════════════════════════════════════════════════════
|
|
141
141
|
echo "🔒 Running comprehensive security validation..."
|
|
142
142
|
|
|
143
|
-
npx claude-flow@v3alpha security scan --depth
|
|
143
|
+
npx claude-flow@v3alpha security scan --depth deep --output-format json > /tmp/security-scan.json 2>/dev/null
|
|
144
144
|
VULNERABILITIES=$(jq -r '.vulnerabilities | length' /tmp/security-scan.json 2>/dev/null || echo "0")
|
|
145
145
|
CRITICAL_COUNT=$(jq -r '.vulnerabilities | map(select(.severity == "critical")) | length' /tmp/security-scan.json 2>/dev/null || echo "0")
|
|
146
146
|
HIGH_COUNT=$(jq -r '.vulnerabilities | map(select(.severity == "high")) | length' /tmp/security-scan.json 2>/dev/null || echo "0")
|
|
@@ -58,7 +58,7 @@ hooks:
|
|
|
58
58
|
echo "✅ Security architecture analysis complete"
|
|
59
59
|
|
|
60
60
|
# 1. Run comprehensive security validation
|
|
61
|
-
npx claude-flow@v3alpha security scan --depth
|
|
61
|
+
npx claude-flow@v3alpha security scan --depth deep --output-format json > /tmp/security-scan.json 2>/dev/null
|
|
62
62
|
VULNERABILITIES=$(jq -r '.vulnerabilities | length' /tmp/security-scan.json 2>/dev/null || echo "0")
|
|
63
63
|
CRITICAL_COUNT=$(jq -r '.vulnerabilities | map(select(.severity == "critical")) | length' /tmp/security-scan.json 2>/dev/null || echo "0")
|
|
64
64
|
|
|
@@ -834,7 +834,7 @@ mcp__claude-flow__memory_usage({
|
|
|
834
834
|
|
|
835
835
|
```bash
|
|
836
836
|
# Full security scan
|
|
837
|
-
npx claude-flow@v3alpha security scan --depth
|
|
837
|
+
npx claude-flow@v3alpha security scan --depth deep
|
|
838
838
|
|
|
839
839
|
# CVE-specific checks
|
|
840
840
|
npx claude-flow@v3alpha security cve --check CVE-2024-001
|
|
@@ -1 +1 @@
|
|
|
1
|
-
3.32.
|
|
1
|
+
3.32.40
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.40",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "68be7e9a9eba7bf9c4e8a230db7bf61a243b965639f8504842799d6c6ca28762",
|
|
6
6
|
"hook-handler.cjs": "dae295fb9ae2626b89899c19a20cc911541af82b52d2eeb9b214d618b96e9a86",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"statusline.cjs": "0457fe53f8cd2c56458ff178392536a5868efd1a573665fa43bc01d2d95ca677"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"signature": "
|
|
11
|
+
"signature": "LKhT8u+7Osi/g/JGxIupJ26jkWtAi7RRh/RLPp/DplCdVEKcP6iTgWRYkBJ1flZNsAJGDkDpGfPbSWzLz3JcAg==",
|
|
12
12
|
"algorithm": "ed25519"
|
|
13
13
|
}
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adoptedAt": 1785415360835,
|
|
3
|
+
"championId": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
|
|
4
|
+
"manifest": {
|
|
5
|
+
"schema": "ruflo.proven-config/v1",
|
|
6
|
+
"policy": {
|
|
7
|
+
"ref": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
|
|
8
|
+
"value": {
|
|
9
|
+
"alpha": 0.3,
|
|
10
|
+
"subjectWeight": 1,
|
|
11
|
+
"mmrLambda": 0.5,
|
|
12
|
+
"bodyWeight": 1.5,
|
|
13
|
+
"typePenaltyFactor": 0.5
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"layer": "framework/node-cli",
|
|
17
|
+
"compatibility": {
|
|
18
|
+
"ruflo": ">=3.24.0"
|
|
19
|
+
},
|
|
20
|
+
"benchmark": {
|
|
21
|
+
"corpus": "ADR-081-labelled-v1",
|
|
22
|
+
"corpusHash": "sha256:2f700b5c363e20a3bd88ce2bc9b87bbbbaa61732c6177894c6ec37890f888982"
|
|
23
|
+
},
|
|
24
|
+
"receipt": {
|
|
25
|
+
"heldOutDelta": 0.07381404928570845,
|
|
26
|
+
"redblue": "PASS",
|
|
27
|
+
"drift": 0,
|
|
28
|
+
"canary": {
|
|
29
|
+
"rollbackRate": 0,
|
|
30
|
+
"latencyP95": 244.612458000076,
|
|
31
|
+
"costPerTask": 0
|
|
32
|
+
},
|
|
33
|
+
"receiptCoverage": 1
|
|
34
|
+
},
|
|
35
|
+
"platform": [
|
|
36
|
+
"linux",
|
|
37
|
+
"macOS",
|
|
38
|
+
"windows"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"previous": ""
|
|
42
|
+
}
|
package/catalog-manifest.json
CHANGED
|
Binary file
|
|
@@ -6,15 +6,51 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { output } from '../output.js';
|
|
8
8
|
import { execSync } from 'node:child_process';
|
|
9
|
+
import { existsSync, statSync } from 'node:fs';
|
|
10
|
+
import { resolve as resolvePath } from 'node:path';
|
|
9
11
|
import { createBuiltinAIDefence } from '../security/builtin-aidefence.js';
|
|
12
|
+
// Accepted values for `security scan`'s enum flags — the single source of truth
|
|
13
|
+
// for both validation and the traversal-depth maps below.
|
|
14
|
+
const SCAN_DEPTHS = ['quick', 'standard', 'deep'];
|
|
15
|
+
const SCAN_TYPES = ['code', 'deps', 'all'];
|
|
16
|
+
// Real type predicates, not `as` casts. Array.includes() does not narrow a
|
|
17
|
+
// string to a literal union on its own, so without these the depth-map lookups
|
|
18
|
+
// below need an unchecked assertion — and an unchecked assertion would let a
|
|
19
|
+
// future refactor index the maps with an invalid key, yielding `undefined`.
|
|
20
|
+
// That matters: `undefined <= 0` is false and `undefined - 1` is NaN, so the
|
|
21
|
+
// recursion guard in scanDir would never fire. An unsafe cast here would
|
|
22
|
+
// silently disable the depth limiter — the exact class of failure this command
|
|
23
|
+
// is being fixed for.
|
|
24
|
+
const isScanDepth = (v) => SCAN_DEPTHS.includes(v);
|
|
25
|
+
const isScanType = (v) => SCAN_TYPES.includes(v);
|
|
26
|
+
// `full` was never a supported depth, but the CLI itself printed it — the
|
|
27
|
+
// statusline insight, the announcement, the release-notes blurb, the CLAUDE.md
|
|
28
|
+
// that `init` generates, and two shipped agent definitions all tell people to
|
|
29
|
+
// run `security scan --depth full`. Pre-fix it silently fell through to the
|
|
30
|
+
// SHALLOWEST traversal, which is the bug. Hard-rejecting it would break every
|
|
31
|
+
// caller we ourselves told to use it, so it is normalised to the depth the word
|
|
32
|
+
// promised, with a warning. Remove once those emitters have aged out.
|
|
33
|
+
const DEPRECATED_SCAN_DEPTHS = { full: 'deep' };
|
|
34
|
+
// `container` has been advertised in --type's help since this command was
|
|
35
|
+
// written, but no phase below implements it. Accepting it would reproduce the
|
|
36
|
+
// exact bug this validation exists to fix: a documented flag value that scans
|
|
37
|
+
// nothing and still prints a clean bill of health. Rejected explicitly, with
|
|
38
|
+
// its own message, until a container phase exists.
|
|
39
|
+
const UNIMPLEMENTED_SCAN_TYPES = ['container'];
|
|
40
|
+
// Directory-recursion limits per depth. Exhaustive records rather than chained
|
|
41
|
+
// ternaries, so adding a depth is a compile error here instead of a silently
|
|
42
|
+
// shallower scan. CODE_SCAN_DEPTH.quick is unreachable — phase 3 is gated on
|
|
43
|
+
// depth !== 'quick' — but is present so the record stays total.
|
|
44
|
+
const SECRET_SCAN_DEPTH = { quick: 3, standard: 5, deep: 10 };
|
|
45
|
+
const CODE_SCAN_DEPTH = { quick: 0, standard: 5, deep: 10 };
|
|
10
46
|
// Scan subcommand
|
|
11
47
|
const scanCommand = {
|
|
12
48
|
name: 'scan',
|
|
13
|
-
description: 'Run security scan on target (code, dependencies
|
|
49
|
+
description: 'Run security scan on target (code, dependencies)',
|
|
14
50
|
options: [
|
|
15
51
|
{ name: 'target', short: 't', type: 'string', description: 'Target path or URL to scan', default: '.' },
|
|
16
52
|
{ name: 'depth', short: 'd', type: 'string', description: 'Scan depth: quick, standard, deep', default: 'standard' },
|
|
17
|
-
{ name: 'type', type: 'string', description: 'Scan type: code, deps,
|
|
53
|
+
{ name: 'type', type: 'string', description: 'Scan type: code, deps, all', default: 'all' },
|
|
18
54
|
{ name: 'output', short: 'o', type: 'string', description: 'Output format: text, json, sarif', default: 'text' },
|
|
19
55
|
{ name: 'fix', short: 'f', type: 'boolean', description: 'Auto-fix vulnerabilities where possible' },
|
|
20
56
|
],
|
|
@@ -24,9 +60,52 @@ const scanCommand = {
|
|
|
24
60
|
],
|
|
25
61
|
action: async (ctx) => {
|
|
26
62
|
const target = ctx.flags.target || '.';
|
|
27
|
-
const
|
|
63
|
+
const requestedDepth = ctx.flags.depth || 'standard';
|
|
28
64
|
const scanType = ctx.flags.type || 'all';
|
|
29
65
|
const fix = ctx.flags.fix;
|
|
66
|
+
// A security scanner must never silently degrade on an unrecognised enum
|
|
67
|
+
// value. An unknown --depth used to fall through to the shallowest
|
|
68
|
+
// traversal (so `--depth full` scanned *less* than the default), and an
|
|
69
|
+
// unknown --type skipped every phase while still reporting "No security
|
|
70
|
+
// issues found!" with exit 0 — a typo was indistinguishable from a clean
|
|
71
|
+
// result, and it silently disabled the critical/high exit-code gate.
|
|
72
|
+
// Fail closed instead, before anything is printed or scanned.
|
|
73
|
+
const aliasedDepth = DEPRECATED_SCAN_DEPTHS[requestedDepth];
|
|
74
|
+
if (aliasedDepth) {
|
|
75
|
+
output.printWarning(`--depth '${requestedDepth}' is deprecated and has been treated as '${aliasedDepth}'. ` +
|
|
76
|
+
`Use one of: ${SCAN_DEPTHS.join(', ')}.`);
|
|
77
|
+
}
|
|
78
|
+
const candidateDepth = aliasedDepth ?? requestedDepth;
|
|
79
|
+
if (!isScanDepth(candidateDepth)) {
|
|
80
|
+
output.printError(`Invalid --depth '${requestedDepth}'. Expected one of: ${SCAN_DEPTHS.join(', ')}.`);
|
|
81
|
+
return { success: false, exitCode: 1 };
|
|
82
|
+
}
|
|
83
|
+
const depth = candidateDepth;
|
|
84
|
+
// Case-insensitive so `--type Container` gets the accurate "not implemented"
|
|
85
|
+
// message rather than being reported as a misspelling.
|
|
86
|
+
if (UNIMPLEMENTED_SCAN_TYPES.includes(scanType.toLowerCase())) {
|
|
87
|
+
output.printError(`--type '${scanType}' is not implemented yet. Expected one of: ${SCAN_TYPES.join(', ')}.`);
|
|
88
|
+
return { success: false, exitCode: 1 };
|
|
89
|
+
}
|
|
90
|
+
if (!isScanType(scanType)) {
|
|
91
|
+
output.printError(`Invalid --type '${scanType}'. Expected one of: ${SCAN_TYPES.join(', ')}.`);
|
|
92
|
+
return { success: false, exitCode: 1 };
|
|
93
|
+
}
|
|
94
|
+
// --target names WHAT gets scanned, and was never validated. A path that
|
|
95
|
+
// does not exist (or is a file, not a directory) made every phase read
|
|
96
|
+
// nothing, and the swallowed dir-read catches turned that into zero
|
|
97
|
+
// findings, the clean banner, exit 0 — and a PERSISTED clean report that
|
|
98
|
+
// getSecurityStatus then reports as CLEAN. Same fail-open class as the enum
|
|
99
|
+
// flags, and the likelier typo of the two, so it fails closed too.
|
|
100
|
+
const resolvedTarget = resolvePath(target);
|
|
101
|
+
if (!existsSync(resolvedTarget)) {
|
|
102
|
+
output.printError(`Target does not exist: ${resolvedTarget}`);
|
|
103
|
+
return { success: false, exitCode: 1 };
|
|
104
|
+
}
|
|
105
|
+
if (!statSync(resolvedTarget).isDirectory()) {
|
|
106
|
+
output.printError(`Target is not a directory: ${resolvedTarget}`);
|
|
107
|
+
return { success: false, exitCode: 1 };
|
|
108
|
+
}
|
|
30
109
|
output.writeln();
|
|
31
110
|
output.writeln(output.bold('Security Scan'));
|
|
32
111
|
output.writeln(output.dim('─'.repeat(50)));
|
|
@@ -98,7 +177,9 @@ const scanCommand = {
|
|
|
98
177
|
{ pattern: /password\s*[:=]\s*['"][^'"]{8,}['"]/gi, type: 'Hardcoded Password' },
|
|
99
178
|
];
|
|
100
179
|
const scanDir = (dir, depthLimit) => {
|
|
101
|
-
|
|
180
|
+
// Positive-test rather than `<= 0`: undefined and NaN both fail this,
|
|
181
|
+
// so a bad budget stops the recursion instead of disabling the limiter.
|
|
182
|
+
if (!(depthLimit > 0))
|
|
102
183
|
return;
|
|
103
184
|
try {
|
|
104
185
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -134,7 +215,7 @@ const scanCommand = {
|
|
|
134
215
|
}
|
|
135
216
|
catch { /* dir read error */ }
|
|
136
217
|
};
|
|
137
|
-
const scanDepth = depth
|
|
218
|
+
const scanDepth = SECRET_SCAN_DEPTH[depth];
|
|
138
219
|
scanDir(path.resolve(target), scanDepth);
|
|
139
220
|
}
|
|
140
221
|
// Phase 3: Check for common security issues in code
|
|
@@ -148,7 +229,9 @@ const scanCommand = {
|
|
|
148
229
|
{ pattern: /\$\{.*\}.*sql|sql.*\$\{/gi, type: 'SQL Injection', severity: 'high', desc: 'Possible SQL injection' },
|
|
149
230
|
];
|
|
150
231
|
const scanCodeDir = (dir, depthLimit) => {
|
|
151
|
-
|
|
232
|
+
// Positive-test rather than `<= 0`: undefined and NaN both fail this,
|
|
233
|
+
// so a bad budget stops the recursion instead of disabling the limiter.
|
|
234
|
+
if (!(depthLimit > 0))
|
|
152
235
|
return;
|
|
153
236
|
try {
|
|
154
237
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -187,7 +270,7 @@ const scanCommand = {
|
|
|
187
270
|
}
|
|
188
271
|
catch { /* dir read error */ }
|
|
189
272
|
};
|
|
190
|
-
const scanDepth = depth
|
|
273
|
+
const scanDepth = CODE_SCAN_DEPTH[depth];
|
|
191
274
|
scanCodeDir(path.resolve(target), scanDepth);
|
|
192
275
|
}
|
|
193
276
|
spinner.succeed('Scan complete');
|
|
@@ -1222,7 +1305,7 @@ export const securityCommand = {
|
|
|
1222
1305
|
output.writeln();
|
|
1223
1306
|
output.writeln('Subcommands:');
|
|
1224
1307
|
output.printList([
|
|
1225
|
-
'scan - Run security scans on code, deps
|
|
1308
|
+
'scan - Run security scans on code, deps',
|
|
1226
1309
|
'cve - Check and manage CVE vulnerabilities',
|
|
1227
1310
|
'threats - Threat modeling (STRIDE, DREAD, PASTA)',
|
|
1228
1311
|
'audit - Security audit logging and compliance',
|
|
@@ -51,7 +51,7 @@ function securityInsight(ctx) {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
if (s.status === 'PENDING') {
|
|
54
|
-
return { id: 'insight-scan-pending', text: '🛡 Security scan pending — Run ruflo security scan --depth
|
|
54
|
+
return { id: 'insight-scan-pending', text: '🛡 Security scan pending — Run ruflo security scan --depth deep', priority: 70 };
|
|
55
55
|
}
|
|
56
56
|
return null;
|
|
57
57
|
}
|
|
@@ -158,7 +158,7 @@ export const MESSAGES = [
|
|
|
158
158
|
schemaVersion: 1,
|
|
159
159
|
id: 'local.edu.security-scan',
|
|
160
160
|
class: 'educational',
|
|
161
|
-
text: '🔒 ruflo security scan --depth
|
|
161
|
+
text: '🔒 ruflo security scan --depth deep — audits dependencies and config',
|
|
162
162
|
url: 'https://cognitum.one/docs/security',
|
|
163
163
|
},
|
|
164
164
|
{
|
|
@@ -247,7 +247,7 @@ function securitySection() {
|
|
|
247
247
|
- Always use parameterized queries (prevent injection)
|
|
248
248
|
|
|
249
249
|
\`\`\`bash
|
|
250
|
-
npx @claude-flow/cli@latest security scan --depth
|
|
250
|
+
npx @claude-flow/cli@latest security scan --depth deep
|
|
251
251
|
npx @claude-flow/cli@latest security audit --report
|
|
252
252
|
\`\`\`
|
|
253
253
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.40",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|