torusguard 1.3.5 → 1.4.0
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/.torusguard/.manifest.json +37 -36
- package/.torusguard/runs/report-latest.html +5862 -315
- package/.torusguard/runs/results-latest.sarif +20 -0
- package/.torusguard/runs/run-20260918-104221-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260918-104221-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260918-104221-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260918-104221-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260918-104236-audit/findings.json +2314 -0
- package/.torusguard/runs/run-20260918-104236-audit/findings.md +960 -0
- package/.torusguard/runs/run-20260918-104236-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260918-104236-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260918-105723-audit/findings.json +2382 -0
- package/.torusguard/runs/run-20260918-105723-audit/findings.md +960 -0
- package/.torusguard/runs/run-20260918-105723-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260918-105723-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260918-105731-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260918-105731-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260918-105731-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260918-105731-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260918-105940-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260918-105940-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260918-105940-audit/manifest.json +13 -0
- package/.torusguard/runs/run-20260918-105940-audit/remediation.md +7 -0
- package/.torusguard/runs/run-20260918-105940-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-145701-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-145701-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-145701-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-145701-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-151729-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-151729-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-151729-audit/manifest.json +13 -0
- package/.torusguard/runs/run-20260919-151729-audit/remediation.md +7 -0
- package/.torusguard/runs/run-20260919-151729-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-152340-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-152340-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-152340-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-152340-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-152345-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-152345-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-152345-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-152345-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-153500-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-153500-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-153500-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-153500-audit/summary.md +5 -0
- package/.torusguard/scripts/__pycache__/apply_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/diff_guard.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/finding_scorer.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/harden_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/memory_engine.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/recheck_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/recipes_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/run_manager.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/sarif_exporter.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/stack_detect.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
- package/.torusguard/scripts/apply_runner.py +108 -9
- package/.torusguard/scripts/audit_runner.py +336 -24
- package/.torusguard/scripts/harden_runner.py +124 -70
- package/.torusguard/scripts/html_reporter.py +3585 -648
- package/.torusguard/scripts/manifest_builder.py +2 -0
- package/.torusguard/scripts/recheck_runner.py +5 -4
- package/.torusguard/scripts/recipes_runner.py +91 -8
- package/.torusguard/scripts/report_sync.py +496 -73
- package/.torusguard/scripts/sarif_exporter.py +48 -8
- package/.torusguard/scripts/stack_detect.py +44 -2
- package/.torusguard/scripts/status_runner.py +267 -0
- package/.torusguard/scripts/term_ui.py +1 -1
- package/.torusguard/skills/torusguard/SKILL.md +75 -72
- package/.torusguard/skills/torusguard-apply/SKILL.md +84 -80
- package/.torusguard/skills/torusguard-audit/SKILL.md +87 -83
- package/.torusguard/skills/torusguard-authorize/SKILL.md +7 -2
- package/.torusguard/skills/torusguard-exploit-check/SKILL.md +7 -2
- package/.torusguard/skills/torusguard-full/SKILL.md +7 -2
- package/.torusguard/skills/torusguard-harden/SKILL.md +98 -94
- package/.torusguard/skills/torusguard-init/SKILL.md +68 -64
- package/.torusguard/skills/torusguard-recheck/SKILL.md +81 -77
- package/.torusguard/skills/torusguard-report/SKILL.md +93 -72
- package/.torusguard/skills/torusguard-status/SKILL.md +62 -58
- package/.torusguard/skills/torusguard-verify/SKILL.md +7 -2
- package/.torusguard/skills/torusguard-web-validate/SKILL.md +7 -2
- package/.torusguard/workflows/apply.md +1 -1
- package/.torusguard/workflows/audit.md +1 -1
- package/.torusguard/workflows/authorize.md +1 -1
- package/.torusguard/workflows/exploit-check.md +1 -1
- package/.torusguard/workflows/harden.md +1 -1
- package/.torusguard/workflows/init.md +1 -1
- package/.torusguard/workflows/memory.md +1 -1
- package/.torusguard/workflows/recheck.md +1 -1
- package/.torusguard/workflows/report.md +1 -1
- package/.torusguard/workflows/status.md +1 -1
- package/.torusguard/workflows/verify.md +1 -1
- package/.torusguard/workflows/web-validate.md +1 -1
- package/README.md +115 -81
- package/bin/torusguard.js +244 -38
- package/package.json +6 -2
- package/skills/torusguard/SKILL.md +1 -1
- package/skills/torusguard/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/skills/torusguard/bootstrap.py +52 -8
- package/skills/torusguard/payload/.manifest.json +51 -36
- package/skills/torusguard/payload/scripts/__pycache__/apply_runner.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/audit_runner.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/diff_guard.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/finding_scorer.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/harden_runner.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/html_reporter.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/memory_engine.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/monorepo_detector.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/recheck_runner.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/report_sync.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/rules_sync.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/run_manager.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/run_manager.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/sarif_exporter.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/stack_detect.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/apply_runner.py +108 -9
- package/skills/torusguard/payload/scripts/audit_runner.py +336 -24
- package/skills/torusguard/payload/scripts/harden_runner.py +124 -70
- package/skills/torusguard/payload/scripts/html_reporter.py +3585 -648
- package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
- package/skills/torusguard/payload/scripts/recheck_runner.py +5 -4
- package/skills/torusguard/payload/scripts/recipes_runner.py +91 -8
- package/skills/torusguard/payload/scripts/report_sync.py +496 -73
- package/skills/torusguard/payload/scripts/sarif_exporter.py +48 -8
- package/skills/torusguard/payload/scripts/stack_detect.py +44 -2
- package/skills/torusguard/payload/scripts/status_runner.py +267 -0
- package/skills/torusguard/payload/scripts/term_ui.py +1 -1
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-apply/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-authorize/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-exploit-check/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-full/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-init/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-report/SKILL.md +40 -23
- package/skills/torusguard/payload/skills/torusguard-status/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-verify/SKILL.md +1 -1
- package/skills/torusguard/payload/skills/torusguard-web-validate/SKILL.md +1 -1
- package/skills/torusguard/payload/workflows/apply.md +9 -1
- package/skills/torusguard/payload/workflows/audit.md +8 -2
- package/skills/torusguard/payload/workflows/authorize.md +1 -1
- package/skills/torusguard/payload/workflows/exploit-check.md +1 -1
- package/skills/torusguard/payload/workflows/harden.md +6 -1
- package/skills/torusguard/payload/workflows/init.md +7 -1
- package/skills/torusguard/payload/workflows/memory.md +1 -1
- package/skills/torusguard/payload/workflows/recheck.md +1 -1
- package/skills/torusguard/payload/workflows/recipes.md +55 -0
- package/skills/torusguard/payload/workflows/report.md +59 -55
- package/skills/torusguard/payload/workflows/status.md +4 -1
- package/skills/torusguard/payload/workflows/torusguard-apply.md +110 -0
- package/skills/torusguard/payload/workflows/torusguard-audit.md +105 -0
- package/skills/torusguard/payload/workflows/torusguard-authorize.md +96 -0
- package/skills/torusguard/payload/workflows/torusguard-exploit-check.md +98 -0
- package/skills/torusguard/payload/workflows/torusguard-harden.md +104 -0
- package/skills/torusguard/payload/workflows/torusguard-init.md +106 -0
- package/skills/torusguard/payload/workflows/torusguard-recheck.md +101 -0
- package/skills/torusguard/payload/workflows/torusguard-recipes.md +55 -0
- package/skills/torusguard/payload/workflows/torusguard-report.md +105 -0
- package/skills/torusguard/payload/workflows/torusguard-status.md +103 -0
- package/skills/torusguard/payload/workflows/torusguard-verify.md +100 -0
- package/skills/torusguard/payload/workflows/torusguard-web-validate.md +96 -0
- package/skills/torusguard/payload/workflows/torusguard.md +19 -0
- package/skills/torusguard/payload/workflows/verify.md +1 -1
- package/skills/torusguard/payload/workflows/web-validate.md +1 -1
- package/skills/torusguard-apply/SKILL.md +1 -1
- package/skills/torusguard-audit/SKILL.md +1 -1
- package/skills/torusguard-authorize/SKILL.md +1 -1
- package/skills/torusguard-exploit-check/SKILL.md +1 -1
- package/skills/torusguard-full/SKILL.md +1 -1
- package/skills/torusguard-harden/SKILL.md +1 -1
- package/skills/torusguard-init/SKILL.md +1 -1
- package/skills/torusguard-recheck/SKILL.md +1 -1
- package/skills/torusguard-report/SKILL.md +40 -23
- package/skills/torusguard-status/SKILL.md +1 -1
- package/skills/torusguard-verify/SKILL.md +1 -1
- package/skills/torusguard-web-validate/SKILL.md +1 -1
package/bin/torusguard.js
CHANGED
|
@@ -15,6 +15,51 @@ const command = args[0] || 'init';
|
|
|
15
15
|
const rootDir = path.resolve(__dirname, '..');
|
|
16
16
|
const cwd = process.cwd();
|
|
17
17
|
|
|
18
|
+
// Parse version flag immediately
|
|
19
|
+
if (command === '--version' || command === '-v' || command === 'version') {
|
|
20
|
+
let ver = '1.4.0';
|
|
21
|
+
try {
|
|
22
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8'));
|
|
23
|
+
ver = pkg.version || ver;
|
|
24
|
+
} catch (e) {}
|
|
25
|
+
console.log(`torusguard v${ver}`);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseTargetAndArgs(cliArgs) {
|
|
30
|
+
let target = '.';
|
|
31
|
+
const remaining = [];
|
|
32
|
+
for (let i = 1; i < cliArgs.length; i++) {
|
|
33
|
+
const a = cliArgs[i];
|
|
34
|
+
if (a === '--target' || a === '-t' || a === '--root') {
|
|
35
|
+
if (i + 1 < cliArgs.length) {
|
|
36
|
+
target = cliArgs[i + 1];
|
|
37
|
+
i++;
|
|
38
|
+
}
|
|
39
|
+
} else if (a.startsWith('--target=') || a.startsWith('--root=')) {
|
|
40
|
+
target = a.split('=')[1];
|
|
41
|
+
} else {
|
|
42
|
+
remaining.push(a);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (target === '.' && remaining.length > 0 && !remaining[0].startsWith('-')) {
|
|
46
|
+
target = remaining.shift();
|
|
47
|
+
}
|
|
48
|
+
return { target, remaining };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function compareSemver(a, b) {
|
|
52
|
+
const pa = a.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0);
|
|
53
|
+
const pb = b.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0);
|
|
54
|
+
for (let i = 0; i < 3; i++) {
|
|
55
|
+
const na = pa[i] || 0;
|
|
56
|
+
const nb = pb[i] || 0;
|
|
57
|
+
if (na > nb) return 1;
|
|
58
|
+
if (na < nb) return -1;
|
|
59
|
+
}
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
18
63
|
// ─── ANSI Color Helpers ───────────────────────────────────────────────────────
|
|
19
64
|
const BOLD = '\x1b[1m';
|
|
20
65
|
const DIM = '\x1b[2m';
|
|
@@ -151,7 +196,7 @@ function cardDivider(title = '', borderColor = CYAN, double = false) {
|
|
|
151
196
|
return ` ${borderColor}${left}${h.repeat(71)}${right}${RESET}`;
|
|
152
197
|
}
|
|
153
198
|
|
|
154
|
-
function cardHeader(title, subtitle = '', version = 'v1.3.
|
|
199
|
+
function cardHeader(title, subtitle = '', version = 'v1.3.6', borderColor = CYAN) {
|
|
155
200
|
const top = ` ${borderColor}╭${'─'.repeat(71)}╮${RESET}`;
|
|
156
201
|
const bottom = ` ${borderColor}╰${'─'.repeat(71)}╯${RESET}`;
|
|
157
202
|
const empty = ` ${borderColor}│${' '.repeat(71)}│${RESET}`;
|
|
@@ -169,12 +214,13 @@ function cardHeader(title, subtitle = '', version = 'v1.3.5', borderColor = CYAN
|
|
|
169
214
|
|
|
170
215
|
function printHelp() {
|
|
171
216
|
console.log();
|
|
172
|
-
console.log(cardHeader('🛡️ T O R U S G U A R D C L I', 'Autonomous Security Engine for AI-Built Applications', 'v1.
|
|
217
|
+
console.log(cardHeader('🛡️ T O R U S G U A R D C L I', 'Autonomous Security Engine for AI-Built Applications', 'v1.4.0'));
|
|
173
218
|
console.log(`\n ${BOLD}Usage:${RESET} ${GREEN}npx torusguard${RESET} ${WHITE}[command]${RESET} ${GRAY}[options]${RESET}\n`);
|
|
174
219
|
|
|
175
220
|
console.log(cardBorderTop('Commands'));
|
|
176
221
|
console.log(formatBoxLine(`${GREEN}init${RESET} Scaffold ${BOLD}.torusguard/${RESET} workspace + unlock slash commands`));
|
|
177
222
|
console.log(formatBoxLine(`${GREEN}status${RESET} Display active security posture, memory, rules, & stack`));
|
|
223
|
+
console.log(formatBoxLine(`${GREEN}update${RESET} Check npm registry for updates (--install to auto-upgrade)`));
|
|
178
224
|
console.log(formatBoxLine(`${GREEN}rules${RESET} Auto-sync memory to AI IDE rules (.cursorrules, CLAUDE.md)`));
|
|
179
225
|
console.log(formatBoxLine(`${GREEN}memory${RESET} Manage persistent security memory (export, hook, learn)`));
|
|
180
226
|
console.log(formatBoxLine(`${GREEN}audit${RESET} Run static AST security scan on target project`));
|
|
@@ -189,6 +235,7 @@ function printHelp() {
|
|
|
189
235
|
console.log(cardDivider('AI & Memory Subcommands'));
|
|
190
236
|
console.log(formatBoxLine(`${WHITE}rules sync${RESET} ${DIM}[--format all|cursor|claude|agent|windsurf]${RESET}`));
|
|
191
237
|
console.log(formatBoxLine(`${WHITE}report --html${RESET} ${DIM}[--out <path>] Self-contained visual HTML dashboard${RESET}`));
|
|
238
|
+
console.log(formatBoxLine(`${WHITE}report --sarif${RESET} ${DIM}[--out <path>] OASIS SARIF v2.1.0 GitHub Scanning log${RESET}`));
|
|
192
239
|
console.log(formatBoxLine(`${WHITE}memory context${RESET} ${DIM}[--role auditor|remediator|reviewer] [--file <f>]${RESET}`));
|
|
193
240
|
console.log(formatBoxLine(`${WHITE}memory hook${RESET} ${DIM}[install|uninstall] Git pre-commit regression hook${RESET}`));
|
|
194
241
|
console.log(formatBoxLine(`${WHITE}memory learn${RESET} ${DIM}[--commits <range>] Ingest security commit fixes${RESET}`));
|
|
@@ -197,6 +244,7 @@ function printHelp() {
|
|
|
197
244
|
console.log(formatBoxLine(`${GRAY}--target <dir>${RESET} Target directory to analyze or scaffold ${DIM}(default: .)${RESET}`));
|
|
198
245
|
console.log(formatBoxLine(`${GRAY}--force${RESET} Overwrite existing workspace and re-scaffold`));
|
|
199
246
|
console.log(formatBoxLine(`${GRAY}--yes, -y${RESET} Non-interactive auto-approval for patch application`));
|
|
247
|
+
console.log(formatBoxLine(`${GRAY}--version, -v${RESET} Display TorusGuard package version`));
|
|
200
248
|
console.log(cardBorderBottom());
|
|
201
249
|
|
|
202
250
|
console.log(`\n ${BOLD}AI Chat Commands:${RESET}`);
|
|
@@ -218,7 +266,18 @@ if (command === 'help' || command === '--help' || command === '-h') {
|
|
|
218
266
|
}
|
|
219
267
|
|
|
220
268
|
if (command === 'status') {
|
|
221
|
-
const
|
|
269
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
270
|
+
const targetDir = path.resolve(cwd, target);
|
|
271
|
+
const statusScript = path.join(targetDir, '.torusguard', 'scripts', 'status_runner.py');
|
|
272
|
+
const fallbackStatusScript = path.join(rootDir, '.torusguard', 'scripts', 'status_runner.py');
|
|
273
|
+
const actualStatusScript = fs.existsSync(statusScript) ? statusScript : fallbackStatusScript;
|
|
274
|
+
|
|
275
|
+
if (fs.existsSync(actualStatusScript)) {
|
|
276
|
+
const proc = spawnSync(pythonCmd, [actualStatusScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
277
|
+
process.exit(proc.status !== null ? proc.status : 0);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const cfgPath = path.join(targetDir, '.torusguard', 'config', 'torusguard.json');
|
|
222
281
|
if (fs.existsSync(cfgPath)) {
|
|
223
282
|
try {
|
|
224
283
|
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf-8'));
|
|
@@ -250,7 +309,7 @@ if (command === 'status') {
|
|
|
250
309
|
}
|
|
251
310
|
|
|
252
311
|
console.log();
|
|
253
|
-
console.log(cardHeader('🛡️ TORUSGUARD SECURITY POSTURE', '', 'v1.3.
|
|
312
|
+
console.log(cardHeader('🛡️ TORUSGUARD SECURITY POSTURE', '', 'v1.3.6'));
|
|
254
313
|
console.log(`\n ${BOLD}▸ Workspace:${RESET} ${GREEN}${cwd}${RESET}`);
|
|
255
314
|
console.log(` ${BOLD}▸ Governance:${RESET} ${GREEN}Full Local Governance (.torusguard/)${RESET}`);
|
|
256
315
|
console.log(` ${BOLD}▸ Living Report:${RESET} ${CYAN}security_report.md${RESET}\n`);
|
|
@@ -440,111 +499,258 @@ if (command === 'rules') {
|
|
|
440
499
|
|
|
441
500
|
// Subcommand: audit
|
|
442
501
|
if (command === 'audit') {
|
|
443
|
-
const
|
|
502
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
503
|
+
const targetDir = path.resolve(cwd, target);
|
|
504
|
+
const auditScript = path.join(targetDir, '.torusguard', 'scripts', 'audit_runner.py');
|
|
444
505
|
const fallbackAuditScript = path.join(rootDir, '.torusguard', 'scripts', 'audit_runner.py');
|
|
445
506
|
const actualAuditScript = fs.existsSync(fallbackAuditScript) ? fallbackAuditScript : auditScript;
|
|
446
507
|
|
|
447
|
-
const proc = spawnSync(pythonCmd, [actualAuditScript, ...
|
|
508
|
+
const proc = spawnSync(pythonCmd, [actualAuditScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
448
509
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
449
510
|
}
|
|
450
511
|
|
|
451
512
|
// Subcommand: report
|
|
452
513
|
if (command === 'report') {
|
|
453
|
-
|
|
454
|
-
|
|
514
|
+
const wantHtml = args.includes('--html') || args[1] === 'html' || args.includes('--out');
|
|
515
|
+
const wantSarif = args.includes('--sarif') || (!wantHtml && args[1] !== 'html');
|
|
516
|
+
|
|
517
|
+
// Resolve target directory (supports --target and --root)
|
|
518
|
+
const rootIdx = args.indexOf('--root') !== -1 ? args.indexOf('--root') : (args.indexOf('--target') !== -1 ? args.indexOf('--target') : args.indexOf('-t'));
|
|
519
|
+
let targetRoot = cwd;
|
|
520
|
+
if (rootIdx !== -1 && args[rootIdx + 1]) {
|
|
521
|
+
targetRoot = path.resolve(cwd, args[rootIdx + 1]);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
let exitCode = 0;
|
|
525
|
+
|
|
526
|
+
// 1. If SARIF export is requested
|
|
527
|
+
if (wantSarif) {
|
|
528
|
+
const sarifScript = path.join(targetRoot, '.torusguard', 'scripts', 'sarif_exporter.py');
|
|
529
|
+
const fallbackSarifScript = path.join(rootDir, '.torusguard', 'scripts', 'sarif_exporter.py');
|
|
530
|
+
const actualSarifScript = fs.existsSync(fallbackSarifScript) ? fallbackSarifScript : sarifScript;
|
|
531
|
+
|
|
532
|
+
const sarifArgs = [actualSarifScript, '--root', targetRoot];
|
|
533
|
+
const sarifOutIdx = args.indexOf('--sarif-out');
|
|
534
|
+
if (sarifOutIdx !== -1 && args[sarifOutIdx + 1]) {
|
|
535
|
+
sarifArgs.push('--output', args[sarifOutIdx + 1]);
|
|
536
|
+
} else if (!wantHtml) {
|
|
537
|
+
const outIdx = args.indexOf('--out');
|
|
538
|
+
if (outIdx !== -1 && args[outIdx + 1]) {
|
|
539
|
+
sarifArgs.push('--output', args[outIdx + 1]);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
const runIdIdx = args.indexOf('--run');
|
|
543
|
+
if (runIdIdx !== -1 && args[runIdIdx + 1]) {
|
|
544
|
+
sarifArgs.push('--run-id', args[runIdIdx + 1]);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const proc = spawnSync(pythonCmd, sarifArgs, { stdio: 'inherit', cwd: targetRoot });
|
|
548
|
+
if (proc.status !== 0 && proc.status !== null) {
|
|
549
|
+
exitCode = proc.status;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// 2. If Visual HTML dashboard is requested
|
|
554
|
+
if (wantHtml) {
|
|
555
|
+
const htmlScript = path.join(targetRoot, '.torusguard', 'scripts', 'html_reporter.py');
|
|
455
556
|
const fallbackHtmlScript = path.join(rootDir, '.torusguard', 'scripts', 'html_reporter.py');
|
|
456
557
|
const actualHtmlScript = fs.existsSync(fallbackHtmlScript) ? fallbackHtmlScript : htmlScript;
|
|
457
558
|
|
|
458
|
-
let pyArgs = [actualHtmlScript];
|
|
559
|
+
let pyArgs = [actualHtmlScript, '--root', targetRoot];
|
|
459
560
|
const outIdx = args.indexOf('--out');
|
|
460
561
|
if (outIdx !== -1 && args[outIdx + 1]) {
|
|
461
|
-
pyArgs.push('--out', args[outIdx + 1]);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (rootIdx !== -1 && args[rootIdx + 1]) {
|
|
465
|
-
pyArgs.push('--root', args[rootIdx + 1]);
|
|
562
|
+
pyArgs.push('--out', path.resolve(cwd, args[outIdx + 1]));
|
|
563
|
+
} else {
|
|
564
|
+
pyArgs.push('--out', path.join(targetRoot, 'report.html'));
|
|
466
565
|
}
|
|
467
566
|
if (args.includes('--json')) {
|
|
468
567
|
pyArgs.push('--json');
|
|
469
568
|
}
|
|
470
569
|
|
|
471
|
-
const proc = spawnSync(pythonCmd, pyArgs, { stdio: 'inherit', cwd });
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
const fallbackSarifScript = path.join(rootDir, '.torusguard', 'scripts', 'sarif_exporter.py');
|
|
476
|
-
const actualSarifScript = fs.existsSync(fallbackSarifScript) ? fallbackSarifScript : sarifScript;
|
|
477
|
-
|
|
478
|
-
const proc = spawnSync(pythonCmd, [actualSarifScript, ...args.slice(1)], { stdio: 'inherit', cwd });
|
|
479
|
-
process.exit(proc.status !== null ? proc.status : 0);
|
|
570
|
+
const proc = spawnSync(pythonCmd, pyArgs, { stdio: 'inherit', cwd: targetRoot });
|
|
571
|
+
if (proc.status !== 0 && proc.status !== null) {
|
|
572
|
+
exitCode = proc.status;
|
|
573
|
+
}
|
|
480
574
|
}
|
|
575
|
+
|
|
576
|
+
process.exit(exitCode);
|
|
481
577
|
}
|
|
482
578
|
|
|
483
579
|
// Subcommand: harden
|
|
484
580
|
if (command === 'harden') {
|
|
485
|
-
const
|
|
581
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
582
|
+
const targetDir = path.resolve(cwd, target);
|
|
583
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'harden_runner.py');
|
|
486
584
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'harden_runner.py');
|
|
487
585
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
488
586
|
|
|
489
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
587
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
490
588
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
491
589
|
}
|
|
492
590
|
|
|
493
591
|
// Subcommand: apply
|
|
494
592
|
if (command === 'apply') {
|
|
495
|
-
const
|
|
593
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
594
|
+
const targetDir = path.resolve(cwd, target);
|
|
595
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
496
596
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
497
597
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
498
598
|
|
|
499
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
599
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
500
600
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
501
601
|
}
|
|
502
602
|
|
|
503
603
|
// Subcommand: rollback
|
|
504
604
|
if (command === 'rollback') {
|
|
505
|
-
const
|
|
605
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
606
|
+
const targetDir = path.resolve(cwd, target);
|
|
607
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
506
608
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
507
609
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
508
610
|
|
|
509
|
-
const proc = spawnSync(pythonCmd, [actualScript, '--rollback', ...
|
|
611
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, '--rollback', ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
510
612
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
511
613
|
}
|
|
512
614
|
|
|
513
615
|
// Subcommand: recheck / verify
|
|
514
616
|
if (command === 'recheck' || command === 'verify') {
|
|
515
|
-
const
|
|
617
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
618
|
+
const targetDir = path.resolve(cwd, target);
|
|
619
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'recheck_runner.py');
|
|
516
620
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recheck_runner.py');
|
|
517
621
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
518
622
|
|
|
519
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
623
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
520
624
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
521
625
|
}
|
|
522
626
|
|
|
523
627
|
// Subcommand: recipes
|
|
524
628
|
if (command === 'recipes') {
|
|
525
|
-
const
|
|
629
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
630
|
+
const targetDir = path.resolve(cwd, target);
|
|
631
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'recipes_runner.py');
|
|
526
632
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recipes_runner.py');
|
|
527
633
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
528
634
|
|
|
529
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
635
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
530
636
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
531
637
|
}
|
|
532
638
|
|
|
533
639
|
// Subcommand: init (scaffold workspace)
|
|
534
640
|
if (command === 'init') {
|
|
641
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
642
|
+
const targetDir = path.resolve(cwd, target);
|
|
535
643
|
const localBootstrap = path.join(rootDir, 'skills', 'torusguard', 'bootstrap.py');
|
|
536
644
|
const localInstall = path.join(rootDir, 'install.py');
|
|
537
645
|
const scriptToRun = fs.existsSync(localBootstrap) ? localBootstrap : localInstall;
|
|
538
646
|
|
|
539
|
-
const scriptArgs = [scriptToRun, '--full-commands', ...
|
|
647
|
+
const scriptArgs = [scriptToRun, '--full-commands', '--target', targetDir, ...remaining];
|
|
540
648
|
const proc = spawnSync(pythonCmd, scriptArgs, {
|
|
541
649
|
stdio: 'inherit',
|
|
542
|
-
cwd:
|
|
650
|
+
cwd: targetDir,
|
|
543
651
|
});
|
|
544
652
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
545
653
|
}
|
|
546
654
|
|
|
655
|
+
// Subcommand: update
|
|
656
|
+
if (command === 'update') {
|
|
657
|
+
const https = require('https');
|
|
658
|
+
const pkgJsonPath = path.join(rootDir, 'package.json');
|
|
659
|
+
let currentVersion = '1.4.0';
|
|
660
|
+
try {
|
|
661
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
662
|
+
currentVersion = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')).version || currentVersion;
|
|
663
|
+
}
|
|
664
|
+
} catch (e) {}
|
|
665
|
+
|
|
666
|
+
console.log();
|
|
667
|
+
console.log(cardHeader('🛡️ TORUSGUARD UPDATE CHECK', 'Package Distribution & Registry Verifier', `v${currentVersion}`));
|
|
668
|
+
console.log(`\n ${DIM}Checking npm registry for updates...${RESET}`);
|
|
669
|
+
|
|
670
|
+
const autoInstall = args.includes('--install') || args.includes('-i') || args.includes('--yes') || args.includes('-y');
|
|
671
|
+
|
|
672
|
+
function printUpdateOffline(reason) {
|
|
673
|
+
console.log();
|
|
674
|
+
console.log(cardBorderTop('Offline / Registry Unreachable', YELLOW));
|
|
675
|
+
console.log(formatBoxLine(`Current: ${WHITE}v${currentVersion}${RESET}`, 67, '│', YELLOW));
|
|
676
|
+
console.log(formatBoxLine(`Notice: ${DIM}${reason}${RESET}`, 67, '│', YELLOW));
|
|
677
|
+
console.log(formatBoxLine(`Manual: ${BOLD}${CYAN}npm update torusguard${RESET} or ${BOLD}${CYAN}npm i -g torusguard@latest${RESET}`, 67, '│', YELLOW));
|
|
678
|
+
console.log(cardBorderBottom(YELLOW));
|
|
679
|
+
console.log();
|
|
680
|
+
process.exit(0);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const req = https.get('https://registry.npmjs.org/torusguard/latest', {
|
|
684
|
+
headers: { 'User-Agent': `torusguard-cli/${currentVersion}` },
|
|
685
|
+
timeout: 6000
|
|
686
|
+
}, (res) => {
|
|
687
|
+
let raw = '';
|
|
688
|
+
res.on('data', chunk => raw += chunk);
|
|
689
|
+
res.on('end', () => {
|
|
690
|
+
try {
|
|
691
|
+
const data = JSON.parse(raw);
|
|
692
|
+
const latestVersion = data.version;
|
|
693
|
+
if (!latestVersion) {
|
|
694
|
+
printUpdateOffline('No version field returned in npm registry response');
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const isNewer = compareSemver(latestVersion, currentVersion) > 0;
|
|
699
|
+
console.log();
|
|
700
|
+
console.log(cardBorderTop('Version Telemetry', CYAN));
|
|
701
|
+
console.log(formatBoxLine(`Installed Version: ${WHITE}v${currentVersion}${RESET}`));
|
|
702
|
+
console.log(formatBoxLine(`Latest on NPM: ${BOLD}${GREEN}v${latestVersion}${RESET}`));
|
|
703
|
+
console.log(cardBorderBottom(CYAN));
|
|
704
|
+
console.log();
|
|
705
|
+
|
|
706
|
+
if (isNewer) {
|
|
707
|
+
console.log(cardBorderTop('Update Available', YELLOW, true));
|
|
708
|
+
console.log(formatBoxLine(`${YELLOW}A new version of TorusGuard is available!${RESET}`, 67, '║', YELLOW));
|
|
709
|
+
console.log(formatBoxLine(`Global: ${BOLD}${WHITE}npm install -g torusguard@latest${RESET}`, 67, '║', YELLOW));
|
|
710
|
+
console.log(formatBoxLine(`Local: ${BOLD}${WHITE}npm install torusguard@latest${RESET}`, 67, '║', YELLOW));
|
|
711
|
+
console.log(cardBorderBottom(YELLOW, true));
|
|
712
|
+
console.log();
|
|
713
|
+
|
|
714
|
+
if (autoInstall) {
|
|
715
|
+
console.log(` ${CYAN}Auto-installing latest version via npm...${RESET}`);
|
|
716
|
+
const npmProc = spawnSync('npm', ['install', '-g', 'torusguard@latest'], { stdio: 'inherit' });
|
|
717
|
+
if (npmProc.status === 0) {
|
|
718
|
+
console.log(`\n ${GREEN}✔ Successfully upgraded TorusGuard to v${latestVersion}!${RESET}\n`);
|
|
719
|
+
} else {
|
|
720
|
+
console.error(`\n ${RED}✖ Failed to auto-install update. Run: npm install -g torusguard@latest${RESET}\n`);
|
|
721
|
+
}
|
|
722
|
+
} else {
|
|
723
|
+
console.log(` ${DIM}Tip: Run with ${CYAN}npx torusguard update --install${DIM} to auto-upgrade.${RESET}\n`);
|
|
724
|
+
}
|
|
725
|
+
} else {
|
|
726
|
+
console.log(cardBorderTop('Status: Up To Date', GREEN, true));
|
|
727
|
+
console.log(formatBoxLine(`${GREEN}✔ TorusGuard is up to date (v${currentVersion})${RESET}`, 67, '║', GREEN));
|
|
728
|
+
console.log(cardBorderBottom(GREEN, true));
|
|
729
|
+
console.log();
|
|
730
|
+
}
|
|
731
|
+
process.exit(0);
|
|
732
|
+
} catch (err) {
|
|
733
|
+
printUpdateOffline(err.message);
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
req.on('error', (err) => printUpdateOffline(err.message));
|
|
739
|
+
req.on('timeout', () => {
|
|
740
|
+
req.destroy();
|
|
741
|
+
printUpdateOffline('npm registry request timed out (6000ms)');
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
|
|
547
745
|
// Unknown command fallback
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
746
|
+
const KNOWN_COMMANDS = new Set([
|
|
747
|
+
'init', 'status', 'rules', 'memory', 'diff-guard', 'audit',
|
|
748
|
+
'report', 'harden', 'apply', 'rollback', 'recheck', 'verify',
|
|
749
|
+
'recipes', 'update', 'help', '--help', '-h', '--version', '-v', 'version'
|
|
750
|
+
]);
|
|
751
|
+
|
|
752
|
+
if (!KNOWN_COMMANDS.has(command)) {
|
|
753
|
+
console.error(`\n ${RED}✖ Unknown command:${RESET} ${WHITE}${command}${RESET}`);
|
|
754
|
+
console.error(` Run ${GREEN}npx torusguard help${RESET} for available commands.\n`);
|
|
755
|
+
process.exit(1);
|
|
756
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "torusguard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Security guardrails, governed remediation, and authorized runtime validation for AI-built web applications.",
|
|
5
5
|
"main": "bin/torusguard.js",
|
|
6
6
|
"bin": {
|
|
@@ -17,8 +17,12 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"test": "python harness/runner.py",
|
|
19
19
|
"init": "node bin/torusguard.js init",
|
|
20
|
+
"status": "node bin/torusguard.js status",
|
|
20
21
|
"audit": "node bin/torusguard.js audit",
|
|
21
|
-
"
|
|
22
|
+
"harden": "node bin/torusguard.js harden",
|
|
23
|
+
"apply": "node bin/torusguard.js apply",
|
|
24
|
+
"recipes": "node bin/torusguard.js recipes",
|
|
25
|
+
"update": "node bin/torusguard.js update"
|
|
22
26
|
},
|
|
23
27
|
"keywords": [
|
|
24
28
|
"security",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: torusguard
|
|
3
3
|
description: Universal autonomous security engine: 74 canonical rules across 18 families, polyglot stack detection across 16+ languages, Ponytail remediation bounds (<=35 add, <=25 del), standardized 75-column terminal UI, living security_report.md ground-truth ledger, SARIF v2.1.0 exports, and persistent security memory context.
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.6
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# TorusGuard Master Security Engine & Command Router
|
|
Binary file
|
|
@@ -135,7 +135,7 @@ def print_header():
|
|
|
135
135
|
print(f"""
|
|
136
136
|
{CYAN}╭─────────────────────────────────────────────────────────────────────────╮{RESET}
|
|
137
137
|
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
138
|
-
{CYAN}│{RESET} {BOLD}{WHITE}🛡️ T O R U S G U A R D{RESET} {GRAY}v1.
|
|
138
|
+
{CYAN}│{RESET} {BOLD}{WHITE}🛡️ T O R U S G U A R D{RESET} {GRAY}v1.4.0{RESET} {CYAN}│{RESET}
|
|
139
139
|
{CYAN}│{RESET} {DIM}Autonomous Security Engine for AI-Built Applications{RESET} {CYAN}│{RESET}
|
|
140
140
|
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
141
141
|
{CYAN}╰─────────────────────────────────────────────────────────────────────────╯{RESET}
|
|
@@ -220,7 +220,7 @@ def print_already_initialized(target_root, cfg):
|
|
|
220
220
|
|
|
221
221
|
{BOLD}▸ Project Root:{RESET} {GREEN}{target_root}{RESET}
|
|
222
222
|
{BOLD}▸ Workspace:{RESET} {GREEN}.torusguard/{RESET} {DIM}(Already Initialized){RESET}
|
|
223
|
-
{BOLD}▸ Version:{RESET} {CYAN}{cfg.get('version', '1.
|
|
223
|
+
{BOLD}▸ Version:{RESET} {CYAN}{cfg.get('version', '1.4.0')}{RESET}
|
|
224
224
|
{BOLD}▸ Severity Floor:{RESET} {YELLOW}{cfg.get('severity_threshold', 'medium')}{RESET}
|
|
225
225
|
|
|
226
226
|
{DIM}To refresh templates or re-scaffold, run:{RESET}
|
|
@@ -228,7 +228,7 @@ def print_already_initialized(target_root, cfg):
|
|
|
228
228
|
""")
|
|
229
229
|
|
|
230
230
|
|
|
231
|
-
def scaffold_workspace(target_root=None, force=False, full_commands=False):
|
|
231
|
+
def scaffold_workspace(target_root=None, force=False, full_commands=False, template=None, run_audit=False):
|
|
232
232
|
"""Scaffold the .torusguard workspace into the target project root."""
|
|
233
233
|
target_root = Path(target_root or find_project_root()).resolve()
|
|
234
234
|
torusguard_target = target_root / ".torusguard"
|
|
@@ -348,13 +348,18 @@ def scaffold_workspace(target_root=None, force=False, full_commands=False):
|
|
|
348
348
|
"cards": []
|
|
349
349
|
}, indent=2), encoding="utf-8")
|
|
350
350
|
|
|
351
|
-
# Ensure target project root .gitignore excludes .torusguard/memory/
|
|
351
|
+
# Ensure target project root .gitignore excludes .torusguard/memory/ and report.html
|
|
352
352
|
root_gitignore = target_root / ".gitignore"
|
|
353
353
|
if root_gitignore.exists():
|
|
354
354
|
try:
|
|
355
355
|
gi_content = root_gitignore.read_text(encoding="utf-8")
|
|
356
|
+
to_add = []
|
|
356
357
|
if ".torusguard/memory" not in gi_content:
|
|
357
|
-
|
|
358
|
+
to_add.append(".torusguard/memory/")
|
|
359
|
+
if "report.html" not in gi_content:
|
|
360
|
+
to_add.append("report.html")
|
|
361
|
+
if to_add:
|
|
362
|
+
root_gitignore.write_text(gi_content.rstrip() + "\n\n# TorusGuard local artifacts\n" + "\n".join(to_add) + "\n", encoding="utf-8")
|
|
358
363
|
except Exception:
|
|
359
364
|
pass
|
|
360
365
|
|
|
@@ -374,12 +379,26 @@ def scaffold_workspace(target_root=None, force=False, full_commands=False):
|
|
|
374
379
|
except Exception:
|
|
375
380
|
detected_stack = None
|
|
376
381
|
|
|
382
|
+
TEMPLATE_MAP = {
|
|
383
|
+
"golang": {"language": "Go", "framework": "Gin/Fiber", "data_layer": "database/sql"},
|
|
384
|
+
"go": {"language": "Go", "framework": "Gin/Fiber", "data_layer": "database/sql"},
|
|
385
|
+
"nextjs": {"language": "TypeScript", "framework": "Next.js", "data_layer": "Prisma ORM"},
|
|
386
|
+
"fastapi": {"language": "Python", "framework": "FastAPI", "data_layer": "SQLAlchemy"},
|
|
387
|
+
"express": {"language": "JavaScript", "framework": "Express", "data_layer": "Mongoose"},
|
|
388
|
+
"django": {"language": "Python", "framework": "Django", "data_layer": "Django ORM"},
|
|
389
|
+
"react": {"language": "JavaScript/TypeScript", "framework": "React / Vite", "data_layer": "Supabase"}
|
|
390
|
+
}
|
|
391
|
+
if template and template.lower() in TEMPLATE_MAP:
|
|
392
|
+
detected_stack = TEMPLATE_MAP[template.lower()]
|
|
393
|
+
|
|
377
394
|
config_file = torusguard_target / "config" / "torusguard.json"
|
|
378
395
|
if config_file.exists():
|
|
379
396
|
try:
|
|
380
397
|
with open(config_file, "r", encoding="utf-8") as f:
|
|
381
398
|
cfg = json.load(f)
|
|
382
|
-
if
|
|
399
|
+
if template and template.lower() in TEMPLATE_MAP:
|
|
400
|
+
cfg["detected_stack"] = TEMPLATE_MAP[template.lower()]
|
|
401
|
+
elif detected_stack and detected_stack.get("framework") != "None":
|
|
383
402
|
cfg["detected_stack"] = {
|
|
384
403
|
"language": detected_stack.get("language"),
|
|
385
404
|
"framework": detected_stack.get("framework"),
|
|
@@ -511,15 +530,40 @@ Parse the requested action from `$ARGUMENTS` (e.g. `audit`, `verify`, `web-valid
|
|
|
511
530
|
|
|
512
531
|
# ── Success Card ────────────────────────────────────────────────────────
|
|
513
532
|
print_success_card()
|
|
533
|
+
|
|
534
|
+
# ── Optional Immediate Audit ────────────────────────────────────────────
|
|
535
|
+
if run_audit:
|
|
536
|
+
audit_script = torusguard_target / "scripts" / "audit_runner.py"
|
|
537
|
+
if audit_script.is_file():
|
|
538
|
+
print(f"\n {CYAN}▸ Running immediate baseline security audit (--audit)...{RESET}\n")
|
|
539
|
+
try:
|
|
540
|
+
import importlib.util
|
|
541
|
+
spec = importlib.util.spec_from_file_location("audit_runner", str(audit_script))
|
|
542
|
+
if spec and spec.loader:
|
|
543
|
+
ar_mod = importlib.util.module_from_spec(spec)
|
|
544
|
+
spec.loader.exec_module(ar_mod)
|
|
545
|
+
if hasattr(ar_mod, "execute_audit"):
|
|
546
|
+
ar_mod.execute_audit(target_root)
|
|
547
|
+
except Exception as e:
|
|
548
|
+
print(f" {YELLOW}⚠ Immediate audit notice: {e}{RESET}")
|
|
549
|
+
|
|
514
550
|
return True
|
|
515
551
|
|
|
516
552
|
|
|
517
553
|
if __name__ == "__main__":
|
|
518
554
|
parser = argparse.ArgumentParser(description="TorusGuard Autonomous Workspace Bootstrapper")
|
|
519
|
-
parser.add_argument("--target", type=str, help="Target project root directory")
|
|
555
|
+
parser.add_argument("--target", "-t", type=str, help="Target project root directory")
|
|
520
556
|
parser.add_argument("--force", action="store_true", help="Force overwrite existing workspace")
|
|
521
557
|
parser.add_argument("--full-commands", action="store_true", help="Unlock and register all 11 individual slash commands")
|
|
558
|
+
parser.add_argument("--template", choices=["golang", "go", "nextjs", "fastapi", "express", "django", "react"], help="Pre-configure target framework stack template")
|
|
559
|
+
parser.add_argument("--audit", action="store_true", help="Execute immediate baseline audit post-initialization")
|
|
522
560
|
args = parser.parse_args()
|
|
523
561
|
|
|
524
|
-
success = scaffold_workspace(
|
|
562
|
+
success = scaffold_workspace(
|
|
563
|
+
target_root=args.target,
|
|
564
|
+
force=args.force,
|
|
565
|
+
full_commands=args.full_commands,
|
|
566
|
+
template=args.template,
|
|
567
|
+
run_audit=args.audit
|
|
568
|
+
)
|
|
525
569
|
sys.exit(0 if success else 1)
|