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.
- package/.torusguard/.manifest.json +15 -10
- package/.torusguard/config/torusguard.json +1 -1
- package/.torusguard/schemas/memory-context.schema.json +95 -0
- package/.torusguard/schemas/memory-event.schema.json +70 -0
- package/.torusguard/schemas/memory-pattern.schema.json +65 -0
- package/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
- package/.torusguard/scripts/diff_guard.py +71 -11
- package/.torusguard/scripts/finding_scorer.py +171 -86
- package/.torusguard/scripts/manifest_builder.py +2 -0
- package/.torusguard/scripts/memory_engine.py +912 -0
- package/.torusguard/scripts/run_manager.py +171 -89
- package/.torusguard/skills/torusguard/SKILL.md +4 -3
- package/.torusguard/skills/torusguard/bootstrap.py +344 -56
- package/.torusguard/skills/torusguard-audit/SKILL.md +25 -25
- package/.torusguard/skills/torusguard-harden/SKILL.md +3 -3
- package/.torusguard/skills/torusguard-recheck/SKILL.md +3 -3
- package/.torusguard/workflows/memory.md +53 -0
- package/README.md +11 -2
- package/bin/torusguard.js +99 -5
- package/package.json +1 -1
- package/skills/torusguard/SKILL.md +4 -3
- package/skills/torusguard/__pycache__/bootstrap.cpython-311.pyc +0 -0
- package/skills/torusguard/bootstrap.py +66 -2
- package/skills/torusguard/payload/.manifest.json +15 -10
- package/skills/torusguard/payload/config/torusguard.json +1 -1
- package/skills/torusguard/payload/schemas/memory-context.schema.json +95 -0
- package/skills/torusguard/payload/schemas/memory-event.schema.json +70 -0
- package/skills/torusguard/payload/schemas/memory-pattern.schema.json +65 -0
- package/skills/torusguard/payload/scripts/diff_guard.py +71 -11
- package/skills/torusguard/payload/scripts/finding_scorer.py +171 -86
- package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
- package/skills/torusguard/payload/scripts/memory_engine.py +912 -0
- package/skills/torusguard/payload/scripts/run_manager.py +171 -89
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +4 -3
- package/skills/torusguard/payload/skills/torusguard/bootstrap.py +344 -56
- package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +25 -25
- package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +3 -3
- package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +3 -3
- package/skills/torusguard/payload/workflows/memory.md +53 -0
- package/skills/torusguard-audit/SKILL.md +25 -25
- package/skills/torusguard-harden/SKILL.md +3 -3
- package/skills/torusguard-recheck/SKILL.md +3 -3
- package/skills/torusguard/payload/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "torusguard-memory-pattern.schema.json",
|
|
4
|
+
"title": "TorusGuard Memory Pattern",
|
|
5
|
+
"description": "Schema for distilled security patterns extracted from raw events. Patterns represent recurring fix strategies, vulnerability classes, and project-specific security idioms.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["pattern_id", "rule_id", "pattern_type", "confidence", "occurrences", "first_seen", "last_seen"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"pattern_id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Unique pattern identifier (PAT-NNN)."
|
|
12
|
+
},
|
|
13
|
+
"rule_id": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "TorusGuard rule ID this pattern relates to."
|
|
16
|
+
},
|
|
17
|
+
"pattern_type": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["recurring_fix", "common_vulnerability", "false_positive_class", "regression_watch", "security_idiom"],
|
|
20
|
+
"description": "Category of the distilled pattern."
|
|
21
|
+
},
|
|
22
|
+
"description": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Human-readable summary of the pattern."
|
|
25
|
+
},
|
|
26
|
+
"fix_strategy": {
|
|
27
|
+
"type": ["string", "null"],
|
|
28
|
+
"description": "The preferred fix approach observed across multiple occurrences."
|
|
29
|
+
},
|
|
30
|
+
"confidence": {
|
|
31
|
+
"type": "integer",
|
|
32
|
+
"minimum": 0,
|
|
33
|
+
"maximum": 100,
|
|
34
|
+
"description": "Pattern confidence (amplified by repeated confirmations, decayed by TTL)."
|
|
35
|
+
},
|
|
36
|
+
"occurrences": {
|
|
37
|
+
"type": "integer",
|
|
38
|
+
"minimum": 1,
|
|
39
|
+
"description": "Number of times this pattern has been observed."
|
|
40
|
+
},
|
|
41
|
+
"affected_files": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": { "type": "string" },
|
|
44
|
+
"description": "List of relative file paths where this pattern has been observed."
|
|
45
|
+
},
|
|
46
|
+
"first_seen": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"format": "date-time"
|
|
49
|
+
},
|
|
50
|
+
"last_seen": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"format": "date-time"
|
|
53
|
+
},
|
|
54
|
+
"decay_checkpoint": {
|
|
55
|
+
"type": ["string", "null"],
|
|
56
|
+
"format": "date-time",
|
|
57
|
+
"description": "Last timestamp when this pattern's confidence was reconfirmed or decayed."
|
|
58
|
+
},
|
|
59
|
+
"source_events": {
|
|
60
|
+
"type": "array",
|
|
61
|
+
"items": { "type": "string" },
|
|
62
|
+
"description": "List of event_ids that contributed to this pattern."
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
TorusGuard Content-Aware Diff Line Scanner (
|
|
4
|
-
Evaluates unified diff patches against security invariants before harden or apply
|
|
3
|
+
TorusGuard Content-Aware Diff Line Scanner (v1.0.0)
|
|
4
|
+
Evaluates unified diff patches against security invariants before harden or apply,
|
|
5
|
+
including regression watch checks against persistent memory patterns.
|
|
5
6
|
Pure Python 3.10+ standard library (zero external dependencies).
|
|
6
7
|
"""
|
|
7
8
|
|
|
@@ -38,16 +39,69 @@ TENANT_FILTER_PATTERNS = [
|
|
|
38
39
|
]
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
def
|
|
42
|
+
def check_memory_regressions(
|
|
43
|
+
current_file: str,
|
|
44
|
+
current_line: int,
|
|
45
|
+
added_content: str,
|
|
46
|
+
root_dir: Optional[Path] = None
|
|
47
|
+
) -> List[Dict[str, Any]]:
|
|
48
|
+
"""
|
|
49
|
+
Check if the added line re-introduces a vulnerability in a file
|
|
50
|
+
that is tracked under active Regression Watch in .torusguard/memory/patterns.json.
|
|
51
|
+
"""
|
|
52
|
+
violations = []
|
|
53
|
+
base = Path(root_dir or Path.cwd()).resolve()
|
|
54
|
+
torusguard_dir = base / ".torusguard"
|
|
55
|
+
if not torusguard_dir.exists():
|
|
56
|
+
for parent in base.parents:
|
|
57
|
+
if (parent / ".torusguard").exists():
|
|
58
|
+
torusguard_dir = parent / ".torusguard"
|
|
59
|
+
break
|
|
60
|
+
|
|
61
|
+
patterns_file = torusguard_dir / "memory" / "patterns.json"
|
|
62
|
+
if not patterns_file.exists():
|
|
63
|
+
return violations
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
with open(patterns_file, "r", encoding="utf-8") as f:
|
|
67
|
+
patterns = json.load(f)
|
|
68
|
+
except Exception:
|
|
69
|
+
return violations
|
|
70
|
+
|
|
71
|
+
clean_file = current_file.replace("\\", "/")
|
|
72
|
+
for pat in patterns:
|
|
73
|
+
if pat.get("pattern_type") == "regression_watch":
|
|
74
|
+
affected = [f.replace("\\", "/") for f in pat.get("affected_files", [])]
|
|
75
|
+
if clean_file in affected or any(clean_file.endswith(a) for a in affected):
|
|
76
|
+
rule_id = pat.get("rule_id", "TG-REG")
|
|
77
|
+
desc = pat.get("description", "Regression watch violation")
|
|
78
|
+
violations.append({
|
|
79
|
+
"rule_id": "TG-DIFF-004",
|
|
80
|
+
"category": "Regression Watch",
|
|
81
|
+
"severity": "HIGH",
|
|
82
|
+
"file": current_file,
|
|
83
|
+
"line": current_line,
|
|
84
|
+
"content": added_content.strip(),
|
|
85
|
+
"description": f"File {current_file} matches active Regression Watch for {rule_id}: {desc}"
|
|
86
|
+
})
|
|
87
|
+
return violations
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def audit_diff(
|
|
91
|
+
diff_content: str,
|
|
92
|
+
check_memory: bool = False,
|
|
93
|
+
root_dir: Optional[Path] = None
|
|
94
|
+
) -> Dict[str, Any]:
|
|
42
95
|
"""
|
|
43
96
|
Parses a unified diff and returns detected violations.
|
|
97
|
+
Optionally checks against active regression watch patterns in memory.
|
|
44
98
|
"""
|
|
45
99
|
lines = diff_content.splitlines()
|
|
46
100
|
violations: List[Dict[str, Any]] = []
|
|
47
|
-
|
|
101
|
+
|
|
48
102
|
current_file = "unknown"
|
|
49
103
|
current_line = 0
|
|
50
|
-
|
|
104
|
+
|
|
51
105
|
additions: List[tuple[int, str]] = []
|
|
52
106
|
deletions: List[tuple[int, str]] = []
|
|
53
107
|
|
|
@@ -68,7 +122,7 @@ def audit_diff(diff_content: str) -> Dict[str, Any]:
|
|
|
68
122
|
current_line += 1
|
|
69
123
|
added_content = line[1:]
|
|
70
124
|
additions.append((current_line, added_content))
|
|
71
|
-
|
|
125
|
+
|
|
72
126
|
# Check bypass patterns
|
|
73
127
|
for pat, desc in BYPASS_PATTERNS:
|
|
74
128
|
if pat.search(added_content):
|
|
@@ -81,7 +135,7 @@ def audit_diff(diff_content: str) -> Dict[str, Any]:
|
|
|
81
135
|
"content": added_content.strip(),
|
|
82
136
|
"description": desc
|
|
83
137
|
})
|
|
84
|
-
|
|
138
|
+
|
|
85
139
|
# Check secret ingestion
|
|
86
140
|
for pat, desc in SECRET_PATTERNS:
|
|
87
141
|
if pat.search(added_content):
|
|
@@ -95,6 +149,11 @@ def audit_diff(diff_content: str) -> Dict[str, Any]:
|
|
|
95
149
|
"description": desc
|
|
96
150
|
})
|
|
97
151
|
|
|
152
|
+
# Check memory regression watch if requested
|
|
153
|
+
if check_memory:
|
|
154
|
+
reg_violations = check_memory_regressions(current_file, current_line, added_content, root_dir=root_dir)
|
|
155
|
+
violations.extend(reg_violations)
|
|
156
|
+
|
|
98
157
|
elif line.startswith('-') and not line.startswith('---'):
|
|
99
158
|
deleted_content = line[1:]
|
|
100
159
|
deletions.append((line_idx, deleted_content))
|
|
@@ -127,7 +186,7 @@ def audit_diff(diff_content: str) -> Dict[str, Any]:
|
|
|
127
186
|
}
|
|
128
187
|
|
|
129
188
|
|
|
130
|
-
def audit_diff_file(file_path: str) -> Dict[str, Any]:
|
|
189
|
+
def audit_diff_file(file_path: str, check_memory: bool = False, root_dir: Optional[Path] = None) -> Dict[str, Any]:
|
|
131
190
|
path = Path(file_path)
|
|
132
191
|
if not path.is_file():
|
|
133
192
|
return {
|
|
@@ -136,23 +195,24 @@ def audit_diff_file(file_path: str) -> Dict[str, Any]:
|
|
|
136
195
|
"violations": []
|
|
137
196
|
}
|
|
138
197
|
content = path.read_text(encoding="utf-8", errors="replace")
|
|
139
|
-
return audit_diff(content)
|
|
198
|
+
return audit_diff(content, check_memory=check_memory, root_dir=root_dir)
|
|
140
199
|
|
|
141
200
|
|
|
142
201
|
def main():
|
|
143
202
|
parser = argparse.ArgumentParser(description="TorusGuard Unified Diff Security Scanner")
|
|
144
203
|
parser.add_argument("diff_path", nargs="?", help="Path to unified diff file (or read stdin if omitted)")
|
|
204
|
+
parser.add_argument("--check-memory", action="store_true", help="Check additions against persistent memory regression watch patterns")
|
|
145
205
|
parser.add_argument("--json", action="store_true", help="Output results as JSON")
|
|
146
206
|
args = parser.parse_args()
|
|
147
207
|
|
|
148
208
|
if args.diff_path:
|
|
149
|
-
res = audit_diff_file(args.diff_path)
|
|
209
|
+
res = audit_diff_file(args.diff_path, check_memory=args.check_memory)
|
|
150
210
|
else:
|
|
151
211
|
if sys.stdin.isatty():
|
|
152
212
|
parser.print_help()
|
|
153
213
|
sys.exit(1)
|
|
154
214
|
diff_text = sys.stdin.read()
|
|
155
|
-
res = audit_diff(diff_text)
|
|
215
|
+
res = audit_diff(diff_text, check_memory=args.check_memory)
|
|
156
216
|
|
|
157
217
|
if args.json:
|
|
158
218
|
print(json.dumps(res, indent=2))
|
|
@@ -1,86 +1,171 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
TorusGuard
|
|
4
|
-
Evaluates finding confidence against the objective 0–100 scoring model
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard Finding Confidence Scorer (v1.0.0)
|
|
4
|
+
Evaluates finding confidence against the objective 0–100 scoring model,
|
|
5
|
+
augmented by persistent memory patterns and false-positive suppression.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
import argparse
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, Any, Tuple, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def compute_memory_boost(
|
|
16
|
+
rule_id: str,
|
|
17
|
+
file_path: Optional[str] = None,
|
|
18
|
+
root_dir: Optional[Path] = None
|
|
19
|
+
) -> int:
|
|
20
|
+
"""
|
|
21
|
+
Query .torusguard/memory/patterns.json to calculate memory confidence modifier:
|
|
22
|
+
- False positive class: -30 (heavily suppressed)
|
|
23
|
+
- Regression watch: +15 (high alert / known recurrence)
|
|
24
|
+
- Recurring fix / Common vulnerability: +10
|
|
25
|
+
- Security idiom: +5
|
|
26
|
+
- Multi-file pattern match bonus: +5
|
|
27
|
+
"""
|
|
28
|
+
if not rule_id:
|
|
29
|
+
return 0
|
|
30
|
+
|
|
31
|
+
base = Path(root_dir or Path.cwd()).resolve()
|
|
32
|
+
# Search for .torusguard
|
|
33
|
+
torusguard_dir = base / ".torusguard"
|
|
34
|
+
if not torusguard_dir.exists():
|
|
35
|
+
for parent in base.parents:
|
|
36
|
+
if (parent / ".torusguard").exists():
|
|
37
|
+
torusguard_dir = parent / ".torusguard"
|
|
38
|
+
break
|
|
39
|
+
|
|
40
|
+
patterns_file = torusguard_dir / "memory" / "patterns.json"
|
|
41
|
+
if not patterns_file.exists():
|
|
42
|
+
return 0
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
with open(patterns_file, "r", encoding="utf-8") as f:
|
|
46
|
+
patterns = json.load(f)
|
|
47
|
+
except Exception:
|
|
48
|
+
return 0
|
|
49
|
+
|
|
50
|
+
boost = 0
|
|
51
|
+
matched_file = False
|
|
52
|
+
|
|
53
|
+
for pat in patterns:
|
|
54
|
+
if pat.get("rule_id") == rule_id:
|
|
55
|
+
ptype = pat.get("pattern_type")
|
|
56
|
+
if ptype == "false_positive_class":
|
|
57
|
+
boost -= 30
|
|
58
|
+
elif ptype == "regression_watch":
|
|
59
|
+
boost += 15
|
|
60
|
+
elif ptype in ("recurring_fix", "common_vulnerability"):
|
|
61
|
+
boost += 10
|
|
62
|
+
elif ptype == "security_idiom":
|
|
63
|
+
boost += 5
|
|
64
|
+
|
|
65
|
+
# File-specific correlation bonus
|
|
66
|
+
if file_path and file_path in pat.get("affected_files", []):
|
|
67
|
+
matched_file = True
|
|
68
|
+
|
|
69
|
+
if matched_file and boost > 0:
|
|
70
|
+
boost += 5
|
|
71
|
+
elif matched_file and boost < 0:
|
|
72
|
+
boost -= 10
|
|
73
|
+
|
|
74
|
+
return boost
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def compute_confidence_score(
|
|
78
|
+
evidence_quality: int = 35,
|
|
79
|
+
reproduction_success: int = 0,
|
|
80
|
+
independent_confirmations: int = 5,
|
|
81
|
+
environmental_clarity: int = 15,
|
|
82
|
+
manual_review_status: int = 0,
|
|
83
|
+
memory_boost: int = 0,
|
|
84
|
+
rule_id: Optional[str] = None,
|
|
85
|
+
file_path: Optional[str] = None,
|
|
86
|
+
root_dir: Optional[Path] = None
|
|
87
|
+
) -> Tuple[int, str, Dict[str, int]]:
|
|
88
|
+
"""
|
|
89
|
+
Computes total score and assigns confidence band.
|
|
90
|
+
Max points:
|
|
91
|
+
- evidence_quality: 35
|
|
92
|
+
- reproduction_success: 25
|
|
93
|
+
- independent_confirmations: 15
|
|
94
|
+
- environmental_clarity: 15
|
|
95
|
+
- manual_review_status: 10
|
|
96
|
+
- memory_boost: -30 to +20 (modifier from persistent memory)
|
|
97
|
+
Total is clamped to [0, 100].
|
|
98
|
+
"""
|
|
99
|
+
eq = min(max(evidence_quality, 0), 35)
|
|
100
|
+
rs = min(max(reproduction_success, 0), 25)
|
|
101
|
+
ic = min(max(independent_confirmations, 0), 15)
|
|
102
|
+
ec = min(max(environmental_clarity, 0), 15)
|
|
103
|
+
mr = min(max(manual_review_status, 0), 10)
|
|
104
|
+
|
|
105
|
+
# Auto-calculate memory boost if rule_id provided and memory_boost == 0
|
|
106
|
+
eff_mem_boost = memory_boost
|
|
107
|
+
if rule_id and eff_mem_boost == 0:
|
|
108
|
+
eff_mem_boost = compute_memory_boost(rule_id, file_path=file_path, root_dir=root_dir)
|
|
109
|
+
|
|
110
|
+
raw_total = eq + rs + ic + ec + mr + eff_mem_boost
|
|
111
|
+
total = min(max(raw_total, 0), 100)
|
|
112
|
+
|
|
113
|
+
if total >= 90:
|
|
114
|
+
band = "Confirmed"
|
|
115
|
+
elif total >= 70:
|
|
116
|
+
band = "High Confidence"
|
|
117
|
+
elif total >= 50:
|
|
118
|
+
band = "Medium Confidence"
|
|
119
|
+
else:
|
|
120
|
+
band = "Needs Review"
|
|
121
|
+
|
|
122
|
+
factors = {
|
|
123
|
+
"evidence_quality": eq,
|
|
124
|
+
"reproduction_success": rs,
|
|
125
|
+
"independent_confirmations": ic,
|
|
126
|
+
"environmental_clarity": ec,
|
|
127
|
+
"manual_review_status": mr,
|
|
128
|
+
"memory_boost": eff_mem_boost,
|
|
129
|
+
"total_score": total,
|
|
130
|
+
"classification_band": band
|
|
131
|
+
}
|
|
132
|
+
return total, band, factors
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def main():
|
|
136
|
+
parser = argparse.ArgumentParser(description="TorusGuard Confidence Scorer")
|
|
137
|
+
parser.add_argument("--eq", type=int, default=35, help="Evidence quality score (0-35)")
|
|
138
|
+
parser.add_argument("--rs", type=int, default=0, help="Reproduction success score (0-25)")
|
|
139
|
+
parser.add_argument("--ic", type=int, default=5, help="Independent confirmations score (0-15)")
|
|
140
|
+
parser.add_argument("--ec", type=int, default=15, help="Environmental clarity score (0-15)")
|
|
141
|
+
parser.add_argument("--mr", type=int, default=0, help="Manual review status score (0-10)")
|
|
142
|
+
parser.add_argument("--memory-boost", type=int, default=0, help="Memory boost score (-30 to +20)")
|
|
143
|
+
parser.add_argument("--rule-id", type=str, help="TorusGuard rule ID for memory pattern matching")
|
|
144
|
+
parser.add_argument("--file", type=str, help="File path for correlation matching")
|
|
145
|
+
parser.add_argument("--json", action="store_true", help="Output JSON")
|
|
146
|
+
args = parser.parse_args()
|
|
147
|
+
|
|
148
|
+
total, band, factors = compute_confidence_score(
|
|
149
|
+
evidence_quality=args.eq,
|
|
150
|
+
reproduction_success=args.rs,
|
|
151
|
+
independent_confirmations=args.ic,
|
|
152
|
+
environmental_clarity=args.ec,
|
|
153
|
+
manual_review_status=args.mr,
|
|
154
|
+
memory_boost=args.memory_boost,
|
|
155
|
+
rule_id=args.rule_id,
|
|
156
|
+
file_path=args.file
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
if args.json:
|
|
160
|
+
print(json.dumps(factors, indent=2))
|
|
161
|
+
else:
|
|
162
|
+
print(f"Total Confidence Score: {total}/100")
|
|
163
|
+
print(f"Classification Band: {band}")
|
|
164
|
+
print("Factor Breakdown:")
|
|
165
|
+
for k, v in factors.items():
|
|
166
|
+
if k not in ("total_score", "classification_band"):
|
|
167
|
+
print(f" - {k}: {v}")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__":
|
|
171
|
+
main()
|