torusguard 0.9.2

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.
Files changed (236) hide show
  1. package/.torusguard/.manifest.json +95 -0
  2. package/.torusguard/ARCHITECTURE.md +168 -0
  3. package/.torusguard/TORUSGUARD.md +145 -0
  4. package/.torusguard/agents/auditor.md +41 -0
  5. package/.torusguard/agents/profiler.md +49 -0
  6. package/.torusguard/agents/remediator.md +41 -0
  7. package/.torusguard/agents/reviewer.md +39 -0
  8. package/.torusguard/agents/validator.md +46 -0
  9. package/.torusguard/config/scope.json +24 -0
  10. package/.torusguard/config/slash-commands.json +102 -0
  11. package/.torusguard/config/torusguard.json +30 -0
  12. package/.torusguard/references/django-security.md +43 -0
  13. package/.torusguard/references/drf-security.md +20 -0
  14. package/.torusguard/references/express-security.md +103 -0
  15. package/.torusguard/references/fastapi-security.md +20 -0
  16. package/.torusguard/references/firebase-security.md +78 -0
  17. package/.torusguard/references/flask-security.md +20 -0
  18. package/.torusguard/references/nextjs-security.md +96 -0
  19. package/.torusguard/references/react-vite-security.md +97 -0
  20. package/.torusguard/references/sqlalchemy-security.md +16 -0
  21. package/.torusguard/references/supabase-security.md +84 -0
  22. package/.torusguard/rules/README.md +62 -0
  23. package/.torusguard/rules/TORUSGUARD.md +145 -0
  24. package/.torusguard/rules/active/.gitkeep +0 -0
  25. package/.torusguard/rules/active/TG-DIFF-001.md +20 -0
  26. package/.torusguard/rules/active/TG-DIFF-002.md +20 -0
  27. package/.torusguard/rules/active/TG-DIFF-003.md +19 -0
  28. package/.torusguard/runs/.gitkeep +0 -0
  29. package/.torusguard/schemas/authorization.schema.json +81 -0
  30. package/.torusguard/schemas/confidence.schema.json +72 -0
  31. package/.torusguard/schemas/evidence.schema.json +66 -0
  32. package/.torusguard/schemas/finding.schema.json +164 -0
  33. package/.torusguard/schemas/provenance.schema.json +46 -0
  34. package/.torusguard/schemas/remediation.schema.json +59 -0
  35. package/.torusguard/schemas/retest.schema.json +53 -0
  36. package/.torusguard/schemas/runtime-evidence.schema.json +72 -0
  37. package/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
  38. package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
  39. package/.torusguard/scripts/diff_guard.py +171 -0
  40. package/.torusguard/scripts/finding_scorer.py +86 -0
  41. package/.torusguard/scripts/manifest_builder.py +130 -0
  42. package/.torusguard/scripts/monorepo_detector.py +164 -0
  43. package/.torusguard/scripts/run_manager.py +89 -0
  44. package/.torusguard/scripts/safety_gate.py +64 -0
  45. package/.torusguard/scripts/sarif_exporter.py +116 -0
  46. package/.torusguard/scripts/stack_detect.py +152 -0
  47. package/.torusguard/skills/torusguard/SKILL.md +37 -0
  48. package/.torusguard/skills/torusguard/bootstrap.py +158 -0
  49. package/.torusguard/skills/torusguard/references/auth-and-sessions.md +56 -0
  50. package/.torusguard/skills/torusguard/references/business-logic-and-abuse.md +23 -0
  51. package/.torusguard/skills/torusguard/references/cache-and-sensitive-responses.md +10 -0
  52. package/.torusguard/skills/torusguard/references/client-code-exposure.md +55 -0
  53. package/.torusguard/skills/torusguard/references/csrf-and-cross-origin.md +11 -0
  54. package/.torusguard/skills/torusguard/references/dependency-and-supply-chain.md +22 -0
  55. package/.torusguard/skills/torusguard/references/django-security.md +43 -0
  56. package/.torusguard/skills/torusguard/references/drf-security.md +20 -0
  57. package/.torusguard/skills/torusguard/references/fastapi-security.md +20 -0
  58. package/.torusguard/skills/torusguard/references/flask-security.md +20 -0
  59. package/.torusguard/skills/torusguard/references/frontend-no-db.md +53 -0
  60. package/.torusguard/skills/torusguard/references/graphql-security.md +12 -0
  61. package/.torusguard/skills/torusguard/references/input-and-injection.md +51 -0
  62. package/.torusguard/skills/torusguard/references/mass-assignment-and-property-auth.md +22 -0
  63. package/.torusguard/skills/torusguard/references/platform-hardening.md +56 -0
  64. package/.torusguard/skills/torusguard/references/python-dependencies.md +16 -0
  65. package/.torusguard/skills/torusguard/references/python-security-overview.md +12 -0
  66. package/.torusguard/skills/torusguard/references/rate-limit-and-abuse.md +57 -0
  67. package/.torusguard/skills/torusguard/references/secrets-and-config.md +64 -0
  68. package/.torusguard/skills/torusguard/references/sqlalchemy-security.md +16 -0
  69. package/.torusguard/skills/torusguard/references/ssrf-and-outbound-requests.md +46 -0
  70. package/.torusguard/skills/torusguard/references/webhook-security.md +15 -0
  71. package/.torusguard/skills/torusguard/references/websocket-security.md +12 -0
  72. package/.torusguard/skills/torusguard-apply/SKILL.md +46 -0
  73. package/.torusguard/skills/torusguard-audit/SKILL.md +70 -0
  74. package/.torusguard/skills/torusguard-authorize/SKILL.md +47 -0
  75. package/.torusguard/skills/torusguard-exploit-check/SKILL.md +64 -0
  76. package/.torusguard/skills/torusguard-full/SKILL.md +70 -0
  77. package/.torusguard/skills/torusguard-harden/SKILL.md +63 -0
  78. package/.torusguard/skills/torusguard-init/SKILL.md +52 -0
  79. package/.torusguard/skills/torusguard-recheck/SKILL.md +53 -0
  80. package/.torusguard/skills/torusguard-report/SKILL.md +54 -0
  81. package/.torusguard/skills/torusguard-status/SKILL.md +42 -0
  82. package/.torusguard/skills/torusguard-verify/SKILL.md +55 -0
  83. package/.torusguard/skills/torusguard-web-validate/SKILL.md +64 -0
  84. package/.torusguard/templates/audit-report.template.md +54 -0
  85. package/.torusguard/templates/authorization.template.md +34 -0
  86. package/.torusguard/templates/finding-card.template.md +32 -0
  87. package/.torusguard/templates/remediation-bundle.template.md +35 -0
  88. package/.torusguard/workflows/apply.md +95 -0
  89. package/.torusguard/workflows/audit.md +93 -0
  90. package/.torusguard/workflows/authorize.md +95 -0
  91. package/.torusguard/workflows/exploit-check.md +97 -0
  92. package/.torusguard/workflows/harden.md +93 -0
  93. package/.torusguard/workflows/init.md +95 -0
  94. package/.torusguard/workflows/recheck.md +95 -0
  95. package/.torusguard/workflows/report.md +95 -0
  96. package/.torusguard/workflows/status.md +95 -0
  97. package/.torusguard/workflows/verify.md +95 -0
  98. package/.torusguard/workflows/web-validate.md +95 -0
  99. package/LICENSE +21 -0
  100. package/README.md +319 -0
  101. package/bin/torusguard.js +110 -0
  102. package/install.py +98 -0
  103. package/package.json +48 -0
  104. package/skills/torusguard/SKILL.md +41 -0
  105. package/skills/torusguard/__pycache__/bootstrap.cpython-311.pyc +0 -0
  106. package/skills/torusguard/bootstrap.py +256 -0
  107. package/skills/torusguard/payload/.manifest.json +95 -0
  108. package/skills/torusguard/payload/ARCHITECTURE.md +168 -0
  109. package/skills/torusguard/payload/TORUSGUARD.md +145 -0
  110. package/skills/torusguard/payload/agents/auditor.md +41 -0
  111. package/skills/torusguard/payload/agents/profiler.md +49 -0
  112. package/skills/torusguard/payload/agents/remediator.md +41 -0
  113. package/skills/torusguard/payload/agents/reviewer.md +39 -0
  114. package/skills/torusguard/payload/agents/validator.md +46 -0
  115. package/skills/torusguard/payload/config/scope.json +24 -0
  116. package/skills/torusguard/payload/config/slash-commands.json +102 -0
  117. package/skills/torusguard/payload/config/torusguard.json +30 -0
  118. package/skills/torusguard/payload/references/django-security.md +43 -0
  119. package/skills/torusguard/payload/references/drf-security.md +20 -0
  120. package/skills/torusguard/payload/references/express-security.md +103 -0
  121. package/skills/torusguard/payload/references/fastapi-security.md +20 -0
  122. package/skills/torusguard/payload/references/firebase-security.md +78 -0
  123. package/skills/torusguard/payload/references/flask-security.md +20 -0
  124. package/skills/torusguard/payload/references/nextjs-security.md +96 -0
  125. package/skills/torusguard/payload/references/react-vite-security.md +97 -0
  126. package/skills/torusguard/payload/references/sqlalchemy-security.md +16 -0
  127. package/skills/torusguard/payload/references/supabase-security.md +84 -0
  128. package/skills/torusguard/payload/rules/README.md +62 -0
  129. package/skills/torusguard/payload/rules/TORUSGUARD.md +145 -0
  130. package/skills/torusguard/payload/rules/active/.gitkeep +0 -0
  131. package/skills/torusguard/payload/rules/active/TG-DIFF-001.md +20 -0
  132. package/skills/torusguard/payload/rules/active/TG-DIFF-002.md +20 -0
  133. package/skills/torusguard/payload/rules/active/TG-DIFF-003.md +19 -0
  134. package/skills/torusguard/payload/schemas/authorization.schema.json +81 -0
  135. package/skills/torusguard/payload/schemas/confidence.schema.json +72 -0
  136. package/skills/torusguard/payload/schemas/evidence.schema.json +66 -0
  137. package/skills/torusguard/payload/schemas/finding.schema.json +164 -0
  138. package/skills/torusguard/payload/schemas/provenance.schema.json +46 -0
  139. package/skills/torusguard/payload/schemas/remediation.schema.json +59 -0
  140. package/skills/torusguard/payload/schemas/retest.schema.json +53 -0
  141. package/skills/torusguard/payload/schemas/runtime-evidence.schema.json +72 -0
  142. package/skills/torusguard/payload/scripts/diff_guard.py +171 -0
  143. package/skills/torusguard/payload/scripts/finding_scorer.py +86 -0
  144. package/skills/torusguard/payload/scripts/manifest_builder.py +130 -0
  145. package/skills/torusguard/payload/scripts/monorepo_detector.py +164 -0
  146. package/skills/torusguard/payload/scripts/run_manager.py +89 -0
  147. package/skills/torusguard/payload/scripts/safety_gate.py +64 -0
  148. package/skills/torusguard/payload/scripts/sarif_exporter.py +116 -0
  149. package/skills/torusguard/payload/scripts/stack_detect.py +152 -0
  150. package/skills/torusguard/payload/skills/torusguard/SKILL.md +37 -0
  151. package/skills/torusguard/payload/skills/torusguard/bootstrap.py +158 -0
  152. package/skills/torusguard/payload/skills/torusguard/references/auth-and-sessions.md +56 -0
  153. package/skills/torusguard/payload/skills/torusguard/references/business-logic-and-abuse.md +23 -0
  154. package/skills/torusguard/payload/skills/torusguard/references/cache-and-sensitive-responses.md +10 -0
  155. package/skills/torusguard/payload/skills/torusguard/references/client-code-exposure.md +55 -0
  156. package/skills/torusguard/payload/skills/torusguard/references/csrf-and-cross-origin.md +11 -0
  157. package/skills/torusguard/payload/skills/torusguard/references/dependency-and-supply-chain.md +22 -0
  158. package/skills/torusguard/payload/skills/torusguard/references/django-security.md +43 -0
  159. package/skills/torusguard/payload/skills/torusguard/references/drf-security.md +20 -0
  160. package/skills/torusguard/payload/skills/torusguard/references/fastapi-security.md +20 -0
  161. package/skills/torusguard/payload/skills/torusguard/references/flask-security.md +20 -0
  162. package/skills/torusguard/payload/skills/torusguard/references/frontend-no-db.md +53 -0
  163. package/skills/torusguard/payload/skills/torusguard/references/graphql-security.md +12 -0
  164. package/skills/torusguard/payload/skills/torusguard/references/input-and-injection.md +51 -0
  165. package/skills/torusguard/payload/skills/torusguard/references/mass-assignment-and-property-auth.md +22 -0
  166. package/skills/torusguard/payload/skills/torusguard/references/platform-hardening.md +56 -0
  167. package/skills/torusguard/payload/skills/torusguard/references/python-dependencies.md +16 -0
  168. package/skills/torusguard/payload/skills/torusguard/references/python-security-overview.md +12 -0
  169. package/skills/torusguard/payload/skills/torusguard/references/rate-limit-and-abuse.md +57 -0
  170. package/skills/torusguard/payload/skills/torusguard/references/secrets-and-config.md +64 -0
  171. package/skills/torusguard/payload/skills/torusguard/references/sqlalchemy-security.md +16 -0
  172. package/skills/torusguard/payload/skills/torusguard/references/ssrf-and-outbound-requests.md +46 -0
  173. package/skills/torusguard/payload/skills/torusguard/references/webhook-security.md +15 -0
  174. package/skills/torusguard/payload/skills/torusguard/references/websocket-security.md +12 -0
  175. package/skills/torusguard/payload/skills/torusguard-apply/SKILL.md +46 -0
  176. package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +70 -0
  177. package/skills/torusguard/payload/skills/torusguard-authorize/SKILL.md +47 -0
  178. package/skills/torusguard/payload/skills/torusguard-exploit-check/SKILL.md +64 -0
  179. package/skills/torusguard/payload/skills/torusguard-full/SKILL.md +70 -0
  180. package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +63 -0
  181. package/skills/torusguard/payload/skills/torusguard-init/SKILL.md +52 -0
  182. package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +53 -0
  183. package/skills/torusguard/payload/skills/torusguard-report/SKILL.md +54 -0
  184. package/skills/torusguard/payload/skills/torusguard-status/SKILL.md +42 -0
  185. package/skills/torusguard/payload/skills/torusguard-verify/SKILL.md +55 -0
  186. package/skills/torusguard/payload/skills/torusguard-web-validate/SKILL.md +64 -0
  187. package/skills/torusguard/payload/templates/audit-report.template.md +54 -0
  188. package/skills/torusguard/payload/templates/authorization.template.md +34 -0
  189. package/skills/torusguard/payload/templates/finding-card.template.md +32 -0
  190. package/skills/torusguard/payload/templates/remediation-bundle.template.md +35 -0
  191. package/skills/torusguard/payload/workflows/apply.md +95 -0
  192. package/skills/torusguard/payload/workflows/audit.md +93 -0
  193. package/skills/torusguard/payload/workflows/authorize.md +95 -0
  194. package/skills/torusguard/payload/workflows/exploit-check.md +97 -0
  195. package/skills/torusguard/payload/workflows/harden.md +93 -0
  196. package/skills/torusguard/payload/workflows/init.md +95 -0
  197. package/skills/torusguard/payload/workflows/recheck.md +95 -0
  198. package/skills/torusguard/payload/workflows/report.md +95 -0
  199. package/skills/torusguard/payload/workflows/status.md +95 -0
  200. package/skills/torusguard/payload/workflows/verify.md +95 -0
  201. package/skills/torusguard/payload/workflows/web-validate.md +95 -0
  202. package/skills/torusguard/references/auth-and-sessions.md +56 -0
  203. package/skills/torusguard/references/business-logic-and-abuse.md +23 -0
  204. package/skills/torusguard/references/cache-and-sensitive-responses.md +10 -0
  205. package/skills/torusguard/references/client-code-exposure.md +55 -0
  206. package/skills/torusguard/references/csrf-and-cross-origin.md +11 -0
  207. package/skills/torusguard/references/dependency-and-supply-chain.md +22 -0
  208. package/skills/torusguard/references/django-security.md +43 -0
  209. package/skills/torusguard/references/drf-security.md +20 -0
  210. package/skills/torusguard/references/fastapi-security.md +20 -0
  211. package/skills/torusguard/references/flask-security.md +20 -0
  212. package/skills/torusguard/references/frontend-no-db.md +53 -0
  213. package/skills/torusguard/references/graphql-security.md +12 -0
  214. package/skills/torusguard/references/input-and-injection.md +51 -0
  215. package/skills/torusguard/references/mass-assignment-and-property-auth.md +22 -0
  216. package/skills/torusguard/references/platform-hardening.md +56 -0
  217. package/skills/torusguard/references/python-dependencies.md +16 -0
  218. package/skills/torusguard/references/python-security-overview.md +12 -0
  219. package/skills/torusguard/references/rate-limit-and-abuse.md +57 -0
  220. package/skills/torusguard/references/secrets-and-config.md +64 -0
  221. package/skills/torusguard/references/sqlalchemy-security.md +16 -0
  222. package/skills/torusguard/references/ssrf-and-outbound-requests.md +46 -0
  223. package/skills/torusguard/references/webhook-security.md +15 -0
  224. package/skills/torusguard/references/websocket-security.md +12 -0
  225. package/skills/torusguard-apply/SKILL.md +46 -0
  226. package/skills/torusguard-audit/SKILL.md +70 -0
  227. package/skills/torusguard-authorize/SKILL.md +47 -0
  228. package/skills/torusguard-exploit-check/SKILL.md +64 -0
  229. package/skills/torusguard-full/SKILL.md +70 -0
  230. package/skills/torusguard-harden/SKILL.md +63 -0
  231. package/skills/torusguard-init/SKILL.md +52 -0
  232. package/skills/torusguard-recheck/SKILL.md +53 -0
  233. package/skills/torusguard-report/SKILL.md +54 -0
  234. package/skills/torusguard-status/SKILL.md +42 -0
  235. package/skills/torusguard-verify/SKILL.md +55 -0
  236. package/skills/torusguard-web-validate/SKILL.md +64 -0
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard Monorepo & Multi-Package Workspace Detector (v0.9.3)
4
+ Discovers and profiles sub-projects across Turborepo, pnpm, npm, and Python workspaces.
5
+ Pure Python 3.10+ standard library (zero external dependencies).
6
+ """
7
+
8
+ import sys
9
+ import os
10
+ import json
11
+ import re
12
+ import argparse
13
+ from pathlib import Path
14
+ from typing import Dict, List, Any, Optional
15
+
16
+
17
+ def detect_package_info(abs_pkg_dir: Path, root: Path) -> Dict[str, Any]:
18
+ """Inspects a single directory to detect language and framework."""
19
+ rel_path = str(abs_pkg_dir.relative_to(root)).replace('\\', '/')
20
+ name = abs_pkg_dir.name
21
+ language = "unknown"
22
+ framework = "generic"
23
+
24
+ pkg_dir = abs_pkg_dir
25
+
26
+ # Check typescript / javascript
27
+ package_json = pkg_dir / "package.json"
28
+ if package_json.is_file() or list(pkg_dir.glob("*.ts")) or list(pkg_dir.glob("*.js")):
29
+ language = "typescript"
30
+ if package_json.is_file():
31
+ try:
32
+ with open(package_json, "r", encoding="utf-8") as f:
33
+ pj = json.load(f)
34
+ name = pj.get("name", name)
35
+ deps = {**pj.get("dependencies", {}), **pj.get("devDependencies", {})}
36
+ if "next" in deps:
37
+ framework = "nextjs"
38
+ elif "express" in deps:
39
+ framework = "express"
40
+ elif "react" in deps:
41
+ framework = "react"
42
+ elif "vue" in deps or "nuxt" in deps:
43
+ framework = "vue"
44
+ except Exception:
45
+ pass
46
+ elif list(pkg_dir.glob("*next*")) or "next" in pkg_dir.name:
47
+ framework = "nextjs"
48
+
49
+ # Check python
50
+ pyproject = pkg_dir / "pyproject.toml"
51
+ reqs = pkg_dir / "requirements.txt"
52
+ if pyproject.is_file() or reqs.is_file() or list(pkg_dir.glob("*.py")):
53
+ if language == "unknown":
54
+ language = "python"
55
+ content = ""
56
+ if pyproject.is_file():
57
+ content += pyproject.read_text(encoding="utf-8", errors="replace").lower()
58
+ if reqs.is_file():
59
+ content += reqs.read_text(encoding="utf-8", errors="replace").lower()
60
+ for pyf in pkg_dir.glob("*.py"):
61
+ content += pyf.read_text(encoding="utf-8", errors="replace").lower()
62
+
63
+ if "fastapi" in content or "fastapi" in pkg_dir.name:
64
+ framework = "fastapi"
65
+ elif "django" in content or "django" in pkg_dir.name:
66
+ framework = "django"
67
+ elif "flask" in content or "flask" in pkg_dir.name:
68
+ framework = "flask"
69
+
70
+ return {
71
+ "name": name,
72
+ "path": rel_path,
73
+ "language": language,
74
+ "framework": framework
75
+ }
76
+
77
+
78
+ def scan_workspace(root_dir: str = ".") -> Dict[str, Any]:
79
+ """Scans root directory for monorepo configuration and sub-packages."""
80
+ root = Path(root_dir).resolve()
81
+ monorepo_type = "single-project"
82
+ sub_packages: List[Dict[str, Any]] = []
83
+
84
+ # 1. Turborepo
85
+ if (root / "turbo.json").is_file():
86
+ monorepo_type = "turborepo"
87
+
88
+ # 2. pnpm workspace
89
+ pnpm_ws = root / "pnpm-workspace.yaml"
90
+ if pnpm_ws.is_file():
91
+ monorepo_type = "pnpm-workspace"
92
+
93
+ # 3. npm / yarn workspaces
94
+ root_pj = root / "package.json"
95
+ if root_pj.is_file():
96
+ try:
97
+ with open(root_pj, "r", encoding="utf-8") as f:
98
+ data = json.load(f)
99
+ if "workspaces" in data:
100
+ monorepo_type = "npm/yarn-workspaces"
101
+ except Exception:
102
+ pass
103
+
104
+ # Scan common monorepo container directories and direct project subfolders
105
+ candidate_folders = ["apps", "packages", "services", "libs", "modules"]
106
+ found_dirs = []
107
+
108
+ for cf in candidate_folders:
109
+ container = root / cf
110
+ if container.is_dir():
111
+ for child in container.iterdir():
112
+ if child.is_dir() and not child.name.startswith(('.', '_')):
113
+ if any((child / m).exists() for m in ["package.json", "pyproject.toml", "requirements.txt", "setup.py", "Cargo.toml", "main.py"]):
114
+ found_dirs.append(child)
115
+
116
+ # Also scan direct subdirectories if not already captured
117
+ for child in root.iterdir():
118
+ if child.is_dir() and not child.name.startswith(('.', '_')) and child.name not in candidate_folders:
119
+ if any((child / m).exists() for m in ["package.json", "pyproject.toml", "requirements.txt", "setup.py", "Cargo.toml", "main.py", "actions.ts"]):
120
+ if child not in found_dirs:
121
+ found_dirs.append(child)
122
+
123
+ if found_dirs:
124
+ if monorepo_type == "single-project":
125
+ monorepo_type = "multi-package-directory"
126
+ for d in found_dirs:
127
+ sub_packages.append(detect_package_info(d, root))
128
+
129
+ # If no monorepo sub-packages found, treat root as primary
130
+ if not sub_packages:
131
+ sub_packages.append(detect_package_info(root, root))
132
+
133
+ return {
134
+ "root": str(root).replace('\\', '/'),
135
+ "monorepo_type": monorepo_type,
136
+ "is_monorepo": monorepo_type != "single-project",
137
+ "package_count": len(sub_packages),
138
+ "packages": sub_packages
139
+ }
140
+
141
+
142
+ def main():
143
+ parser = argparse.ArgumentParser(description="TorusGuard Monorepo & Multi-Package Detector")
144
+ parser.add_argument("--scan", default=".", help="Root directory to scan (default: .)")
145
+ parser.add_argument("--write", action="store_true", help="Write to .torusguard/config/workspaces.json")
146
+ parser.add_argument("--json", action="store_true", help="Output JSON to stdout")
147
+ args = parser.parse_args()
148
+
149
+ res = scan_workspace(args.scan)
150
+
151
+ if args.write:
152
+ config_dir = Path(args.scan) / ".torusguard" / "config"
153
+ config_dir.mkdir(parents=True, exist_ok=True)
154
+ out_file = config_dir / "workspaces.json"
155
+ with open(out_file, "w", encoding="utf-8") as f:
156
+ json.dump(res, f, indent=2)
157
+ print(f"[SUCCESS] Wrote workspace registry to {out_file}")
158
+
159
+ if args.json or not args.write:
160
+ print(json.dumps(res, indent=2))
161
+
162
+
163
+ if __name__ == "__main__":
164
+ main()
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard Run Folder Lifecycle Manager
4
+ Creates isolated run folders, tracks manifest.json state, and enumerates execution history.
5
+ """
6
+
7
+ import sys
8
+ import json
9
+ import datetime
10
+ import argparse
11
+ from pathlib import Path
12
+ from typing import Dict, Any, List
13
+
14
+ def create_run(base_dir: Path, command: str, target_name: str = "project") -> Path:
15
+ timestamp = datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%S")
16
+ run_id = f"run-{timestamp}-{command}"
17
+ run_folder = base_dir / run_id
18
+ run_folder.mkdir(parents=True, exist_ok=True)
19
+
20
+ manifest = {
21
+ "run_id": run_id,
22
+ "command": command,
23
+ "target_name": target_name,
24
+ "created_at": datetime.datetime.utcnow().isoformat() + "Z",
25
+ "status": "in_progress",
26
+ "torusguard_version": "0.8.0",
27
+ "findings_count": 0,
28
+ "confirmed_fixed_count": 0,
29
+ "regressed_count": 0
30
+ }
31
+
32
+ manifest_path = run_folder / "manifest.json"
33
+ with open(manifest_path, "w", encoding="utf-8") as f:
34
+ json.dump(manifest, f, indent=2)
35
+
36
+ return run_folder
37
+
38
+
39
+ def list_runs(base_dir: Path) -> List[Dict[str, Any]]:
40
+ runs = []
41
+ if not base_dir.is_dir():
42
+ return runs
43
+
44
+ for d in sorted(base_dir.iterdir(), reverse=True):
45
+ if d.is_dir() and d.name.startswith("run-"):
46
+ manifest_file = d / "manifest.json"
47
+ if manifest_file.is_file():
48
+ try:
49
+ with open(manifest_file, "r", encoding="utf-8") as f:
50
+ data = json.load(f)
51
+ runs.append(data)
52
+ except Exception:
53
+ runs.append({"run_id": d.name, "status": "corrupted"})
54
+ else:
55
+ runs.append({"run_id": d.name, "status": "unmanifested"})
56
+ return runs
57
+
58
+
59
+ def main():
60
+ parser = argparse.ArgumentParser(description="TorusGuard Run Manager")
61
+ subparsers = parser.add_subparsers(dest="subcommand")
62
+
63
+ create_p = subparsers.add_parser("create")
64
+ create_p.add_argument("--command", "-c", default="audit", help="TorusGuard command (audit, web-validate, harden, etc.)")
65
+ create_p.add_argument("--target", "-t", default="project", help="Target project name")
66
+ create_p.add_argument("--dir", "-d", default=".torusguard/runs", help="Base runs directory")
67
+
68
+ list_p = subparsers.add_parser("list")
69
+ list_p.add_argument("--dir", "-d", default=".torusguard/runs", help="Base runs directory")
70
+ list_p.add_argument("--json", action="store_true", help="Output JSON")
71
+
72
+ args = parser.parse_args()
73
+
74
+ if args.subcommand == "create":
75
+ folder = create_run(Path(args.dir), args.command, args.target)
76
+ print(f"Created run folder: {folder}")
77
+ elif args.subcommand == "list":
78
+ runs = list_runs(Path(args.dir))
79
+ if args.json:
80
+ print(json.dumps(runs, indent=2))
81
+ else:
82
+ print(f"Total Runs Found: {len(runs)}")
83
+ for r in runs:
84
+ print(f" - {r.get('run_id')}: command={r.get('command')}, status={r.get('status')}")
85
+ else:
86
+ parser.print_help()
87
+
88
+ if __name__ == "__main__":
89
+ main()
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard Runtime Safety Gate Evaluator
4
+ Evaluates prospective HTTP/browser validation probes against non-destruction policies.
5
+ """
6
+
7
+ import sys
8
+ import json
9
+ import argparse
10
+ from typing import Dict, Any, Tuple
11
+
12
+ def evaluate_safety_gate(method: str, path: str, body: str = "") -> Tuple[str, str]:
13
+ """
14
+ Returns (decision, rationale)
15
+ Decisions:
16
+ - Auto-Allowed
17
+ - Approval Required
18
+ - Manual Only (Blocked)
19
+ """
20
+ method_upper = method.upper()
21
+
22
+ # Block destructive verbs
23
+ if method_upper in ("DELETE", "DROP"):
24
+ return "Manual Only", f"Method '{method_upper}' is destructive and strictly blocked from automated runtime validation."
25
+
26
+ # Block sensitive administrative paths
27
+ destructive_keywords = ["/admin/delete", "/shutdown", "/drop-database", "/purge", "/reset-system"]
28
+ for kw in destructive_keywords:
29
+ if kw in path.lower():
30
+ return "Manual Only", f"Path '{path}' targets destructive administrative endpoint '{kw}'."
31
+
32
+ # Safe read methods
33
+ if method_upper in ("GET", "HEAD", "OPTIONS"):
34
+ return "Auto-Allowed", f"Read-only method '{method_upper}' with non-destructive path."
35
+
36
+ # State-changing methods (POST, PUT, PATCH)
37
+ if method_upper in ("POST", "PUT", "PATCH"):
38
+ # Check if safe canary marker exists
39
+ if "tg-canary" in body.lower() or "torusguard" in body.lower():
40
+ return "Approval Required", f"State-changing method '{method_upper}' contains benign TorusGuard test marker; requires user approval."
41
+ else:
42
+ return "Approval Required", f"State-changing method '{method_upper}' requires operator approval before execution."
43
+
44
+ return "Approval Required", f"Unknown probe profile for {method_upper} {path}."
45
+
46
+
47
+ def main():
48
+ parser = argparse.ArgumentParser(description="TorusGuard Safety Gate Evaluator")
49
+ parser.add_argument("--method", "-m", default="GET", help="HTTP Method")
50
+ parser.add_argument("--path", "-p", default="/api/test", help="Endpoint path")
51
+ parser.add_argument("--body", "-b", default="", help="Request payload body")
52
+ parser.add_argument("--json", action="store_true", help="Output JSON")
53
+ args = parser.parse_args()
54
+
55
+ decision, rationale = evaluate_safety_gate(args.method, args.path, args.body)
56
+
57
+ if args.json:
58
+ print(json.dumps({"decision": decision, "rationale": rationale}, indent=2))
59
+ else:
60
+ print(f"Safety Decision: {decision}")
61
+ print(f"Rationale: {rationale}")
62
+
63
+ if __name__ == "__main__":
64
+ main()
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard OASIS SARIF v2.1.0 Exporter
4
+ Converts normalized TorusGuard findings into standard SARIF v2.1.0 format with
5
+ GitHub Code Scanning multi-analysis category separation and partialFingerprints deduplication.
6
+ """
7
+
8
+ import sys
9
+ import json
10
+ import hashlib
11
+ import argparse
12
+ from typing import List, Dict, Any
13
+
14
+ def generate_sarif(findings: List[Dict[str, Any]], run_id: str = "default", category: str = "torusguard/static") -> Dict[str, Any]:
15
+ rules_map: Dict[str, Dict[str, Any]] = {}
16
+ results: List[Dict[str, Any]] = []
17
+
18
+ for f in findings:
19
+ rule_id = f.get("rule_id", "TG-GEN-001")
20
+ if rule_id not in rules_map:
21
+ rules_map[rule_id] = {
22
+ "id": rule_id,
23
+ "name": f.get("title", rule_id),
24
+ "shortDescription": {"text": f.get("title", rule_id)},
25
+ "fullDescription": {"text": f.get("description", f.get("title", rule_id))},
26
+ "defaultConfiguration": {
27
+ "level": "error" if f.get("severity") in ("Critical", "High") else "warning"
28
+ },
29
+ "properties": {
30
+ "tags": ["security", "torusguard", f.get("category", "general")]
31
+ }
32
+ }
33
+
34
+ target = f.get("target", {})
35
+ file_path = target.get("file_path", "unknown")
36
+ line = target.get("start_line", 1)
37
+
38
+ # Generate deduplication fingerprint
39
+ seed = f"{rule_id}:{file_path}:{line}"
40
+ line_hash = hashlib.sha256(seed.encode("utf-8")).hexdigest()[:16]
41
+
42
+ result: Dict[str, Any] = {
43
+ "ruleId": rule_id,
44
+ "message": {"text": f.get("title", "TorusGuard Security Finding")},
45
+ "level": "error" if f.get("severity") in ("Critical", "High") else "warning",
46
+ "locations": [
47
+ {
48
+ "physicalLocation": {
49
+ "artifactLocation": {
50
+ "uri": file_path,
51
+ "uriBaseId": "%SRCROOT%"
52
+ },
53
+ "region": {
54
+ "startLine": line,
55
+ "startColumn": 1
56
+ }
57
+ }
58
+ }
59
+ ],
60
+ "partialFingerprints": {
61
+ "primaryLocationLineHash": line_hash
62
+ },
63
+ "properties": {
64
+ "confidence": f.get("confidence", 70),
65
+ "status": f.get("status", "Confirmed"),
66
+ "finding_id": f.get("finding_id", "TG-FIND-UNKNOWN")
67
+ }
68
+ }
69
+ results.append(result)
70
+
71
+ sarif = {
72
+ "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
73
+ "version": "2.1.0",
74
+ "runs": [
75
+ {
76
+ "tool": {
77
+ "driver": {
78
+ "name": "TorusGuard",
79
+ "semanticVersion": "0.8.0",
80
+ "informationUri": "https://github.com/githubmofo/TorusGuard",
81
+ "rules": list(rules_map.values())
82
+ }
83
+ },
84
+ "automationDetails": {
85
+ "id": f"{category}/{run_id}"
86
+ },
87
+ "results": results
88
+ }
89
+ ]
90
+ }
91
+ return sarif
92
+
93
+
94
+ def main():
95
+ parser = argparse.ArgumentParser(description="TorusGuard SARIF v2.1.0 Exporter")
96
+ parser.add_argument("--input", "-i", help="Path to findings JSON file")
97
+ parser.add_argument("--output", "-o", help="Output path for sarif.json")
98
+ parser.add_argument("--run-id", default="run-default", help="Unique execution Run ID")
99
+ args = parser.parse_args()
100
+
101
+ findings = []
102
+ if args.input:
103
+ with open(args.input, "r", encoding="utf-8") as f:
104
+ findings = json.load(f)
105
+
106
+ sarif = generate_sarif(findings, run_id=args.run_id)
107
+
108
+ if args.output:
109
+ with open(args.output, "w", encoding="utf-8") as f:
110
+ json.dump(sarif, f, indent=2)
111
+ print(f"SARIF log written to: {args.output}")
112
+ else:
113
+ print(json.dumps(sarif, indent=2))
114
+
115
+ if __name__ == "__main__":
116
+ main()
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard Stack Detector Utility
4
+ Inspects project directory to detect programming language, frameworks, ORM/data layer,
5
+ and dependency manifests. Outputs canonical stack block and structured JSON.
6
+ """
7
+
8
+ import sys
9
+ import json
10
+ import argparse
11
+ from pathlib import Path
12
+ from typing import Dict, Any, List
13
+
14
+ def detect_stack(project_root: Path) -> Dict[str, Any]:
15
+ profile = {
16
+ "language": "Unknown",
17
+ "framework": "None",
18
+ "data_layer": "None",
19
+ "dependency_files": [],
20
+ "detection_evidence": [],
21
+ "confidence": "Needs Review",
22
+ "recommended_rules": [
23
+ "TG-SEC-*",
24
+ "TG-INPUT-*",
25
+ "TG-AUTH-*"
26
+ ],
27
+ "recommended_references": []
28
+ }
29
+
30
+ # 1. Inspect dependency manifests
31
+ dep_candidates = ["pyproject.toml", "requirements.txt", "Pipfile", "package.json", "package-lock.json", "pnpm-lock.yaml"]
32
+ for dc in dep_candidates:
33
+ if (project_root / dc).is_file():
34
+ profile["dependency_files"].append(dc)
35
+
36
+ # 2. Check Python ecosystem
37
+ manage_py = project_root / "manage.py"
38
+ settings_py = list(project_root.glob("**/settings.py"))
39
+
40
+ if manage_py.is_file() or settings_py:
41
+ profile["language"] = "Python"
42
+ profile["framework"] = "Django"
43
+ profile["data_layer"] = "Django ORM"
44
+ profile["confidence"] = "Confirmed"
45
+ profile["detection_evidence"].append({
46
+ "file": "manage.py" if manage_py.is_file() else str(settings_py[0].relative_to(project_root)),
47
+ "indicator": "Django management or settings configuration"
48
+ })
49
+ profile["recommended_rules"].extend(["TG-DB-004", "TG-RATE-001", "TG-PLATFORM-*"])
50
+ profile["recommended_references"].extend(["django-security.md", "python-security-overview.md"])
51
+
52
+ # Check for DRF
53
+ for py_file in project_root.glob("**/*.py"):
54
+ try:
55
+ content = py_file.read_text(encoding="utf-8", errors="ignore")
56
+ if "rest_framework" in content:
57
+ profile["framework"] = "Django / DRF"
58
+ profile["recommended_references"].append("drf-security.md")
59
+ break
60
+ except Exception:
61
+ continue
62
+
63
+ # Check for FastAPI / Flask if not Django
64
+ if profile["framework"] == "None":
65
+ for py_file in list(project_root.glob("*.py")) + list(project_root.glob("app/**/*.py")) + list(project_root.glob("src/**/*.py")):
66
+ try:
67
+ content = py_file.read_text(encoding="utf-8", errors="ignore")
68
+ if "FastAPI(" in content or "from fastapi" in content:
69
+ profile["language"] = "Python"
70
+ profile["framework"] = "FastAPI"
71
+ profile["confidence"] = "Confirmed"
72
+ profile["detection_evidence"].append({
73
+ "file": str(py_file.relative_to(project_root)),
74
+ "indicator": "FastAPI application instantiation"
75
+ })
76
+ profile["recommended_references"].append("fastapi-security.md")
77
+ elif "Flask(__name__)" in content or "from flask" in content:
78
+ profile["language"] = "Python"
79
+ profile["framework"] = "Flask"
80
+ profile["confidence"] = "Confirmed"
81
+ profile["detection_evidence"].append({
82
+ "file": str(py_file.relative_to(project_root)),
83
+ "indicator": "Flask application instantiation"
84
+ })
85
+ profile["recommended_references"].append("flask-security.md")
86
+
87
+ if "sqlalchemy" in content:
88
+ profile["data_layer"] = "SQLAlchemy"
89
+ profile["recommended_references"].append("sqlalchemy-security.md")
90
+ except Exception:
91
+ continue
92
+
93
+ # 3. Check JavaScript / TypeScript ecosystem
94
+ pkg_json_path = project_root / "package.json"
95
+ if pkg_json_path.is_file():
96
+ profile["language"] = "TypeScript" if list(project_root.glob("**/*.ts*")) else "JavaScript"
97
+ try:
98
+ with open(pkg_json_path, "r", encoding="utf-8") as f:
99
+ pkg = json.load(f)
100
+ deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
101
+
102
+ if "next" in deps:
103
+ profile["framework"] = "Next.js"
104
+ profile["confidence"] = "Confirmed"
105
+ profile["detection_evidence"].append({"file": "package.json", "indicator": "next dependency"})
106
+ profile["recommended_references"].append("nextjs-security.md")
107
+ profile["recommended_rules"].extend(["TG-CLIENT-*", "TG-PLATFORM-001"])
108
+ elif "express" in deps:
109
+ profile["framework"] = "Express"
110
+ profile["confidence"] = "Confirmed"
111
+ profile["detection_evidence"].append({"file": "package.json", "indicator": "express dependency"})
112
+ profile["recommended_references"].append("express-security.md")
113
+ elif "react" in deps:
114
+ profile["framework"] = "React / Vite"
115
+ profile["confidence"] = "Confirmed"
116
+ profile["detection_evidence"].append({"file": "package.json", "indicator": "react dependency"})
117
+ profile["recommended_references"].append("react-vite-security.md")
118
+
119
+ if "@supabase/supabase-js" in deps:
120
+ profile["data_layer"] = "Supabase"
121
+ profile["recommended_references"].append("supabase-security.md")
122
+ elif "firebase" in deps or "firebase-admin" in deps:
123
+ profile["data_layer"] = "Firebase"
124
+ profile["recommended_references"].append("firebase-security.md")
125
+ except Exception:
126
+ pass
127
+
128
+ return profile
129
+
130
+
131
+ def main():
132
+ parser = argparse.ArgumentParser(description="TorusGuard Stack Detector")
133
+ parser.add_argument("path", nargs="?", default=".", help="Target project root directory")
134
+ parser.add_argument("--json", action="store_true", help="Output raw JSON")
135
+ args = parser.parse_args()
136
+
137
+ project_root = Path(args.path).resolve()
138
+ profile = detect_stack(project_root)
139
+
140
+ if args.json:
141
+ print(json.dumps(profile, indent=2))
142
+ else:
143
+ evidence = profile["detection_evidence"][0]["file"] if profile["detection_evidence"] else "heuristic"
144
+ print(f"## Detected Stack")
145
+ print(f"- Language: {profile['language']}")
146
+ print(f"- Framework: {profile['framework']}")
147
+ print(f"- Data layer: {profile['data_layer']}")
148
+ print(f"- Dependency files: {', '.join(profile['dependency_files']) if profile['dependency_files'] else 'None'}")
149
+ print(f"- Detection confidence: {profile['confidence']} ({evidence})")
150
+
151
+ if __name__ == "__main__":
152
+ main()
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: torusguard
3
+ description: Security guardrails, governed remediation, and authorized runtime validation for AI-built web applications across Python and TypeScript.
4
+ version: 0.9.2
5
+ ---
6
+
7
+ # TorusGuard Master Router
8
+
9
+ **Principle:** If the browser receives it, users can inspect it. Keep secrets, direct database access, and authorization on trusted server-side code.
10
+
11
+ ---
12
+
13
+ ## ⚡ Workspace Bootstrap Check
14
+ 1. **If `.torusguard/` exists:** Load matching specialist skill on demand per command.
15
+ 2. **If `.torusguard/` is missing:** Run `python skills/torusguard/bootstrap.py --target .` or `/torusguard init`.
16
+
17
+ ---
18
+
19
+ ## Specialist Skill Routing (Lazy Loading)
20
+ Load **only** the designated sub-skill when a slash command is executed to maintain strict 1,000–1,500 token budget:
21
+
22
+ | Command | Specialist Skill | Agent |
23
+ | :--- | :--- | :--- |
24
+ | `/torusguard init` | `skills/torusguard-init/SKILL.md` | `profiler` |
25
+ | `/torusguard authorize` | `skills/torusguard-authorize/SKILL.md` | `reviewer` |
26
+ | `/torusguard audit` | `skills/torusguard-audit/SKILL.md` | `auditor` |
27
+ | `/torusguard verify` | `skills/torusguard-verify/SKILL.md` | `validator` |
28
+ | `/torusguard web-validate` | `skills/torusguard-web-validate/SKILL.md` | `validator` |
29
+ | `/torusguard exploit-check` | `skills/torusguard-exploit-check/SKILL.md` | `validator` |
30
+ | `/torusguard harden` | `skills/torusguard-harden/SKILL.md` | `remediator` |
31
+ | `/torusguard apply` | `skills/torusguard-apply/SKILL.md` | `remediator` |
32
+ | `/torusguard recheck` | `skills/torusguard-recheck/SKILL.md` | `reviewer` |
33
+ | `/torusguard report` | `skills/torusguard-report/SKILL.md` | `reviewer` |
34
+ | `/torusguard status` | `skills/torusguard-status/SKILL.md` | `reviewer` |
35
+ | `/torusguard full` | `skills/torusguard-full/SKILL.md` | *All* |
36
+
37
+ *Note: Never load all skills simultaneously. Lazy-load strictly on demand.*