torusguard 1.3.6 โ 2.0.0-alpha
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 +9 -8
- package/.torusguard/auth.json +5 -0
- package/.torusguard/rules_catalog.json +242 -518
- package/.torusguard/runs/report-latest.html +3529 -364
- package/.torusguard/runs/run-20260918-105940-audit/manifest.json +2 -1
- package/.torusguard/runs/run-20260918-105940-audit/remediation.md +7 -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__/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__/recipes_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
- package/.torusguard/scripts/apply_runner.py +101 -8
- package/.torusguard/scripts/audit_runner.py +116 -11
- package/.torusguard/scripts/harden_runner.py +122 -68
- package/.torusguard/scripts/html_reporter.py +1170 -253
- package/.torusguard/scripts/manifest_builder.py +2 -0
- package/.torusguard/scripts/recheck_runner.py +2 -1
- package/.torusguard/scripts/recipes_runner.py +91 -8
- package/.torusguard/scripts/report_sync.py +134 -7
- package/.torusguard/scripts/status_runner.py +267 -0
- package/.torusguard/snapshots/20260921-182638/go.mod.bak +11 -0
- package/.torusguard/snapshots/20260921-185213/file.go.bak +5 -0
- package/README.md +314 -364
- package/bin/torusguard.js +190 -20
- package/package.json +6 -2
- package/skills/torusguard/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/skills/torusguard/bootstrap.py +45 -6
- package/skills/torusguard/payload/.manifest.json +29 -14
- package/skills/torusguard/payload/TORUSGUARD.md +145 -145
- package/skills/torusguard/payload/agents/auditor.md +41 -41
- package/skills/torusguard/payload/agents/profiler.md +49 -49
- package/skills/torusguard/payload/agents/remediator.md +41 -41
- package/skills/torusguard/payload/agents/reviewer.md +39 -39
- package/skills/torusguard/payload/agents/validator.md +46 -46
- package/skills/torusguard/payload/config/scope.json +24 -24
- package/skills/torusguard/payload/references/csharp-security.md +41 -41
- package/skills/torusguard/payload/references/go-security.md +41 -41
- package/skills/torusguard/payload/references/java-security.md +40 -40
- package/skills/torusguard/payload/references/polyglot-security-matrix.md +25 -25
- package/skills/torusguard/payload/references/rust-security.md +40 -40
- package/skills/torusguard/payload/rules/custom/.gitkeep +1 -1
- package/skills/torusguard/payload/rules/custom/README.md +30 -30
- package/skills/torusguard/payload/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/sarif_exporter.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/apply_runner.py +101 -8
- package/skills/torusguard/payload/scripts/audit_runner.py +116 -11
- package/skills/torusguard/payload/scripts/harden_runner.py +122 -68
- package/skills/torusguard/payload/scripts/html_reporter.py +1170 -253
- package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
- package/skills/torusguard/payload/scripts/recheck_runner.py +2 -1
- package/skills/torusguard/payload/scripts/recipes_runner.py +91 -8
- package/skills/torusguard/payload/scripts/report_sync.py +134 -7
- package/skills/torusguard/payload/scripts/rules_sync.py +321 -321
- package/skills/torusguard/payload/scripts/safety_gate.py +64 -64
- package/skills/torusguard/payload/scripts/status_runner.py +267 -0
- package/skills/torusguard/payload/skills/torusguard/references/csharp-security.md +41 -41
- package/skills/torusguard/payload/skills/torusguard/references/go-security.md +41 -41
- package/skills/torusguard/payload/skills/torusguard/references/java-security.md +40 -40
- package/skills/torusguard/payload/skills/torusguard/references/polyglot-security-matrix.md +25 -25
- package/skills/torusguard/payload/skills/torusguard/references/rust-security.md +40 -40
- package/skills/torusguard/payload/templates/audit-report.template.md +54 -54
- package/skills/torusguard/payload/templates/authorization.template.md +34 -34
- package/skills/torusguard/payload/templates/finding-card.template.md +32 -32
- package/skills/torusguard/payload/templates/remediation-bundle.template.md +35 -35
- package/skills/torusguard/payload/workflows/apply.md +9 -1
- package/skills/torusguard/payload/workflows/audit.md +8 -2
- package/skills/torusguard/payload/workflows/harden.md +6 -1
- package/skills/torusguard/payload/workflows/init.md +7 -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
|
@@ -147,6 +147,15 @@ def generate_patch_for_finding(finding: Dict[str, Any], target_root: Path) -> Op
|
|
|
147
147
|
new_lines[line_number - 1] = replacement
|
|
148
148
|
applied_rule = True
|
|
149
149
|
fix_explanation = f"Replaced hardcoded credential with os.environ.get('{env_key}')"
|
|
150
|
+
elif file_path.endswith(".go"):
|
|
151
|
+
if re.search(r'(:=|=)\s*["\'][A-Za-z0-9_\-]{8,}["\']', target_line):
|
|
152
|
+
var_match = re.search(r'([A-Za-z0-9_]+)\s*[:=]', target_line)
|
|
153
|
+
var_name = var_match.group(1) if var_match else "apiKey"
|
|
154
|
+
env_key = re.sub(r'(?<!^)(?=[A-Z])', '_', var_name).upper()
|
|
155
|
+
replacement = f'{indent}{var_name} := os.Getenv("{env_key}")'
|
|
156
|
+
new_lines[line_number - 1] = replacement
|
|
157
|
+
applied_rule = True
|
|
158
|
+
fix_explanation = f"Replaced hardcoded Go credential with os.Getenv('{env_key}')"
|
|
150
159
|
|
|
151
160
|
# Strategy 2: Dangerous React HTML rendering & DOM innerHTML (TG-INPUT-003)
|
|
152
161
|
elif rule_id == "TG-INPUT-003":
|
|
@@ -187,6 +196,13 @@ def generate_patch_for_finding(finding: Dict[str, Any], target_root: Path) -> Op
|
|
|
187
196
|
new_lines[line_number - 1] = fixed_line
|
|
188
197
|
applied_rule = True
|
|
189
198
|
fix_explanation = "Replaced template literal SQL string interpolation with parameterized SQL placeholder (?)"
|
|
199
|
+
elif file_path.endswith(".go") and ("fmt.Sprintf(" in target_line or " + " in target_line):
|
|
200
|
+
if any(w in target_line for w in ("SELECT", "INSERT", "UPDATE", "DELETE")):
|
|
201
|
+
fixed_line = re.sub(r'fmt\.Sprintf\(\s*["\'](SELECT.*?WHERE.*?%s.*?)["\'],\s*([A-Za-z0-9_$.]+)\)', r'/* parameterized */ "\1", \2', target_line)
|
|
202
|
+
if fixed_line != target_line:
|
|
203
|
+
new_lines[line_number - 1] = fixed_line
|
|
204
|
+
applied_rule = True
|
|
205
|
+
fix_explanation = "Replaced unsafe Go SQL fmt.Sprintf concatenation with parameterized placeholder"
|
|
190
206
|
|
|
191
207
|
# Strategy 4: Multi-Tenant Query Scoping (TG-DB-004)
|
|
192
208
|
elif rule_id == "TG-DB-004":
|
|
@@ -246,6 +262,12 @@ def generate_patch_for_finding(finding: Dict[str, Any], target_root: Path) -> Op
|
|
|
246
262
|
new_lines[line_number - 1] = fixed_line
|
|
247
263
|
applied_rule = True
|
|
248
264
|
fix_explanation = "Wrapped dynamic path segment in os.path.basename to neutralize path traversal sequences"
|
|
265
|
+
elif file_path.endswith(".go") and "filepath.Join(" in target_line and "filepath.Base" not in target_line:
|
|
266
|
+
fixed_line = re.sub(r'filepath\.Join\((.*?),\s*([a-zA-Z0-9_$.]+)\)', r'filepath.Join(\1, filepath.Base(\2))', target_line)
|
|
267
|
+
if fixed_line != target_line:
|
|
268
|
+
new_lines[line_number - 1] = fixed_line
|
|
269
|
+
applied_rule = True
|
|
270
|
+
fix_explanation = "Wrapped dynamic path segment in filepath.Base to neutralize Go path traversal"
|
|
249
271
|
|
|
250
272
|
# Strategy 8: TLS Verification Bypass (TG-DIFF-001)
|
|
251
273
|
elif rule_id == "TG-DIFF-001":
|
|
@@ -265,6 +287,22 @@ def generate_patch_for_finding(finding: Dict[str, Any], target_root: Path) -> Op
|
|
|
265
287
|
applied_rule = True
|
|
266
288
|
fix_explanation = "Restored mandatory TLS certificate validation (InsecureSkipVerify: false)"
|
|
267
289
|
|
|
290
|
+
# Strategy 9: Unbounded HTTP Client Timeout / SSRF (TG-SSRF-004)
|
|
291
|
+
elif rule_id == "TG-SSRF-004":
|
|
292
|
+
if file_path.endswith(".go") and ("&http.Client{}" in target_line or "http.DefaultClient" in target_line):
|
|
293
|
+
fixed_line = target_line.replace("&http.Client{}", "&http.Client{Timeout: 10 * time.Second}")
|
|
294
|
+
fixed_line = fixed_line.replace("http.DefaultClient", "&http.Client{Timeout: 10 * time.Second}")
|
|
295
|
+
if fixed_line != target_line:
|
|
296
|
+
new_lines[line_number - 1] = fixed_line
|
|
297
|
+
applied_rule = True
|
|
298
|
+
fix_explanation = "Injected explicit 10s timeout to Go http.Client to prevent resource exhaustion"
|
|
299
|
+
elif file_path.endswith(".py") and "requests.get(" in target_line and "timeout=" not in target_line:
|
|
300
|
+
fixed_line = re.sub(r'requests\.get\((.*?)\)', r'requests.get(\1, timeout=10)', target_line)
|
|
301
|
+
if fixed_line != target_line:
|
|
302
|
+
new_lines[line_number - 1] = fixed_line
|
|
303
|
+
applied_rule = True
|
|
304
|
+
fix_explanation = "Injected explicit timeout=10 to requests.get call"
|
|
305
|
+
|
|
268
306
|
|
|
269
307
|
# Strategy 9: Hardcoded Database / Service Credential in Config (TG-SEC-003)
|
|
270
308
|
elif rule_id == "TG-SEC-003":
|
|
@@ -466,7 +504,7 @@ def generate_patch_for_finding(finding: Dict[str, Any], target_root: Path) -> Op
|
|
|
466
504
|
}
|
|
467
505
|
|
|
468
506
|
|
|
469
|
-
def execute_harden(target_root: Path, run_id_arg: Optional[str] = None) -> Dict[str, Any]:
|
|
507
|
+
def execute_harden(target_root: Path, run_id_arg: Optional[str] = None, severity_floor: str = "medium", dry_run: bool = False) -> Dict[str, Any]:
|
|
470
508
|
"""Execute autonomous remediation formulation and package candidate bundles."""
|
|
471
509
|
runs_dir = target_root / ".torusguard" / "runs"
|
|
472
510
|
if run_id_arg:
|
|
@@ -490,8 +528,14 @@ def execute_harden(target_root: Path, run_id_arg: Optional[str] = None) -> Dict[
|
|
|
490
528
|
print(f"\n {RED}โ Failed to parse findings.json:{RESET} {e}\n")
|
|
491
529
|
sys.exit(1)
|
|
492
530
|
|
|
531
|
+
# Severity filtering
|
|
532
|
+
SEV_RANKS = {"critical": 4, "high": 3, "medium": 2, "low": 1}
|
|
533
|
+
min_rank = SEV_RANKS.get(severity_floor.lower(), 2)
|
|
534
|
+
findings = [f for f in findings if SEV_RANKS.get(f.get("severity", "Medium").lower(), 2) >= min_rank]
|
|
535
|
+
|
|
493
536
|
bundles_dir = run_folder / "bundles"
|
|
494
|
-
|
|
537
|
+
if not dry_run:
|
|
538
|
+
bundles_dir.mkdir(parents=True, exist_ok=True)
|
|
495
539
|
|
|
496
540
|
bundles = []
|
|
497
541
|
seen_file_lines = set()
|
|
@@ -503,73 +547,79 @@ def execute_harden(target_root: Path, run_id_arg: Optional[str] = None) -> Dict[
|
|
|
503
547
|
if candidate:
|
|
504
548
|
seen_file_lines.add(target_key)
|
|
505
549
|
bundles.append(candidate)
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
json
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
report_sync.record_harden_bundles(target_root, bundles, run_folder.name)
|
|
552
|
-
except Exception:
|
|
553
|
-
pass
|
|
554
|
-
|
|
555
|
-
# Update manifest
|
|
556
|
-
manifest_file = run_folder / "manifest.json"
|
|
557
|
-
if manifest_file.is_file():
|
|
550
|
+
if not dry_run:
|
|
551
|
+
b_dir = bundles_dir / candidate["bundle_id"]
|
|
552
|
+
b_dir.mkdir(parents=True, exist_ok=True)
|
|
553
|
+
|
|
554
|
+
# 1. patch.diff
|
|
555
|
+
(b_dir / "patch.diff").write_text(candidate["proposed_diff"], encoding="utf-8")
|
|
556
|
+
|
|
557
|
+
# 2. minimal_patch_plan.md
|
|
558
|
+
plan_content = [
|
|
559
|
+
f"# Remediation Plan: {candidate['bundle_id']}",
|
|
560
|
+
f"- **Rule ID:** `{candidate['rule_id']}`",
|
|
561
|
+
f"- **Target File:** `{candidate['target_file']}:{candidate['line_number']}`",
|
|
562
|
+
f"- **Ponytail Churn:** `+{candidate['additions']} / -{candidate['deletions']}` (Compliant <=35/<=25)",
|
|
563
|
+
f"\n## Proposed Change\n{candidate['what_should_change']}\n",
|
|
564
|
+
"## Unified Diff Preview\n```diff",
|
|
565
|
+
candidate["proposed_diff"],
|
|
566
|
+
"```"
|
|
567
|
+
]
|
|
568
|
+
(b_dir / "minimal_patch_plan.md").write_text("\n".join(plan_content), encoding="utf-8")
|
|
569
|
+
|
|
570
|
+
# 3. metadata.json
|
|
571
|
+
with open(b_dir / "metadata.json", "w", encoding="utf-8") as mf:
|
|
572
|
+
json.dump(candidate, mf, indent=2)
|
|
573
|
+
|
|
574
|
+
if not dry_run:
|
|
575
|
+
# Render run-level remediation.md
|
|
576
|
+
remediation_lines = [
|
|
577
|
+
f"# TorusGuard Governed Remediation Catalog",
|
|
578
|
+
f"**Run ID:** `{run_folder.name}` ",
|
|
579
|
+
f"**Generated:** `{get_ist_now().strftime('%Y-%m-%d %H:%M:%S IST')}` ",
|
|
580
|
+
f"**Candidate Bundles Formulated:** `{len(bundles)}` \n",
|
|
581
|
+
"---",
|
|
582
|
+
"## Formulated Candidate Patches\n"
|
|
583
|
+
]
|
|
584
|
+
|
|
585
|
+
for b in bundles:
|
|
586
|
+
remediation_lines.append(f"### [{b['rule_id']}] {b['title']}")
|
|
587
|
+
remediation_lines.append(f"- **Target:** `{b['target_file']}:{b['line_number']}` | **Bundle ID:** `{b['bundle_id']}`")
|
|
588
|
+
remediation_lines.append(f"- **Strategy:** {b['what_should_change']}")
|
|
589
|
+
remediation_lines.append(f"- **Ponytail Churn:** `+{b['additions']} / -{b['deletions']}`")
|
|
590
|
+
remediation_lines.append("```diff")
|
|
591
|
+
remediation_lines.append(b["proposed_diff"].strip())
|
|
592
|
+
remediation_lines.append("```\n")
|
|
593
|
+
|
|
594
|
+
(run_folder / "remediation.md").write_text("\n".join(remediation_lines), encoding="utf-8")
|
|
558
595
|
try:
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
manifest_file.write_text(json.dumps(mdata, indent=2), encoding="utf-8")
|
|
596
|
+
import report_sync
|
|
597
|
+
report_sync.record_harden_bundles(target_root, bundles, run_folder.name)
|
|
562
598
|
except Exception:
|
|
563
599
|
pass
|
|
564
600
|
|
|
601
|
+
# Update manifest
|
|
602
|
+
manifest_file = run_folder / "manifest.json"
|
|
603
|
+
if manifest_file.is_file():
|
|
604
|
+
try:
|
|
605
|
+
mdata = json.loads(manifest_file.read_text(encoding="utf-8"))
|
|
606
|
+
mdata["remediation_bundles_count"] = len(bundles)
|
|
607
|
+
manifest_file.write_text(json.dumps(mdata, indent=2), encoding="utf-8")
|
|
608
|
+
except Exception:
|
|
609
|
+
pass
|
|
610
|
+
|
|
565
611
|
# Print 75-column Terminal Cards
|
|
612
|
+
title_sub = "DRY RUN PREVIEW (No Disk Modifications)" if dry_run else "Autonomous Minimal Patch Formulation & Ponytail Packaging"
|
|
566
613
|
print()
|
|
567
|
-
print(box_header("๐ก๏ธ TORUSGUARD GOVERNED REMEDIATION ENGINE",
|
|
614
|
+
print(box_header("๐ก๏ธ TORUSGUARD GOVERNED REMEDIATION ENGINE", title_sub, "v1.4.0"))
|
|
568
615
|
print()
|
|
569
616
|
|
|
570
617
|
print(border_top("Remediation Scope"))
|
|
571
618
|
print(box_line(f"Active Run: {WHITE}{run_folder.name}{RESET}"))
|
|
572
619
|
print(box_line(f"Target Scope: {WHITE}{target_root}{RESET}"))
|
|
620
|
+
print(box_line(f"Severity Floor: {YELLOW}{severity_floor.upper()}{RESET}"))
|
|
621
|
+
if dry_run:
|
|
622
|
+
print(box_line(f"Execution Mode: {YELLOW}DRY RUN (Preview Only ยท Zero Disk Churn){RESET}"))
|
|
573
623
|
print(box_line(f"Total Findings: {len(findings)} evaluated | {GREEN}{len(bundles)} surgical patches formulated{RESET}"))
|
|
574
624
|
print(box_line(f"Ponytail Guard: {GREEN}All patches strictly <= 35 additions, <= 25 deletions{RESET}"))
|
|
575
625
|
print(border_bottom())
|
|
@@ -585,13 +635,14 @@ def execute_harden(target_root: Path, run_id_arg: Optional[str] = None) -> Dict[
|
|
|
585
635
|
print(border_bottom())
|
|
586
636
|
print()
|
|
587
637
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
638
|
+
if not dry_run:
|
|
639
|
+
print(border_top("Next Governed Action", border_color=GREEN, double=True))
|
|
640
|
+
print(box_line(f"Living Report: {CYAN}security_report.md (patch previews attached){RESET}", border="โ", border_color=GREEN))
|
|
641
|
+
print(box_line(f"Review & Apply: {BOLD}{WHITE}npx torusguard apply{RESET} (CLI Human Gate)", border="โ", border_color=GREEN))
|
|
642
|
+
print(box_line(f"Auto-Apply Flag: {CYAN}npx torusguard apply --yes{RESET} (Automated mode)", border="โ", border_color=GREEN))
|
|
643
|
+
print(box_line(f"AI IDE Chat: Run {CYAN}/torusguard-apply{RESET} in your AI chat", border="โ", border_color=GREEN))
|
|
644
|
+
print(border_bottom(border_color=GREEN, double=True))
|
|
645
|
+
print()
|
|
595
646
|
else:
|
|
596
647
|
print(f" {YELLOW}โน No automatic patch templates matched current findings.{RESET}")
|
|
597
648
|
print(f" {GRAY}Findings require architectural refactoring or AI-assisted guidance.{RESET}\n")
|
|
@@ -603,7 +654,7 @@ def execute_harden(target_root: Path, run_id_arg: Optional[str] = None) -> Dict[
|
|
|
603
654
|
print()
|
|
604
655
|
|
|
605
656
|
return {
|
|
606
|
-
"status": "success",
|
|
657
|
+
"status": "dry_run" if dry_run else "success",
|
|
607
658
|
"run_folder": str(run_folder),
|
|
608
659
|
"bundles_count": len(bundles),
|
|
609
660
|
"bundles": bundles
|
|
@@ -613,12 +664,15 @@ def execute_harden(target_root: Path, run_id_arg: Optional[str] = None) -> Dict[
|
|
|
613
664
|
def main():
|
|
614
665
|
parser = argparse.ArgumentParser(description="TorusGuard Autonomous Governed Remediation Engine")
|
|
615
666
|
parser.add_argument("path", nargs="?", default=".", help="Target project root directory")
|
|
667
|
+
parser.add_argument("--target", "-t", help="Target project root directory (alias for path)")
|
|
616
668
|
parser.add_argument("--run", "-r", help="Explicit run ID to harden (default: latest audit run)")
|
|
669
|
+
parser.add_argument("--severity", "-s", choices=["critical", "high", "medium", "low"], default="medium", help="Severity floor for patch generation")
|
|
670
|
+
parser.add_argument("--dry-run", action="store_true", help="Preview patch diffs without writing files to disk")
|
|
617
671
|
parser.add_argument("--json", action="store_true", help="Output raw JSON")
|
|
618
672
|
args = parser.parse_args()
|
|
619
673
|
|
|
620
|
-
target = Path(args.path).resolve()
|
|
621
|
-
result = execute_harden(target, run_id_arg=args.run)
|
|
674
|
+
target = Path(args.target or args.path).resolve()
|
|
675
|
+
result = execute_harden(target, run_id_arg=args.run, severity_floor=args.severity, dry_run=args.dry_run)
|
|
622
676
|
|
|
623
677
|
if args.json:
|
|
624
678
|
print(json.dumps(result, indent=2))
|