torusguard 0.9.5 → 1.3.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.
Files changed (80) hide show
  1. package/.torusguard/.manifest.json +98 -79
  2. package/.torusguard/config/torusguard.json +1 -1
  3. package/.torusguard/references/csharp-security.md +41 -0
  4. package/.torusguard/references/go-security.md +41 -0
  5. package/.torusguard/references/java-security.md +40 -0
  6. package/.torusguard/references/polyglot-security-matrix.md +25 -0
  7. package/.torusguard/references/rust-security.md +40 -0
  8. package/.torusguard/rules/custom/.gitkeep +1 -0
  9. package/.torusguard/rules/custom/README.md +30 -0
  10. package/.torusguard/runs/report-latest.html +328 -0
  11. package/.torusguard/schemas/golden-recipe.schema.json +75 -0
  12. package/.torusguard/schemas/memory-context.schema.json +95 -0
  13. package/.torusguard/schemas/memory-event.schema.json +70 -0
  14. package/.torusguard/schemas/memory-pattern.schema.json +65 -0
  15. package/.torusguard/scripts/diff_guard.py +202 -15
  16. package/.torusguard/scripts/finding_scorer.py +199 -86
  17. package/.torusguard/scripts/html_reporter.py +628 -0
  18. package/.torusguard/scripts/manifest_builder.py +7 -5
  19. package/.torusguard/scripts/memory_engine.py +1334 -0
  20. package/.torusguard/scripts/monorepo_detector.py +123 -10
  21. package/.torusguard/scripts/rules_sync.py +321 -0
  22. package/.torusguard/scripts/run_manager.py +171 -89
  23. package/.torusguard/scripts/stack_detect.py +458 -26
  24. package/.torusguard/skills/torusguard/SKILL.md +4 -3
  25. package/.torusguard/skills/torusguard/bootstrap.py +344 -56
  26. package/.torusguard/skills/torusguard/references/csharp-security.md +41 -0
  27. package/.torusguard/skills/torusguard/references/go-security.md +41 -0
  28. package/.torusguard/skills/torusguard/references/java-security.md +40 -0
  29. package/.torusguard/skills/torusguard/references/polyglot-security-matrix.md +25 -0
  30. package/.torusguard/skills/torusguard/references/rust-security.md +40 -0
  31. package/.torusguard/skills/torusguard-audit/SKILL.md +25 -25
  32. package/.torusguard/skills/torusguard-harden/SKILL.md +3 -3
  33. package/.torusguard/skills/torusguard-recheck/SKILL.md +3 -3
  34. package/.torusguard/workflows/memory.md +53 -0
  35. package/README.md +307 -401
  36. package/bin/torusguard.js +204 -6
  37. package/package.json +1 -1
  38. package/skills/torusguard/SKILL.md +4 -3
  39. package/skills/torusguard/bootstrap.py +68 -4
  40. package/skills/torusguard/payload/.manifest.json +98 -79
  41. package/skills/torusguard/payload/config/torusguard.json +1 -1
  42. package/skills/torusguard/payload/references/csharp-security.md +41 -0
  43. package/skills/torusguard/payload/references/go-security.md +41 -0
  44. package/skills/torusguard/payload/references/java-security.md +40 -0
  45. package/skills/torusguard/payload/references/polyglot-security-matrix.md +25 -0
  46. package/skills/torusguard/payload/references/rust-security.md +40 -0
  47. package/skills/torusguard/payload/rules/custom/.gitkeep +1 -0
  48. package/skills/torusguard/payload/rules/custom/README.md +30 -0
  49. package/skills/torusguard/payload/schemas/golden-recipe.schema.json +75 -0
  50. package/skills/torusguard/payload/schemas/memory-context.schema.json +95 -0
  51. package/skills/torusguard/payload/schemas/memory-event.schema.json +70 -0
  52. package/skills/torusguard/payload/schemas/memory-pattern.schema.json +65 -0
  53. package/skills/torusguard/payload/scripts/diff_guard.py +202 -15
  54. package/skills/torusguard/payload/scripts/finding_scorer.py +199 -86
  55. package/skills/torusguard/payload/scripts/html_reporter.py +628 -0
  56. package/skills/torusguard/payload/scripts/manifest_builder.py +7 -5
  57. package/skills/torusguard/payload/scripts/memory_engine.py +1334 -0
  58. package/skills/torusguard/payload/scripts/monorepo_detector.py +123 -10
  59. package/skills/torusguard/payload/scripts/rules_sync.py +321 -0
  60. package/skills/torusguard/payload/scripts/run_manager.py +171 -89
  61. package/skills/torusguard/payload/scripts/stack_detect.py +458 -26
  62. package/skills/torusguard/payload/skills/torusguard/SKILL.md +4 -3
  63. package/skills/torusguard/payload/skills/torusguard/bootstrap.py +344 -56
  64. package/skills/torusguard/payload/skills/torusguard/references/csharp-security.md +41 -0
  65. package/skills/torusguard/payload/skills/torusguard/references/go-security.md +41 -0
  66. package/skills/torusguard/payload/skills/torusguard/references/java-security.md +40 -0
  67. package/skills/torusguard/payload/skills/torusguard/references/polyglot-security-matrix.md +25 -0
  68. package/skills/torusguard/payload/skills/torusguard/references/rust-security.md +40 -0
  69. package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +25 -25
  70. package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +3 -3
  71. package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +3 -3
  72. package/skills/torusguard/payload/workflows/memory.md +53 -0
  73. package/skills/torusguard-audit/SKILL.md +25 -25
  74. package/skills/torusguard-harden/SKILL.md +3 -3
  75. package/skills/torusguard-recheck/SKILL.md +3 -3
  76. package/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
  77. package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
  78. package/skills/torusguard/__pycache__/bootstrap.cpython-311.pyc +0 -0
  79. package/skills/torusguard/payload/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
  80. package/skills/torusguard/payload/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
