torusguard 0.9.5 → 1.0.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 (46) hide show
  1. package/.torusguard/.manifest.json +15 -10
  2. package/.torusguard/config/torusguard.json +1 -1
  3. package/.torusguard/schemas/memory-context.schema.json +95 -0
  4. package/.torusguard/schemas/memory-event.schema.json +70 -0
  5. package/.torusguard/schemas/memory-pattern.schema.json +65 -0
  6. package/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
  7. package/.torusguard/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
  8. package/.torusguard/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
  9. package/.torusguard/scripts/diff_guard.py +71 -11
  10. package/.torusguard/scripts/finding_scorer.py +171 -86
  11. package/.torusguard/scripts/manifest_builder.py +2 -0
  12. package/.torusguard/scripts/memory_engine.py +912 -0
  13. package/.torusguard/scripts/run_manager.py +171 -89
  14. package/.torusguard/skills/torusguard/SKILL.md +4 -3
  15. package/.torusguard/skills/torusguard/bootstrap.py +344 -56
  16. package/.torusguard/skills/torusguard-audit/SKILL.md +25 -25
  17. package/.torusguard/skills/torusguard-harden/SKILL.md +3 -3
  18. package/.torusguard/skills/torusguard-recheck/SKILL.md +3 -3
  19. package/.torusguard/workflows/memory.md +53 -0
  20. package/README.md +11 -2
  21. package/bin/torusguard.js +99 -5
  22. package/package.json +1 -1
  23. package/skills/torusguard/SKILL.md +4 -3
  24. package/skills/torusguard/__pycache__/bootstrap.cpython-311.pyc +0 -0
  25. package/skills/torusguard/bootstrap.py +66 -2
  26. package/skills/torusguard/payload/.manifest.json +15 -10
  27. package/skills/torusguard/payload/config/torusguard.json +1 -1
  28. package/skills/torusguard/payload/schemas/memory-context.schema.json +95 -0
  29. package/skills/torusguard/payload/schemas/memory-event.schema.json +70 -0
  30. package/skills/torusguard/payload/schemas/memory-pattern.schema.json +65 -0
  31. package/skills/torusguard/payload/scripts/diff_guard.py +71 -11
  32. package/skills/torusguard/payload/scripts/finding_scorer.py +171 -86
  33. package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
  34. package/skills/torusguard/payload/scripts/memory_engine.py +912 -0
  35. package/skills/torusguard/payload/scripts/run_manager.py +171 -89
  36. package/skills/torusguard/payload/skills/torusguard/SKILL.md +4 -3
  37. package/skills/torusguard/payload/skills/torusguard/bootstrap.py +344 -56
  38. package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +25 -25
  39. package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +3 -3
  40. package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +3 -3
  41. package/skills/torusguard/payload/workflows/memory.md +53 -0
  42. package/skills/torusguard-audit/SKILL.md +25 -25
  43. package/skills/torusguard-harden/SKILL.md +3 -3
  44. package/skills/torusguard-recheck/SKILL.md +3 -3
  45. package/skills/torusguard/payload/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
  46. 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()
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: torusguard
3
- description: "Autonomous security engine: 71 rules across 11 families, governed remediation (Ponytail Protocol), SARIF v2.1.0 exports, and 5-agent authority separation for Python & TypeScript web applications."
4
- version: 0.9.5
3
+ description: "Autonomous security engine: 71 rules across 11 families, governed remediation (Ponytail Protocol), SARIF v2.1.0 exports, and persistent security memory context for Python & TypeScript web applications."
4
+ version: 1.0.0
5
5
  ---
6
6
 
7
7
  # TorusGuard Master Security Router
@@ -11,7 +11,7 @@ version: 0.9.5
11
11
  ---
12
12
 
13
13
  ## ⚡ Workspace Bootstrap Check
14
- 1. **If `.torusguard/` exists on disk:** Full governance active. Route slash commands to local specialist workflows below.
14
+ 1. **If `.torusguard/` exists on disk:** Full governance active. Load `.torusguard/memory/context.json` into prompt context for local-first intelligence. Route commands to specialist workflows below.
15
15
  2. **If `.torusguard/` is absent (Autonomous AI Mode):** Operates standalone in any AI agent (Kimi, Antigravity, VS Code, Cursor). Apply in-memory security invariants:
16
16
  - Server-side auth & tenant scoping (`.filter(tenant=...)`).
17
17
  - Zero client-side secrets (`SUPABASE_SERVICE_ROLE_KEY`, live API keys).
@@ -36,6 +36,7 @@ Load **only** the designated sub-skill on demand to preserve the 1,000–1,500 t
36
36
  | `/torusguard recheck` | `skills/torusguard-recheck/SKILL.md` | `reviewer` |
37
37
  | `/torusguard report` | `skills/torusguard-report/SKILL.md` | `reviewer` |
38
38
  | `/torusguard status` | `skills/torusguard-status/SKILL.md` | `reviewer` |
39
+ | `/torusguard memory` | `skills/torusguard/SKILL.md` | `reviewer` |
39
40
  | `/torusguard full` | `skills/torusguard-full/SKILL.md` | *All* |
40
41
 
41
42
  *Note: Never load all skills simultaneously. Lazy-load strictly on demand.*