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
|
@@ -9,6 +9,7 @@ import sys
|
|
|
9
9
|
import json
|
|
10
10
|
import hashlib
|
|
11
11
|
import argparse
|
|
12
|
+
from pathlib import Path
|
|
12
13
|
from typing import List, Dict, Any
|
|
13
14
|
|
|
14
15
|
def generate_sarif(findings: List[Dict[str, Any]], run_id: str = "default", category: str = "torusguard/static") -> Dict[str, Any]:
|
|
@@ -76,7 +77,7 @@ def generate_sarif(findings: List[Dict[str, Any]], run_id: str = "default", cate
|
|
|
76
77
|
"tool": {
|
|
77
78
|
"driver": {
|
|
78
79
|
"name": "TorusGuard",
|
|
79
|
-
"semanticVersion": "1.3.
|
|
80
|
+
"semanticVersion": "1.3.6",
|
|
80
81
|
"informationUri": "https://github.com/githubmofo/TorusGuard",
|
|
81
82
|
"rules": list(rules_map.values())
|
|
82
83
|
}
|
|
@@ -95,22 +96,61 @@ def main():
|
|
|
95
96
|
parser = argparse.ArgumentParser(description="TorusGuard SARIF v2.1.0 Exporter")
|
|
96
97
|
parser.add_argument("--input", "-i", help="Path to findings JSON file")
|
|
97
98
|
parser.add_argument("--output", "-o", help="Output path for sarif.json")
|
|
98
|
-
parser.add_argument("--
|
|
99
|
+
parser.add_argument("--root", "-r", help="Project root override")
|
|
100
|
+
parser.add_argument("--run-id", default=None, help="Unique execution Run ID")
|
|
101
|
+
parser.add_argument("--stdout", action="store_true", help="Print SARIF JSON to stdout")
|
|
99
102
|
args = parser.parse_args()
|
|
100
103
|
|
|
104
|
+
root = Path(args.root).resolve() if args.root else Path.cwd().resolve()
|
|
101
105
|
findings = []
|
|
106
|
+
run_id = args.run_id or "run-default"
|
|
107
|
+
|
|
102
108
|
if args.input:
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
in_path = Path(args.input)
|
|
110
|
+
if not in_path.is_absolute():
|
|
111
|
+
in_path = (root / in_path).resolve()
|
|
112
|
+
if in_path.is_file():
|
|
113
|
+
with open(in_path, "r", encoding="utf-8") as f:
|
|
114
|
+
findings = json.load(f)
|
|
115
|
+
else:
|
|
116
|
+
# Auto-discover latest audit run findings
|
|
117
|
+
runs_dir = root / ".torusguard" / "runs"
|
|
118
|
+
if runs_dir.is_dir():
|
|
119
|
+
run_folders = sorted(
|
|
120
|
+
[d for d in runs_dir.iterdir() if d.is_dir() and (d / "findings.json").is_file()],
|
|
121
|
+
key=lambda p: p.stat().st_mtime,
|
|
122
|
+
reverse=True
|
|
123
|
+
)
|
|
124
|
+
if run_folders:
|
|
125
|
+
latest_run = run_folders[0]
|
|
126
|
+
run_id = args.run_id or latest_run.name
|
|
127
|
+
findings_file = latest_run / "findings.json"
|
|
128
|
+
try:
|
|
129
|
+
with open(findings_file, "r", encoding="utf-8") as f:
|
|
130
|
+
findings = json.load(f)
|
|
131
|
+
except Exception:
|
|
132
|
+
findings = []
|
|
105
133
|
|
|
106
|
-
sarif = generate_sarif(findings, run_id=
|
|
134
|
+
sarif = generate_sarif(findings, run_id=run_id)
|
|
107
135
|
|
|
108
136
|
if args.output:
|
|
109
|
-
|
|
137
|
+
out_path = Path(args.output)
|
|
138
|
+
if not out_path.is_absolute():
|
|
139
|
+
out_path = (root / out_path).resolve()
|
|
140
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
141
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
110
142
|
json.dump(sarif, f, indent=2)
|
|
111
|
-
print(f"SARIF log written to: {
|
|
112
|
-
|
|
143
|
+
print(f"[SUCCESS] SARIF log written to: {out_path}")
|
|
144
|
+
elif args.stdout:
|
|
113
145
|
print(json.dumps(sarif, indent=2))
|
|
146
|
+
else:
|
|
147
|
+
# Default to writing in .torusguard/runs/results-latest.sarif
|
|
148
|
+
default_sarif = root / ".torusguard" / "runs" / "results-latest.sarif"
|
|
149
|
+
default_sarif.parent.mkdir(parents=True, exist_ok=True)
|
|
150
|
+
with open(default_sarif, "w", encoding="utf-8") as f:
|
|
151
|
+
json.dump(sarif, f, indent=2)
|
|
152
|
+
print(f"[SUCCESS] SARIF log written to: {default_sarif}")
|
|
153
|
+
|
|
114
154
|
|
|
115
155
|
if __name__ == "__main__":
|
|
116
156
|
main()
|
|
@@ -221,6 +221,24 @@ def detect_stack(project_root: Path) -> dict[str, Any]:
|
|
|
221
221
|
"indicator": "Flask application instantiation"
|
|
222
222
|
})
|
|
223
223
|
profile["recommended_references"].append("flask-security.md")
|
|
224
|
+
elif "tornado" in content or "tornado.web" in content:
|
|
225
|
+
add_to_list(profile, "languages_found", "Python")
|
|
226
|
+
profile["ecosystem_family"] = "python"
|
|
227
|
+
add_to_list(profile, "frameworks_found", "Tornado")
|
|
228
|
+
profile["confidence"] = "Confirmed"
|
|
229
|
+
profile["detection_evidence"].append({
|
|
230
|
+
"file": str(py_file.relative_to(project_root)),
|
|
231
|
+
"indicator": "Tornado application"
|
|
232
|
+
})
|
|
233
|
+
elif "starlette" in content:
|
|
234
|
+
add_to_list(profile, "languages_found", "Python")
|
|
235
|
+
profile["ecosystem_family"] = "python"
|
|
236
|
+
add_to_list(profile, "frameworks_found", "Starlette")
|
|
237
|
+
profile["confidence"] = "Confirmed"
|
|
238
|
+
profile["detection_evidence"].append({
|
|
239
|
+
"file": str(py_file.relative_to(project_root)),
|
|
240
|
+
"indicator": "Starlette application"
|
|
241
|
+
})
|
|
224
242
|
|
|
225
243
|
if "sqlalchemy" in content:
|
|
226
244
|
add_to_list(profile, "data_layers_found", "SQLAlchemy")
|
|
@@ -286,11 +304,27 @@ def detect_stack(project_root: Path) -> dict[str, Any]:
|
|
|
286
304
|
profile["confidence"] = "Confirmed"
|
|
287
305
|
profile["detection_evidence"].append({"file": "package.json", "indicator": "express dependency"})
|
|
288
306
|
profile["recommended_references"].append("express-security.md")
|
|
307
|
+
elif "fastify" in deps:
|
|
308
|
+
add_to_list(profile, "frameworks_found", "Fastify")
|
|
309
|
+
profile["confidence"] = "Confirmed"
|
|
310
|
+
profile["detection_evidence"].append({"file": "package.json", "indicator": "fastify dependency"})
|
|
311
|
+
elif "koa" in deps:
|
|
312
|
+
add_to_list(profile, "frameworks_found", "Koa")
|
|
313
|
+
profile["confidence"] = "Confirmed"
|
|
314
|
+
profile["detection_evidence"].append({"file": "package.json", "indicator": "koa dependency"})
|
|
315
|
+
elif "@remix-run/react" in deps or "@remix-run/node" in deps:
|
|
316
|
+
add_to_list(profile, "frameworks_found", "Remix")
|
|
317
|
+
profile["confidence"] = "Confirmed"
|
|
318
|
+
profile["detection_evidence"].append({"file": "package.json", "indicator": "Remix dependency"})
|
|
289
319
|
elif "react" in deps:
|
|
290
320
|
add_to_list(profile, "frameworks_found", "React / Vite")
|
|
291
321
|
profile["confidence"] = "Confirmed"
|
|
292
322
|
profile["detection_evidence"].append({"file": "package.json", "indicator": "react dependency"})
|
|
293
323
|
profile["recommended_references"].append("react-vite-security.md")
|
|
324
|
+
elif "vite" in deps:
|
|
325
|
+
add_to_list(profile, "frameworks_found", "Vite")
|
|
326
|
+
profile["confidence"] = "Confirmed"
|
|
327
|
+
profile["detection_evidence"].append({"file": "package.json", "indicator": "vite dependency"})
|
|
294
328
|
|
|
295
329
|
# ORM / Data layer detection
|
|
296
330
|
if "@prisma/client" in deps or "prisma" in deps:
|
|
@@ -433,6 +467,8 @@ def detect_stack(project_root: Path) -> dict[str, Any]:
|
|
|
433
467
|
|
|
434
468
|
if "Microsoft.NET.Sdk.Web" in csproj_content or "Microsoft.AspNetCore" in csproj_content or "Swashbuckle" in csproj_content:
|
|
435
469
|
add_to_list(profile, "frameworks_found", "ASP.NET Core")
|
|
470
|
+
if list(project_root.glob("**/*.razor")) or "Microsoft.AspNetCore.Components" in csproj_content or "blazor" in csproj_content.lower():
|
|
471
|
+
add_to_list(profile, "frameworks_found", "Blazor")
|
|
436
472
|
if "Microsoft.EntityFrameworkCore" in csproj_content:
|
|
437
473
|
add_to_list(profile, "data_layers_found", "Entity Framework Core")
|
|
438
474
|
elif "Dapper" in csproj_content:
|
|
@@ -442,11 +478,17 @@ def detect_stack(project_root: Path) -> dict[str, Any]:
|
|
|
442
478
|
# G. PHP Ecosystem
|
|
443
479
|
# -------------------------------------------------------------------------
|
|
444
480
|
composer_json = project_root / "composer.json"
|
|
445
|
-
|
|
481
|
+
is_wordpress = (project_root / "wp-config.php").is_file() or (project_root / "wp-load.php").is_file() or (project_root / "wp-content").is_dir()
|
|
482
|
+
if composer_json.is_file() or is_wordpress:
|
|
446
483
|
add_to_list(profile, "languages_found", "PHP")
|
|
447
484
|
profile["ecosystem_family"] = "php"
|
|
448
485
|
profile["confidence"] = "Confirmed"
|
|
449
|
-
|
|
486
|
+
if is_wordpress:
|
|
487
|
+
add_to_list(profile, "frameworks_found", "WordPress")
|
|
488
|
+
add_to_list(profile, "data_layers_found", "MySQL / wpdb")
|
|
489
|
+
profile["detection_evidence"].append({"file": "wp-config.php" if (project_root / "wp-config.php").is_file() else "wp-content", "indicator": "WordPress installation"})
|
|
490
|
+
if composer_json.is_file():
|
|
491
|
+
profile["detection_evidence"].append({"file": "composer.json", "indicator": "PHP Composer manifest"})
|
|
450
492
|
profile["recommended_rules"].extend(["TG-SEC-*", "TG-INPUT-001", "TG-INPUT-002", "TG-PLATFORM-*"])
|
|
451
493
|
profile["recommended_references"].append("polyglot-security-matrix.md")
|
|
452
494
|
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard Diagnostic Status Engine (v1.4.0)
|
|
4
|
+
Displays workspace security posture, detected stack, active rules, historical runs,
|
|
5
|
+
golden recipes, and runtime scope validity in mathematically aligned 75-column cards.
|
|
6
|
+
Adheres to Python Pro & Python Patterns standards.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
import json
|
|
13
|
+
import argparse
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from dataclasses import dataclass, asdict
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
# Import term_ui for 75-column card formatting
|
|
19
|
+
try:
|
|
20
|
+
from term_ui import (
|
|
21
|
+
BOLD, DIM, RESET, CYAN, GREEN, YELLOW, WHITE, GRAY, RED,
|
|
22
|
+
card_header, card_border_top, card_border_bottom, card_divider, format_box_line
|
|
23
|
+
)
|
|
24
|
+
except ImportError:
|
|
25
|
+
scripts_dir = Path(__file__).resolve().parent
|
|
26
|
+
if str(scripts_dir) not in sys.path:
|
|
27
|
+
sys.path.insert(0, str(scripts_dir))
|
|
28
|
+
from term_ui import (
|
|
29
|
+
BOLD, DIM, RESET, CYAN, GREEN, YELLOW, WHITE, GRAY, RED,
|
|
30
|
+
card_header, card_border_top, card_border_bottom, card_divider, format_box_line
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class WorkspaceStatus:
|
|
36
|
+
version: str
|
|
37
|
+
target_path: str
|
|
38
|
+
is_initialized: bool
|
|
39
|
+
stack_detected: str
|
|
40
|
+
active_rules_count: int
|
|
41
|
+
total_runs_count: int
|
|
42
|
+
latest_run_id: str | None
|
|
43
|
+
latest_run_time: str | None
|
|
44
|
+
latest_findings: int
|
|
45
|
+
golden_recipes_count: int
|
|
46
|
+
scope_status: str
|
|
47
|
+
health_score: int
|
|
48
|
+
posture_status: str
|
|
49
|
+
|
|
50
|
+
def to_dict(self) -> dict[str, Any]:
|
|
51
|
+
return asdict(self)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def collect_status(target_dir: Path) -> WorkspaceStatus:
|
|
55
|
+
"""Inspect workspace configuration and filesystem records to construct status snapshot."""
|
|
56
|
+
target_dir = target_dir.resolve()
|
|
57
|
+
tg_dir = target_dir / ".torusguard"
|
|
58
|
+
is_init = tg_dir.is_dir()
|
|
59
|
+
|
|
60
|
+
# 1. Read config
|
|
61
|
+
version = "1.4.0"
|
|
62
|
+
stack_name = "Undetected"
|
|
63
|
+
cfg_file = tg_dir / "config" / "torusguard.json"
|
|
64
|
+
if cfg_file.is_file():
|
|
65
|
+
try:
|
|
66
|
+
with open(cfg_file, "r", encoding="utf-8") as f:
|
|
67
|
+
cfg = json.load(f)
|
|
68
|
+
version = cfg.get("version", version)
|
|
69
|
+
stack_name = cfg.get("stack", stack_name)
|
|
70
|
+
except (json.JSONDecodeError, OSError):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
if stack_name in ("Undetected", "Unknown", "None", ""):
|
|
74
|
+
try:
|
|
75
|
+
from stack_detect import detect_stack
|
|
76
|
+
p = detect_stack(target_dir)
|
|
77
|
+
parts = []
|
|
78
|
+
if p.get("language") and p["language"] != "Unknown":
|
|
79
|
+
parts.append(p["language"])
|
|
80
|
+
if p.get("framework") and p["framework"] != "None":
|
|
81
|
+
parts.append(p["framework"])
|
|
82
|
+
if parts:
|
|
83
|
+
stack_name = " / ".join(parts)
|
|
84
|
+
except Exception:
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
# 2. Count active rules
|
|
88
|
+
active_rules_count = 0
|
|
89
|
+
active_rules_dir = tg_dir / "rules" / "active"
|
|
90
|
+
if active_rules_dir.is_dir():
|
|
91
|
+
active_rules_count = sum(1 for f in active_rules_dir.glob("*.md"))
|
|
92
|
+
if active_rules_count == 0:
|
|
93
|
+
rules_root = tg_dir / "rules"
|
|
94
|
+
if rules_root.is_dir():
|
|
95
|
+
active_rules_count = sum(1 for f in rules_root.rglob("TG-*.md"))
|
|
96
|
+
if active_rules_count == 0:
|
|
97
|
+
active_rules_count = 74 # Canonical rule catalog default
|
|
98
|
+
|
|
99
|
+
# 3. Read run history
|
|
100
|
+
total_runs = 0
|
|
101
|
+
latest_run_id: str | None = None
|
|
102
|
+
latest_run_time: str | None = None
|
|
103
|
+
latest_findings = 0
|
|
104
|
+
runs_dir = tg_dir / "runs"
|
|
105
|
+
if runs_dir.is_dir():
|
|
106
|
+
run_folders = [d for d in runs_dir.iterdir() if d.is_dir() and d.name.startswith("run-")]
|
|
107
|
+
run_folders.sort(key=lambda d: d.name, reverse=True)
|
|
108
|
+
total_runs = len(run_folders)
|
|
109
|
+
if run_folders:
|
|
110
|
+
latest = run_folders[0]
|
|
111
|
+
latest_run_id = latest.name
|
|
112
|
+
manifest_file = latest / "manifest.json"
|
|
113
|
+
if manifest_file.is_file():
|
|
114
|
+
try:
|
|
115
|
+
with open(manifest_file, "r", encoding="utf-8") as f:
|
|
116
|
+
m = json.load(f)
|
|
117
|
+
latest_run_time = m.get("created_at", latest.name)
|
|
118
|
+
latest_findings = m.get("findings_count", 0)
|
|
119
|
+
except (json.JSONDecodeError, OSError):
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
# 4. Golden recipes in persistent memory
|
|
123
|
+
golden_recipes_count = 0
|
|
124
|
+
patterns_file = tg_dir / "memory" / "patterns.json"
|
|
125
|
+
if patterns_file.is_file():
|
|
126
|
+
try:
|
|
127
|
+
with open(patterns_file, "r", encoding="utf-8") as f:
|
|
128
|
+
p_data = json.load(f)
|
|
129
|
+
if isinstance(p_data, list):
|
|
130
|
+
golden_recipes_count = sum(
|
|
131
|
+
1 for p in p_data
|
|
132
|
+
if isinstance(p, dict) and (
|
|
133
|
+
p.get("pattern_type") == "golden_fix_recipe" or "recipe_data" in p or "recipe_id" in p
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
elif isinstance(p_data, dict):
|
|
137
|
+
golden_recipes_count = len(p_data.get("golden_recipes", []))
|
|
138
|
+
except (json.JSONDecodeError, OSError):
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
# 5. Scope authorization
|
|
142
|
+
scope_status = "Unconfigured"
|
|
143
|
+
scope_file = tg_dir / "config" / "scope.json"
|
|
144
|
+
if scope_file.is_file():
|
|
145
|
+
try:
|
|
146
|
+
with open(scope_file, "r", encoding="utf-8") as f:
|
|
147
|
+
s_data = json.load(f)
|
|
148
|
+
expires_at = s_data.get("expires_at")
|
|
149
|
+
if expires_at:
|
|
150
|
+
scope_status = "Authorized (TTL Active)"
|
|
151
|
+
else:
|
|
152
|
+
scope_status = "Authorized (Static)"
|
|
153
|
+
except (json.JSONDecodeError, OSError):
|
|
154
|
+
scope_status = "Error reading scope"
|
|
155
|
+
|
|
156
|
+
# 6. Posture health from security_report.md
|
|
157
|
+
health_score = 100
|
|
158
|
+
posture = "CLEAN & SECURE"
|
|
159
|
+
report_file = target_dir / "security_report.md"
|
|
160
|
+
if report_file.is_file():
|
|
161
|
+
try:
|
|
162
|
+
content = report_file.read_text(encoding="utf-8")
|
|
163
|
+
import re
|
|
164
|
+
m = re.search(r"Posture Score:\s*`(\d+)/100`", content)
|
|
165
|
+
if m:
|
|
166
|
+
health_score = int(m.group(1))
|
|
167
|
+
m_stat = re.search(r"Posture Status:\s*`([^`]+)`", content)
|
|
168
|
+
if m_stat:
|
|
169
|
+
posture = m_stat.group(1)
|
|
170
|
+
except OSError:
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
if health_score < 70:
|
|
174
|
+
posture = "ACTION NEEDED"
|
|
175
|
+
elif health_score < 90:
|
|
176
|
+
posture = "ELEVATED RISK"
|
|
177
|
+
elif health_score == 100:
|
|
178
|
+
posture = "CLEAN & SECURE"
|
|
179
|
+
|
|
180
|
+
return WorkspaceStatus(
|
|
181
|
+
version=version,
|
|
182
|
+
target_path=str(target_dir),
|
|
183
|
+
is_initialized=is_init,
|
|
184
|
+
stack_detected=stack_name,
|
|
185
|
+
active_rules_count=active_rules_count,
|
|
186
|
+
total_runs_count=total_runs,
|
|
187
|
+
latest_run_id=latest_run_id,
|
|
188
|
+
latest_run_time=latest_run_time,
|
|
189
|
+
latest_findings=latest_findings,
|
|
190
|
+
golden_recipes_count=golden_recipes_count,
|
|
191
|
+
scope_status=scope_status,
|
|
192
|
+
health_score=health_score,
|
|
193
|
+
posture_status=posture,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def print_status_card(status: WorkspaceStatus) -> None:
|
|
198
|
+
"""Render standardized 75-column diagnostic status cards."""
|
|
199
|
+
print()
|
|
200
|
+
print(card_header(
|
|
201
|
+
"🛡️ T O R U S G U A R D S T A T U S",
|
|
202
|
+
"Workspace Diagnostic Overview & Posture Snapshot",
|
|
203
|
+
f"v{status.version}"
|
|
204
|
+
))
|
|
205
|
+
print()
|
|
206
|
+
|
|
207
|
+
# Card 1: Workspace & Stack
|
|
208
|
+
print(card_border_top("Workspace Environment", CYAN))
|
|
209
|
+
init_str = f"{GREEN}Initialized (.torusguard/ active){RESET}" if status.is_initialized else f"{RED}Uninitialized (Run: npx torusguard init){RESET}"
|
|
210
|
+
print(format_box_line(f"Workspace: {WHITE}{status.target_path}{RESET}", 67))
|
|
211
|
+
print(format_box_line(f"Status: {init_str}", 67))
|
|
212
|
+
print(format_box_line(f"Stack: {BOLD}{WHITE}{status.stack_detected}{RESET}", 67))
|
|
213
|
+
print(format_box_line(f"Active Rules: {GREEN}{status.active_rules_count}{RESET} canonical rules enabled across 18 families", 67))
|
|
214
|
+
print(card_border_bottom(CYAN))
|
|
215
|
+
print()
|
|
216
|
+
|
|
217
|
+
# Card 2: Run History & Memory
|
|
218
|
+
print(card_border_top("Run History & Memory Engine", YELLOW))
|
|
219
|
+
print(format_box_line(f"Total Runs: {WHITE}{status.total_runs_count}{RESET} historical audit runs", 67, border_color=YELLOW))
|
|
220
|
+
if status.latest_run_id:
|
|
221
|
+
print(format_box_line(f"Latest Run: {CYAN}{status.latest_run_id}{RESET}", 67, border_color=YELLOW))
|
|
222
|
+
print(format_box_line(f"Run Timestamp: {DIM}{status.latest_run_time or 'N/A'}{RESET}", 67, border_color=YELLOW))
|
|
223
|
+
print(format_box_line(f"Run Findings: {WHITE}{status.latest_findings}{RESET} vulnerabilities discovered", 67, border_color=YELLOW))
|
|
224
|
+
else:
|
|
225
|
+
print(format_box_line(f"Latest Run: {DIM}No runs recorded yet (Run: npx torusguard audit){RESET}", 67, border_color=YELLOW))
|
|
226
|
+
print(format_box_line(f"Golden Recipes: {GREEN}{status.golden_recipes_count}{RESET} verified fix patterns distilled in memory", 67, border_color=YELLOW))
|
|
227
|
+
print(format_box_line(f"Runtime Scope: {WHITE}{status.scope_status}{RESET}", 67, border_color=YELLOW))
|
|
228
|
+
print(card_border_bottom(YELLOW))
|
|
229
|
+
print()
|
|
230
|
+
|
|
231
|
+
# Card 3: Security Posture
|
|
232
|
+
posture_color = GREEN if status.health_score >= 90 else (YELLOW if status.health_score >= 70 else RED)
|
|
233
|
+
print(card_border_top("Security Health Posture", posture_color, double=True))
|
|
234
|
+
print(format_box_line(f"Health Score: {posture_color}{BOLD}{status.health_score}/100{RESET}", 67, border="║", border_color=posture_color))
|
|
235
|
+
print(format_box_line(f"Posture State: {posture_color}{BOLD}{status.posture_status}{RESET}", 67, border="║", border_color=posture_color))
|
|
236
|
+
print(format_box_line(f"Living Ledger: {CYAN}security_report.md (Synchronized){RESET}", 67, border="║", border_color=posture_color))
|
|
237
|
+
print(card_border_bottom(posture_color, double=True))
|
|
238
|
+
print()
|
|
239
|
+
|
|
240
|
+
# Quick Next Actions
|
|
241
|
+
print(card_border_top("Available Lifecycle Actions", GRAY))
|
|
242
|
+
print(format_box_line(f"Audit Codebase: {GREEN}npx torusguard audit{RESET}", 67, border_color=GRAY))
|
|
243
|
+
print(format_box_line(f"Harden Patches: {GREEN}npx torusguard harden{RESET}", 67, border_color=GRAY))
|
|
244
|
+
print(format_box_line(f"View Recipes: {GREEN}npx torusguard recipes{RESET}", 67, border_color=GRAY))
|
|
245
|
+
print(format_box_line(f"HTML Dashboard: {GREEN}npx torusguard report --html{RESET}", 67, border_color=GRAY))
|
|
246
|
+
print(card_border_bottom(GRAY))
|
|
247
|
+
print()
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def main() -> None:
|
|
251
|
+
parser = argparse.ArgumentParser(description="TorusGuard Workspace Diagnostic Status Engine")
|
|
252
|
+
parser.add_argument("path", nargs="?", default=".", help="Target project root directory")
|
|
253
|
+
parser.add_argument("--target", "-t", help="Target project root directory (alias for path)")
|
|
254
|
+
parser.add_argument("--json", action="store_true", help="Output raw JSON snapshot")
|
|
255
|
+
args = parser.parse_args()
|
|
256
|
+
|
|
257
|
+
target = Path(args.target or args.path).resolve()
|
|
258
|
+
status = collect_status(target)
|
|
259
|
+
|
|
260
|
+
if args.json:
|
|
261
|
+
print(json.dumps(status.to_dict(), indent=2))
|
|
262
|
+
else:
|
|
263
|
+
print_status_card(status)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
if __name__ == "__main__":
|
|
267
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
TorusGuard Unified Terminal UI Engine (v1.3.
|
|
3
|
+
TorusGuard Unified Terminal UI Engine (v1.3.6)
|
|
4
4
|
Provides mathematically exact 75-column card formatting, ANSI-stripping,
|
|
5
5
|
Unicode/emoji visual width calculation, and visual truncation with ellipsis.
|
|
6
6
|
Pure Python 3.10+ standard library (zero external dependencies).
|
|
@@ -1,72 +1,75 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: torusguard
|
|
3
|
-
description: Universal autonomous security engine:
|
|
4
|
-
version: 1.3.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# TorusGuard Master Security Engine & Command Router
|
|
8
|
-
|
|
9
|
-
**Core Invariant:** If the browser or client receives it, users can inspect it. Never expose database credentials, master keys, or private API secrets in client bundles. Always isolate multi-tenant database queries.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Command Catalog: Terminal CLI & AI Chat Parity
|
|
14
|
-
|
|
15
|
-
TorusGuard operates with 100% feature parity across both the terminal CLI and AI chat slash commands:
|
|
16
|
-
|
|
17
|
-
| Capability | Terminal CLI Command | AI Chat Slash Command | Specialist Skill | Purpose |
|
|
18
|
-
| :--- | :--- | :--- | :--- | :--- |
|
|
19
|
-
| **Init** | `npx torusguard init` | `/torusguard init` | `skills/torusguard-init` | Stack discovery, rule activation, workspace scaffolding |
|
|
20
|
-
| **Status** | `npx torusguard status` | `/torusguard status` | `skills/torusguard-status` | Posture score, active rules, run history, scope check |
|
|
21
|
-
| **Audit** | `npx torusguard audit` | `/torusguard audit` | `skills/torusguard-audit` | Static AST scan, invariant fingerprinting, confidence scoring |
|
|
22
|
-
| **Verify** | `npx torusguard verify` | `/torusguard verify` | `skills/torusguard-verify` | Evidence sufficiency audit & line match calibration |
|
|
23
|
-
| **Harden** | `npx torusguard harden` | `/torusguard harden` | `skills/torusguard-harden` | Ponytail patch formulation ($\le 35$ add, $\le 25$ del) |
|
|
24
|
-
| **Apply** | `npx torusguard apply [--yes]` | `/torusguard apply` | `skills/torusguard-apply` | Human Gate review, `.bak` snapshots, patch application |
|
|
25
|
-
| **Rollback** | `npx torusguard rollback` | `/torusguard rollback` | `skills/torusguard-apply` | Instant 1-step rollback from pre-apply snapshots |
|
|
26
|
-
| **Recheck** | `npx torusguard recheck` | `/torusguard recheck` | `skills/torusguard-recheck` | Targeted differential AST scan, fix closure verification |
|
|
27
|
-
| **Recipes** | `npx torusguard recipes` | `/torusguard recipes` | `skills/torusguard-harden` | Explore verified Golden Fix Recipes from persistent memory |
|
|
28
|
-
| **Report** | `npx torusguard report --html` | `/torusguard report` | `skills/torusguard-report` | Executive posture reporting, SARIF v2.1.0 & visual HTML |
|
|
29
|
-
| **Authorize** | `npx torusguard authorize` | `/torusguard authorize` | `skills/torusguard-authorize`| Legal scope definition & safety boundaries |
|
|
30
|
-
| **Validate** | `npx torusguard web-validate` | `/torusguard web-validate` | `skills/torusguard-web-validate`| Authorized non-destructive HTTP probing |
|
|
31
|
-
| **Exploit** | `npx torusguard exploit-check` | `/torusguard exploit-check`| `skills/torusguard-exploit-check`| Bounded single-step exploitability confirmation |
|
|
32
|
-
| **Full** | `npx torusguard full` | `/torusguard full` | `skills/torusguard-full` | End-to-end 7-stage closed-loop execution |
|
|
33
|
-
| **Sync** | `npx torusguard rules sync` | `/torusguard rules sync` | `skills/torusguard-init` | Synchronize rules across AI editors (Cursor, Claude, Antigravity) |
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## Non-Negotiable Invariants
|
|
38
|
-
|
|
39
|
-
1. **Browser-Code Truth:** If the client receives it, it is public. Zero hardcoded secrets (`SUPABASE_SERVICE_ROLE_KEY`, private tokens, live API keys) in frontend code.
|
|
40
|
-
2. **Multi-Tenant Isolation:** All database lookups must be scoped by organization or user ownership (`tenant_id`, `organization_id`, `where: { tenantId }`).
|
|
41
|
-
3. **Ponytail Churn Bounds:** Patches must be minimal and surgical ($\le 35$ additions, $\le 25$ deletions). Never perform full-file rewrites.
|
|
42
|
-
4. **Standardized 75-Column Terminal:** All CLI terminal output is strictly normalized to 75 visual columns with Unicode emoji width calculation, ANSI escape handling, and visual truncation with ellipsis (`...`).
|
|
43
|
-
5. **Zero Security Bypasses:** Never insert `# nosec`, `verify=False`, `InsecureSkipVerify: true`, `[AllowAnonymous]`, or `csrf().disable()`.
|
|
44
|
-
6. **Snapshots Before Edits:** Every code modification must capture a byte-for-byte pre-apply backup in `.torusguard/snapshots/<run_id>/` before touching disk code.
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Workspace Layout Structure
|
|
49
|
-
```
|
|
50
|
-
.torusguard/
|
|
51
|
-
├── config/
|
|
52
|
-
│ ├── torusguard.json # Detected stack, settings, and rule counts
|
|
53
|
-
│ └── scope.json # Authorized runtime validation targets & TTL
|
|
54
|
-
├── memory/
|
|
55
|
-
│ ├── context.json # Aggregated security memory context
|
|
56
|
-
│ ├── patterns.json # Distilled Golden Fix Recipes
|
|
57
|
-
│ └── events.json # Historical audit, apply, and recheck events
|
|
58
|
-
├── rules/
|
|
59
|
-
│ └── active/ # Active TG-* rule definitions
|
|
60
|
-
├── runs/
|
|
61
|
-
│ └── run-YYYYMMDD-HHMMSS-audit/
|
|
62
|
-
│ ├── findings.json # Machine-readable AST findings
|
|
63
|
-
│ ├── findings.md # Actionable markdown finding cards
|
|
64
|
-
│ ├── remediation.md # Formulated candidate patch catalog
|
|
65
|
-
│ ├── diff_summary.md # Summary of applied diffs
|
|
66
|
-
│ ├── recheck.md # Differential recheck status transitions
|
|
67
|
-
│ ├── report.html # Single-file visual dark-mode HTML report
|
|
68
|
-
│ ├── results.sarif # OASIS SARIF v2.1.0 log
|
|
69
|
-
│ └── bundles/ # Formulated Ponytail remediation bundles
|
|
70
|
-
└── snapshots/
|
|
71
|
-
└── run-YYYYMMDD-HHMMSS-audit/ # Pre-apply .bak files for instant rollback
|
|
72
|
-
```
|
|
1
|
+
---
|
|
2
|
+
name: torusguard
|
|
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, SARIF v2.1.0 exports, and persistent security memory context.
|
|
4
|
+
version: 1.3.6
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# TorusGuard Master Security Engine & Command Router
|
|
8
|
+
|
|
9
|
+
**Core Invariant:** If the browser or client receives it, users can inspect it. Never expose database credentials, master keys, or private API secrets in client bundles. Always isolate multi-tenant database queries.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Command Catalog: Terminal CLI & AI Chat Parity
|
|
14
|
+
|
|
15
|
+
TorusGuard operates with 100% feature parity across both the terminal CLI and AI chat slash commands:
|
|
16
|
+
|
|
17
|
+
| Capability | Terminal CLI Command | AI Chat Slash Command | Specialist Skill | Purpose |
|
|
18
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
19
|
+
| **Init** | `npx torusguard init` | `/torusguard init` | `skills/torusguard-init` | Stack discovery, rule activation, workspace scaffolding |
|
|
20
|
+
| **Status** | `npx torusguard status` | `/torusguard status` | `skills/torusguard-status` | Posture score, active rules, run history, scope check |
|
|
21
|
+
| **Audit** | `npx torusguard audit` | `/torusguard audit` | `skills/torusguard-audit` | Static AST scan, invariant fingerprinting, confidence scoring |
|
|
22
|
+
| **Verify** | `npx torusguard verify` | `/torusguard verify` | `skills/torusguard-verify` | Evidence sufficiency audit & line match calibration |
|
|
23
|
+
| **Harden** | `npx torusguard harden` | `/torusguard harden` | `skills/torusguard-harden` | Ponytail patch formulation ($\le 35$ add, $\le 25$ del) |
|
|
24
|
+
| **Apply** | `npx torusguard apply [--yes]` | `/torusguard apply` | `skills/torusguard-apply` | Human Gate review, `.bak` snapshots, patch application |
|
|
25
|
+
| **Rollback** | `npx torusguard rollback` | `/torusguard rollback` | `skills/torusguard-apply` | Instant 1-step rollback from pre-apply snapshots |
|
|
26
|
+
| **Recheck** | `npx torusguard recheck` | `/torusguard recheck` | `skills/torusguard-recheck` | Targeted differential AST scan, fix closure verification |
|
|
27
|
+
| **Recipes** | `npx torusguard recipes` | `/torusguard recipes` | `skills/torusguard-harden` | Explore verified Golden Fix Recipes from persistent memory |
|
|
28
|
+
| **Report** | `npx torusguard report --html` | `/torusguard report` | `skills/torusguard-report` | Executive posture reporting, SARIF v2.1.0 & visual HTML |
|
|
29
|
+
| **Authorize** | `npx torusguard authorize` | `/torusguard authorize` | `skills/torusguard-authorize`| Legal scope definition & safety boundaries |
|
|
30
|
+
| **Validate** | `npx torusguard web-validate` | `/torusguard web-validate` | `skills/torusguard-web-validate`| Authorized non-destructive HTTP probing |
|
|
31
|
+
| **Exploit** | `npx torusguard exploit-check` | `/torusguard exploit-check`| `skills/torusguard-exploit-check`| Bounded single-step exploitability confirmation |
|
|
32
|
+
| **Full** | `npx torusguard full` | `/torusguard full` | `skills/torusguard-full` | End-to-end 7-stage closed-loop execution |
|
|
33
|
+
| **Sync** | `npx torusguard rules sync` | `/torusguard rules sync` | `skills/torusguard-init` | Synchronize rules across AI editors (Cursor, Claude, Antigravity) |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Non-Negotiable Invariants
|
|
38
|
+
|
|
39
|
+
1. **Browser-Code Truth:** If the client receives it, it is public. Zero hardcoded secrets (`SUPABASE_SERVICE_ROLE_KEY`, private tokens, live API keys) in frontend code.
|
|
40
|
+
2. **Multi-Tenant Isolation:** All database lookups must be scoped by organization or user ownership (`tenant_id`, `organization_id`, `where: { tenantId }`).
|
|
41
|
+
3. **Ponytail Churn Bounds:** Patches must be minimal and surgical ($\le 35$ additions, $\le 25$ deletions). Never perform full-file rewrites.
|
|
42
|
+
4. **Standardized 75-Column Terminal:** All CLI terminal output is strictly normalized to 75 visual columns with Unicode emoji width calculation, ANSI escape handling, and visual truncation with ellipsis (`...`).
|
|
43
|
+
5. **Zero Security Bypasses:** Never insert `# nosec`, `verify=False`, `InsecureSkipVerify: true`, `[AllowAnonymous]`, or `csrf().disable()`.
|
|
44
|
+
6. **Snapshots Before Edits:** Every code modification must capture a byte-for-byte pre-apply backup in `.torusguard/snapshots/<run_id>/` before touching disk code.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Workspace Layout Structure
|
|
49
|
+
```
|
|
50
|
+
.torusguard/
|
|
51
|
+
├── config/
|
|
52
|
+
│ ├── torusguard.json # Detected stack, settings, and rule counts
|
|
53
|
+
│ └── scope.json # Authorized runtime validation targets & TTL
|
|
54
|
+
├── memory/
|
|
55
|
+
│ ├── context.json # Aggregated security memory context
|
|
56
|
+
│ ├── patterns.json # Distilled Golden Fix Recipes
|
|
57
|
+
│ └── events.json # Historical audit, apply, and recheck events
|
|
58
|
+
├── rules/
|
|
59
|
+
│ └── active/ # Active TG-* rule definitions
|
|
60
|
+
├── runs/
|
|
61
|
+
│ └── run-YYYYMMDD-HHMMSS-audit/
|
|
62
|
+
│ ├── findings.json # Machine-readable AST findings
|
|
63
|
+
│ ├── findings.md # Actionable markdown finding cards
|
|
64
|
+
│ ├── remediation.md # Formulated candidate patch catalog
|
|
65
|
+
│ ├── diff_summary.md # Summary of applied diffs
|
|
66
|
+
│ ├── recheck.md # Differential recheck status transitions
|
|
67
|
+
│ ├── report.html # Single-file visual dark-mode HTML report
|
|
68
|
+
│ ├── results.sarif # OASIS SARIF v2.1.0 log
|
|
69
|
+
│ └── bundles/ # Formulated Ponytail remediation bundles
|
|
70
|
+
└── snapshots/
|
|
71
|
+
└── run-YYYYMMDD-HHMMSS-audit/ # Pre-apply .bak files for instant rollback
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Living Report Ground Truth
|
|
75
|
+
- Read `security_report.md` in the workspace root before taking any action. Update the relevant finding card after completing remediation.
|