@@ -1,89 +1,171 @@
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()
1
+ #!/usr/bin/env python3
2
+ """
3
+ TorusGuard Run Folder Lifecycle Manager (v1.0.0)
4
+ Creates isolated run folders, tracks manifest.json state, enumerates execution history,
5
+ and bridges completed run findings to the persistent security memory engine.
6
+ """
7
+
8
+ import sys
9
+ import json
10
+ import datetime
11
+ import argparse
12
+ from pathlib import Path
13
+ from typing import Dict, Any, List, Optional
14
+
15
+
16
+ def create_run(base_dir: Path, command: str, target_name: str = "project") -> Path:
17
+ timestamp = datetime.datetime.utcnow().strftime("%Y%m%d-%H%M%S")
18
+ run_id = f"run-{timestamp}-{command}"
19
+ run_folder = base_dir / run_id
20
+ run_folder.mkdir(parents=True, exist_ok=True)
21
+
22
+ manifest = {
23
+ "run_id": run_id,
24
+ "command": command,
25
+ "target_name": target_name,
26
+ "created_at": datetime.datetime.utcnow().isoformat() + "Z",
27
+ "status": "in_progress",
28
+ "torusguard_version": "1.0.0",
29
+ "findings_count": 0,
30
+ "confirmed_fixed_count": 0,
31
+ "regressed_count": 0
32
+ }
33
+
34
+ manifest_path = run_folder / "manifest.json"
35
+ with open(manifest_path, "w", encoding="utf-8") as f:
36
+ json.dump(manifest, f, indent=2)
37
+
38
+ return run_folder
39
+
40
+
41
+ def list_runs(base_dir: Path) -> List[Dict[str, Any]]:
42
+ runs = []
43
+ if not base_dir.is_dir():
44
+ return runs
45
+
46
+ for d in sorted(base_dir.iterdir(), reverse=True):
47
+ if d.is_dir() and d.name.startswith("run-"):
48
+ manifest_file = d / "manifest.json"
49
+ if manifest_file.is_file():
50
+ try:
51
+ with open(manifest_file, "r", encoding="utf-8") as f:
52
+ data = json.load(f)
53
+ runs.append(data)
54
+ except Exception:
55
+ runs.append({"run_id": d.name, "status": "corrupted"})
56
+ else:
57
+ runs.append({"run_id": d.name, "status": "unmanifested"})
58
+ return runs
59
+
60
+
61
+ def sync_run_to_memory(run_folder: Path, findings: Optional[List[Dict[str, Any]]] = None) -> int:
62
+ """
63
+ Sync findings from a completed run into the .torusguard/memory/ engine.
64
+ Records events based on command type (audit -> audit_finding, apply -> fix_applied, recheck -> fix_verified).
65
+ """
66
+ manifest_file = run_folder / "manifest.json"
67
+ if not manifest_file.is_file():
68
+ return 0
69
+
70
+ try:
71
+ with open(manifest_file, "r", encoding="utf-8") as f:
72
+ manifest = json.load(f)
73
+ except Exception:
74
+ return 0
75
+
76
+ command = manifest.get("command", "audit")
77
+
78
+ # If findings not explicitly provided, try reading findings.json in run_folder
79
+ actual_findings = findings
80
+ if actual_findings is None:
81
+ findings_file = run_folder / "findings.json"
82
+ if findings_file.is_file():
83
+ try:
84
+ with open(findings_file, "r", encoding="utf-8") as f:
85
+ actual_findings = json.load(f)
86
+ except Exception:
87
+ actual_findings = []
88
+
89
+ if not actual_findings or not isinstance(actual_findings, list):
90
+ return 0
91
+
92
+ # Import memory_engine in-process
93
+ try:
94
+ scripts_dir = Path(__file__).resolve().parent
95
+ if str(scripts_dir) not in sys.path:
96
+ sys.path.insert(0, str(scripts_dir))
97
+ import memory_engine
98
+
99
+ recorded_count = 0
100
+ for f in actual_findings:
101
+ rule_id = f.get("rule_id") or f.get("id")
102
+ if not rule_id:
103
+ continue
104
+
105
+ event_type = "audit_finding"
106
+ if command in ("harden", "apply"):
107
+ event_type = "fix_applied"
108
+ elif command in ("recheck", "verify"):
109
+ event_type = "fix_verified"
110
+
111
+ data = {
112
+ "rule_id": rule_id,
113
+ "file_path": f.get("file_path") or f.get("file"),
114
+ "line_number": f.get("line_number") or f.get("line"),
115
+ "severity": (f.get("severity") or "medium").lower(),
116
+ "confidence_score": f.get("confidence_score") or f.get("confidence", 70),
117
+ "code_hash": f.get("code_hash"),
118
+ "fix_strategy": f.get("fix_strategy") or f.get("strategy"),
119
+ "verification_result": f.get("verification_result") or f.get("result", "fixed"),
120
+ "suppression_reason": f.get("suppression_reason")
121
+ }
122
+ memory_engine.record_event(event_type, data)
123
+ recorded_count += 1
124
+
125
+ if recorded_count > 0:
126
+ memory_engine.distill_patterns()
127
+
128
+ return recorded_count
129
+ except Exception as e:
130
+ # Non-blocking: memory failure should never crash a run
131
+ return 0
132
+
133
+
134
+ def main():
135
+ parser = argparse.ArgumentParser(description="TorusGuard Run Manager")
136
+ subparsers = parser.add_subparsers(dest="subcommand")
137
+
138
+ create_p = subparsers.add_parser("create")
139
+ create_p.add_argument("--command", "-c", default="audit", help="TorusGuard command (audit, web-validate, harden, etc.)")
140
+ create_p.add_argument("--target", "-t", default="project", help="Target project name")
141
+ create_p.add_argument("--dir", "-d", default=".torusguard/runs", help="Base runs directory")
142
+
143
+ list_p = subparsers.add_parser("list")
144
+ list_p.add_argument("--dir", "-d", default=".torusguard/runs", help="Base runs directory")
145
+ list_p.add_argument("--json", action="store_true", help="Output JSON")
146
+
147
+ sync_p = subparsers.add_parser("sync-memory")
148
+ sync_p.add_argument("--run-folder", "-r", required=True, help="Path to run folder")
149
+
150
+ args = parser.parse_args()
151
+
152
+ if args.subcommand == "create":
153
+ folder = create_run(Path(args.dir), args.command, args.target)
154
+ print(f"Created run folder: {folder}")
155
+ elif args.subcommand == "list":
156
+ runs = list_runs(Path(args.dir))
157
+ if args.json:
158
+ print(json.dumps(runs, indent=2))
159
+ else:
160
+ print(f"Total Runs Found: {len(runs)}")
161
+ for r in runs:
162
+ print(f" - {r.get('run_id')}: command={r.get('command')}, status={r.get('status')}")
163
+ elif args.subcommand == "sync-memory":
164
+ count = sync_run_to_memory(Path(args.run_folder))
165
+ print(f"Synced {count} findings from run to memory.")
166
+ else:
167
+ parser.print_help()
168
+
169
+
170
+ if __name__ == "__main__":
171
+ main()