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.
- package/.torusguard/.manifest.json +98 -79
- package/.torusguard/config/torusguard.json +1 -1
- package/.torusguard/references/csharp-security.md +41 -0
- package/.torusguard/references/go-security.md +41 -0
- package/.torusguard/references/java-security.md +40 -0
- package/.torusguard/references/polyglot-security-matrix.md +25 -0
- package/.torusguard/references/rust-security.md +40 -0
- package/.torusguard/rules/custom/.gitkeep +1 -0
- package/.torusguard/rules/custom/README.md +30 -0
- package/.torusguard/runs/report-latest.html +328 -0
- package/.torusguard/schemas/golden-recipe.schema.json +75 -0
- 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/diff_guard.py +202 -15
- package/.torusguard/scripts/finding_scorer.py +199 -86
- package/.torusguard/scripts/html_reporter.py +628 -0
- package/.torusguard/scripts/manifest_builder.py +7 -5
- package/.torusguard/scripts/memory_engine.py +1334 -0
- package/.torusguard/scripts/monorepo_detector.py +123 -10
- package/.torusguard/scripts/rules_sync.py +321 -0
- package/.torusguard/scripts/run_manager.py +171 -89
- package/.torusguard/scripts/stack_detect.py +458 -26
- package/.torusguard/skills/torusguard/SKILL.md +4 -3
- package/.torusguard/skills/torusguard/bootstrap.py +344 -56
- package/.torusguard/skills/torusguard/references/csharp-security.md +41 -0
- package/.torusguard/skills/torusguard/references/go-security.md +41 -0
- package/.torusguard/skills/torusguard/references/java-security.md +40 -0
- package/.torusguard/skills/torusguard/references/polyglot-security-matrix.md +25 -0
- package/.torusguard/skills/torusguard/references/rust-security.md +40 -0
- 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 +307 -401
- package/bin/torusguard.js +204 -6
- package/package.json +1 -1
- package/skills/torusguard/SKILL.md +4 -3
- package/skills/torusguard/bootstrap.py +68 -4
- package/skills/torusguard/payload/.manifest.json +98 -79
- package/skills/torusguard/payload/config/torusguard.json +1 -1
- package/skills/torusguard/payload/references/csharp-security.md +41 -0
- package/skills/torusguard/payload/references/go-security.md +41 -0
- package/skills/torusguard/payload/references/java-security.md +40 -0
- package/skills/torusguard/payload/references/polyglot-security-matrix.md +25 -0
- package/skills/torusguard/payload/references/rust-security.md +40 -0
- package/skills/torusguard/payload/rules/custom/.gitkeep +1 -0
- package/skills/torusguard/payload/rules/custom/README.md +30 -0
- package/skills/torusguard/payload/schemas/golden-recipe.schema.json +75 -0
- 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 +202 -15
- package/skills/torusguard/payload/scripts/finding_scorer.py +199 -86
- package/skills/torusguard/payload/scripts/html_reporter.py +628 -0
- package/skills/torusguard/payload/scripts/manifest_builder.py +7 -5
- package/skills/torusguard/payload/scripts/memory_engine.py +1334 -0
- package/skills/torusguard/payload/scripts/monorepo_detector.py +123 -10
- package/skills/torusguard/payload/scripts/rules_sync.py +321 -0
- package/skills/torusguard/payload/scripts/run_manager.py +171 -89
- package/skills/torusguard/payload/scripts/stack_detect.py +458 -26
- 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/references/csharp-security.md +41 -0
- package/skills/torusguard/payload/skills/torusguard/references/go-security.md +41 -0
- package/skills/torusguard/payload/skills/torusguard/references/java-security.md +40 -0
- package/skills/torusguard/payload/skills/torusguard/references/polyglot-security-matrix.md +25 -0
- package/skills/torusguard/payload/skills/torusguard/references/rust-security.md +40 -0
- 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/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
- package/skills/torusguard/__pycache__/bootstrap.cpython-311.pyc +0 -0
- 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
|
@@ -10,9 +10,33 @@ import sys
|
|
|
10
10
|
import shutil
|
|
11
11
|
import json
|
|
12
12
|
import argparse
|
|
13
|
-
import subprocess
|
|
14
13
|
from pathlib import Path
|
|
15
14
|
|
|
15
|
+
# Ensure UTF-8 stdout/stderr on Windows consoles
|
|
16
|
+
if sys.stdout and hasattr(sys.stdout, "reconfigure"):
|
|
17
|
+
try:
|
|
18
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
19
|
+
except Exception:
|
|
20
|
+
pass
|
|
21
|
+
if sys.stderr and hasattr(sys.stderr, "reconfigure"):
|
|
22
|
+
try:
|
|
23
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
24
|
+
except Exception:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
# ─── ANSI Color Helpers ───────────────────────────────────────────────────────
|
|
28
|
+
BOLD = "\033[1m"
|
|
29
|
+
DIM = "\033[2m"
|
|
30
|
+
RESET = "\033[0m"
|
|
31
|
+
CYAN = "\033[36m"
|
|
32
|
+
GREEN = "\033[32m"
|
|
33
|
+
YELLOW = "\033[33m"
|
|
34
|
+
WHITE = "\033[97m"
|
|
35
|
+
GRAY = "\033[90m"
|
|
36
|
+
RED = "\033[31m"
|
|
37
|
+
BG_GREEN = "\033[42m"
|
|
38
|
+
BG_CYAN = "\033[46m"
|
|
39
|
+
|
|
16
40
|
|
|
17
41
|
def find_project_root(start_dir=None):
|
|
18
42
|
"""Detect project root directory by searching for standard repo root markers."""
|
|
@@ -33,36 +57,141 @@ def find_project_root(start_dir=None):
|
|
|
33
57
|
return current
|
|
34
58
|
|
|
35
59
|
|
|
36
|
-
def
|
|
60
|
+
def print_header():
|
|
61
|
+
"""Print the branded TorusGuard header card."""
|
|
62
|
+
print(f"""
|
|
63
|
+
{CYAN}╭─────────────────────────────────────────────────────────────────────────╮{RESET}
|
|
64
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
65
|
+
{CYAN}│{RESET} {BOLD}{WHITE}🛡️ T O R U S G U A R D{RESET} {GRAY}v0.9.5{RESET} {CYAN}│{RESET}
|
|
66
|
+
{CYAN}│{RESET} {DIM}Autonomous Security Engine for AI-Built Applications{RESET} {CYAN}│{RESET}
|
|
67
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
68
|
+
{CYAN}╰─────────────────────────────────────────────────────────────────────────╯{RESET}
|
|
69
|
+
""")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def print_step_1_assets(file_count):
|
|
73
|
+
"""Print the enhanced Step 1 asset unpacking card."""
|
|
74
|
+
print(f""" {CYAN}┌─ {BOLD}Step 1/3{RESET} {CYAN}──────────────────────── {WHITE}Unpacking Governance Assets{RESET} {CYAN}──────┐{RESET}
|
|
75
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
76
|
+
{CYAN}│{RESET} {GREEN}✔{RESET} Canonical security rules {DIM}71 rules across 11 families{RESET} {CYAN}│{RESET}
|
|
77
|
+
{CYAN}│{RESET} {GREEN}✔{RESET} JSON validation schemas {DIM}8 formal schemas{RESET} {CYAN}│{RESET}
|
|
78
|
+
{CYAN}│{RESET} {GREEN}✔{RESET} Specialist agent specifications {DIM}5 isolated agents{RESET} {CYAN}│{RESET}
|
|
79
|
+
{CYAN}│{RESET} {GREEN}✔{RESET} Workflow templates {DIM}11 slash commands{RESET} {CYAN}│{RESET}
|
|
80
|
+
{CYAN}│{RESET} {GREEN}✔{RESET} Framework reference guides {DIM}10 security guides{RESET} {CYAN}│{RESET}
|
|
81
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
82
|
+
{CYAN}│{RESET} {BOLD}{WHITE}{file_count} files unpacked{RESET} {CYAN}│{RESET}
|
|
83
|
+
{CYAN}└───────────────────────────────────────────────────────────────────────┘{RESET}
|
|
84
|
+
""")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def print_step_2_profile(detected_stack=None):
|
|
88
|
+
"""Print the security profile & coverage card (in-process stack alignment)."""
|
|
89
|
+
if detected_stack and detected_stack.get("framework") and detected_stack.get("framework") != "None":
|
|
90
|
+
fw = str(detected_stack.get("framework"))
|
|
91
|
+
lang = str(detected_stack.get("language", ""))
|
|
92
|
+
label = f"Auto-aligned stack: {fw} ({lang})"
|
|
93
|
+
pad = " " * max(0, 66 - len(label))
|
|
94
|
+
status_line = f" {CYAN}│{RESET} {GREEN}✔{RESET} {BOLD}Auto-aligned stack:{RESET} {WHITE}{fw}{RESET} {DIM}({lang}){RESET}{pad}{CYAN}│{RESET}"
|
|
95
|
+
else:
|
|
96
|
+
status_line = f" {CYAN}│{RESET} {DIM}ℹ Stack auto-detected on first /torusguard-audit run{RESET} {CYAN}│{RESET}"
|
|
97
|
+
|
|
98
|
+
print(f""" {CYAN}┌─ {BOLD}Step 2/3{RESET} {CYAN}──────────────────── {WHITE}Security Profile & Coverage{RESET} {CYAN}────────┐{RESET}
|
|
99
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
100
|
+
{CYAN}│{RESET} {BOLD}Rule Families:{RESET} {CYAN}│{RESET}
|
|
101
|
+
{CYAN}│{RESET} {YELLOW}TG-SEC{RESET} Secrets & Credentials {YELLOW}TG-DB{RESET} Database Safety {CYAN}│{RESET}
|
|
102
|
+
{CYAN}│{RESET} {YELLOW}TG-INPUT{RESET} Input Validation {YELLOW}TG-AUTH{RESET} Authentication {CYAN}│{RESET}
|
|
103
|
+
{CYAN}│{RESET} {YELLOW}TG-CLIENT{RESET} Client Bundle Leaks {YELLOW}TG-DIFF{RESET} Diff Inspection {CYAN}│{RESET}
|
|
104
|
+
{CYAN}│{RESET} {YELLOW}TG-AGENT{RESET} AI Agent Security {YELLOW}TG-EDGE{RESET} Serverless {CYAN}│{RESET}
|
|
105
|
+
{CYAN}│{RESET} {YELLOW}TG-SUPPLY{RESET} Supply Chain & CI/CD {YELLOW}TG-SSRF{RESET} Outbound Net {CYAN}│{RESET}
|
|
106
|
+
{CYAN}│{RESET} {YELLOW}TG-BIZ{RESET} Business Logic {CYAN}│{RESET}
|
|
107
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
108
|
+
{CYAN}│{RESET} {BOLD}Supported Stacks:{RESET} {CYAN}│{RESET}
|
|
109
|
+
{CYAN}│{RESET} {GREEN}Python{RESET} Django {DIM}·{RESET} FastAPI {DIM}·{RESET} Flask {DIM}·{RESET} DRF {DIM}·{RESET} SQLAlchemy {CYAN}│{RESET}
|
|
110
|
+
{CYAN}│{RESET} {GREEN}Node.js{RESET} Next.js {DIM}·{RESET} Express {DIM}·{RESET} React {DIM}·{RESET} Supabase {DIM}·{RESET} Firebase {CYAN}│{RESET}
|
|
111
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
112
|
+
{status_line}
|
|
113
|
+
{CYAN}└───────────────────────────────────────────────────────────────────────┘{RESET}
|
|
114
|
+
""")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def print_step_3_bridges(registered_ides):
|
|
118
|
+
"""Print the IDE command registration card."""
|
|
119
|
+
lines = ""
|
|
120
|
+
for r in registered_ides:
|
|
121
|
+
lines += f" {CYAN}│{RESET} {GREEN}✔{RESET} {r:<67} {CYAN}│{RESET}\n"
|
|
122
|
+
|
|
123
|
+
print(f""" {CYAN}┌─ {BOLD}Step 3/3{RESET} {CYAN}─────────────────── {WHITE}AI IDE Command Registration{RESET} {CYAN}─────────┐{RESET}
|
|
124
|
+
{CYAN}│{RESET} {CYAN}│{RESET}
|
|
125
|
+
{lines} {CYAN}│{RESET} {CYAN}│{RESET}
|
|
126
|
+
{CYAN}└───────────────────────────────────────────────────────────────────────┘{RESET}
|
|
127
|
+
""")
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def print_success_card():
|
|
131
|
+
"""Print the final success card with next steps."""
|
|
132
|
+
print(f""" {GREEN}╔═══════════════════════════════════════════════════════════════════════╗{RESET}
|
|
133
|
+
{GREEN}║{RESET} {GREEN}║{RESET}
|
|
134
|
+
{GREEN}║{RESET} {GREEN}{BOLD}✅ WORKSPACE INITIALIZED SUCCESSFULLY{RESET} {GREEN}║{RESET}
|
|
135
|
+
{GREEN}║{RESET} {GREEN}║{RESET}
|
|
136
|
+
{GREEN}╠═══════════════════════════════════════════════════════════════════════╣{RESET}
|
|
137
|
+
{GREEN}║{RESET} {GREEN}║{RESET}
|
|
138
|
+
{GREEN}║{RESET} {BOLD}Next Steps:{RESET} {GREEN}║{RESET}
|
|
139
|
+
{GREEN}║{RESET} {GREEN}║{RESET}
|
|
140
|
+
{GREEN}║{RESET} {CYAN}1.{RESET} In AI Chat {WHITE}/torusguard-audit{RESET} or {WHITE}/torusguard{RESET} {GREEN}║{RESET}
|
|
141
|
+
{GREEN}║{RESET} {CYAN}2.{RESET} In Terminal {WHITE}npx torusguard status{RESET} {GREEN}║{RESET}
|
|
142
|
+
{GREEN}║{RESET} {CYAN}3.{RESET} In CI/CD {WHITE}npx torusguard audit{RESET} {GREEN}║{RESET}
|
|
143
|
+
{GREEN}║{RESET} {GREEN}║{RESET}
|
|
144
|
+
{GREEN}║{RESET} {DIM}Docs{RESET} {CYAN}https://github.com/githubmofo/TorusGuard{RESET} {GREEN}║{RESET}
|
|
145
|
+
{GREEN}║{RESET} {DIM}NPM{RESET} {CYAN}https://npmjs.com/package/torusguard{RESET} {GREEN}║{RESET}
|
|
146
|
+
{GREEN}║{RESET} {GREEN}║{RESET}
|
|
147
|
+
{GREEN}╚═══════════════════════════════════════════════════════════════════════╝{RESET}
|
|
148
|
+
""")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def print_already_initialized(target_root, cfg):
|
|
152
|
+
"""Print the already-initialized status card."""
|
|
153
|
+
print(f"""
|
|
154
|
+
{CYAN}╭─────────────────────────────────────────────────────────────────────────╮{RESET}
|
|
155
|
+
{CYAN}│{RESET} {BOLD}{WHITE}🛡️ TORUSGUARD WORKSPACE{RESET} {GREEN}[Active]{RESET} {CYAN}│{RESET}
|
|
156
|
+
{CYAN}╰─────────────────────────────────────────────────────────────────────────╯{RESET}
|
|
157
|
+
|
|
158
|
+
{BOLD}▸ Project Root:{RESET} {GREEN}{target_root}{RESET}
|
|
159
|
+
{BOLD}▸ Workspace:{RESET} {GREEN}.torusguard/{RESET} {DIM}(Already Initialized){RESET}
|
|
160
|
+
{BOLD}▸ Version:{RESET} {CYAN}{cfg.get('version', '1.0.0')}{RESET}
|
|
161
|
+
{BOLD}▸ Severity Floor:{RESET} {YELLOW}{cfg.get('severity_threshold', 'medium')}{RESET}
|
|
162
|
+
|
|
163
|
+
{DIM}To refresh templates or re-scaffold, run:{RESET}
|
|
164
|
+
{CYAN}npx torusguard init --force{RESET}
|
|
165
|
+
""")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def scaffold_workspace(target_root=None, force=False, full_commands=False):
|
|
37
169
|
"""Scaffold the .torusguard workspace into the target project root."""
|
|
38
170
|
target_root = Path(target_root or find_project_root()).resolve()
|
|
39
171
|
torusguard_target = target_root / ".torusguard"
|
|
40
172
|
script_dir = Path(__file__).resolve().parent
|
|
41
173
|
payload_dir = script_dir / "payload"
|
|
42
174
|
|
|
43
|
-
print("================================================================================")
|
|
44
|
-
print("TORUSGUARD WORKSPACE BOOTSTRAPPER")
|
|
45
|
-
print("================================================================================")
|
|
46
|
-
print(f"Target Directory: {target_root}")
|
|
47
|
-
print(f"Destination: {torusguard_target}")
|
|
48
|
-
|
|
49
175
|
if torusguard_target.exists() and not force:
|
|
50
|
-
print(f"\n[INFO] Workspace already exists at {torusguard_target}")
|
|
51
176
|
config_file = torusguard_target / "config" / "torusguard.json"
|
|
177
|
+
cfg = {}
|
|
52
178
|
if config_file.exists():
|
|
53
179
|
try:
|
|
54
180
|
with open(config_file, "r", encoding="utf-8") as f:
|
|
55
181
|
cfg = json.load(f)
|
|
56
|
-
print(f"Current Version: {cfg.get('version', 'unknown')}")
|
|
57
|
-
print(f"Severity Minimum: {cfg.get('severity_threshold', 'medium')}")
|
|
58
182
|
except Exception:
|
|
59
183
|
pass
|
|
60
|
-
|
|
184
|
+
print_already_initialized(target_root, cfg)
|
|
61
185
|
return True
|
|
62
186
|
|
|
63
|
-
#
|
|
187
|
+
# ── Header ──────────────────────────────────────────────────────────────
|
|
188
|
+
print_header()
|
|
189
|
+
print(f" {BOLD}▸ Target Project:{RESET} {WHITE}{target_root}{RESET}")
|
|
190
|
+
print(f" {BOLD}▸ Destination:{RESET} {WHITE}{torusguard_target}{RESET}")
|
|
191
|
+
|
|
192
|
+
# ── Step 1: Unpack Payload ──────────────────────────────────────────────
|
|
193
|
+
file_count = 93
|
|
64
194
|
if payload_dir.is_dir():
|
|
65
|
-
print("\n1. Unpacking bundled offline workspace payload...")
|
|
66
195
|
try:
|
|
67
196
|
if torusguard_target.exists() and force:
|
|
68
197
|
shutil.rmtree(torusguard_target)
|
|
@@ -71,22 +200,25 @@ def scaffold_workspace(target_root=None, force=False):
|
|
|
71
200
|
torusguard_target,
|
|
72
201
|
ignore=shutil.ignore_patterns("runs", "*.pyc", "__pycache__", ".git*")
|
|
73
202
|
)
|
|
74
|
-
|
|
203
|
+
# Count actual files
|
|
204
|
+
file_count = sum(1 for _ in torusguard_target.rglob("*") if _.is_file())
|
|
75
205
|
except Exception as e:
|
|
76
|
-
print(f"
|
|
206
|
+
print(f"\n {RED}✖ Failed to unpack payload: {e}{RESET}")
|
|
77
207
|
return False
|
|
78
208
|
else:
|
|
79
209
|
# Fallback: create base structure
|
|
80
|
-
print("\n1. Bundled payload not found. Creating core skeleton...")
|
|
81
210
|
subdirs = [
|
|
82
211
|
"config", "agents", "workflows", "scripts", "templates",
|
|
83
212
|
"schemas", "references", "rules/active", "runs"
|
|
84
213
|
]
|
|
85
214
|
for s in subdirs:
|
|
86
215
|
(torusguard_target / s).mkdir(parents=True, exist_ok=True)
|
|
87
|
-
|
|
216
|
+
file_count = 0
|
|
217
|
+
|
|
218
|
+
print()
|
|
219
|
+
print_step_1_assets(file_count)
|
|
88
220
|
|
|
89
|
-
#
|
|
221
|
+
# ── Ensure runs and rules/active directories exist ──────────────────────
|
|
90
222
|
runs_dir = torusguard_target / "runs"
|
|
91
223
|
runs_dir.mkdir(parents=True, exist_ok=True)
|
|
92
224
|
gitkeep_runs = runs_dir / ".gitkeep"
|
|
@@ -99,52 +231,207 @@ def scaffold_workspace(target_root=None, force=False):
|
|
|
99
231
|
if not gitkeep_rules.exists():
|
|
100
232
|
gitkeep_rules.write_text("", encoding="utf-8")
|
|
101
233
|
|
|
102
|
-
#
|
|
103
|
-
|
|
234
|
+
# ── Ensure memory subsystem is initialized (v1.0.0) ────────────────────
|
|
235
|
+
memory_dir = torusguard_target / "memory"
|
|
236
|
+
memory_dir.mkdir(parents=True, exist_ok=True)
|
|
237
|
+
events_dir = memory_dir / "events"
|
|
238
|
+
events_dir.mkdir(parents=True, exist_ok=True)
|
|
239
|
+
|
|
240
|
+
gitkeep_events = events_dir / ".gitkeep"
|
|
241
|
+
if not gitkeep_events.exists():
|
|
242
|
+
gitkeep_events.write_text("", encoding="utf-8")
|
|
243
|
+
|
|
244
|
+
mem_gitignore = memory_dir / ".gitignore"
|
|
245
|
+
if not mem_gitignore.exists():
|
|
246
|
+
mem_gitignore.write_text("*\n", encoding="utf-8")
|
|
247
|
+
|
|
248
|
+
decay_file = memory_dir / "decay.json"
|
|
249
|
+
if not decay_file.exists():
|
|
250
|
+
decay_file.write_text(json.dumps({
|
|
251
|
+
"default_ttl_days": 90,
|
|
252
|
+
"decay_rate": 0.15,
|
|
253
|
+
"last_decay_run": None
|
|
254
|
+
}, indent=2), encoding="utf-8")
|
|
255
|
+
|
|
256
|
+
patterns_file = memory_dir / "patterns.json"
|
|
257
|
+
if not patterns_file.exists():
|
|
258
|
+
patterns_file.write_text("[]", encoding="utf-8")
|
|
259
|
+
|
|
260
|
+
profile_file = memory_dir / "profile.json"
|
|
261
|
+
if not profile_file.exists():
|
|
262
|
+
profile_file.write_text(json.dumps({
|
|
263
|
+
"stack": [],
|
|
264
|
+
"total_events": 0,
|
|
265
|
+
"active_patterns_count": 0,
|
|
266
|
+
"fix_rate_percentage": None,
|
|
267
|
+
"top_vulnerabilities": [],
|
|
268
|
+
"last_updated": None
|
|
269
|
+
}, indent=2), encoding="utf-8")
|
|
270
|
+
|
|
271
|
+
context_file = memory_dir / "context.json"
|
|
272
|
+
if not context_file.exists():
|
|
273
|
+
context_file.write_text(json.dumps({
|
|
274
|
+
"version": "1.0.0",
|
|
275
|
+
"generated_at": None,
|
|
276
|
+
"token_estimate": 0,
|
|
277
|
+
"max_token_budget": 2000,
|
|
278
|
+
"project_profile": {
|
|
279
|
+
"stack": [],
|
|
280
|
+
"total_events": 0,
|
|
281
|
+
"active_patterns_count": 0,
|
|
282
|
+
"fix_rate_percentage": None,
|
|
283
|
+
"top_vulnerabilities": []
|
|
284
|
+
},
|
|
285
|
+
"cards": []
|
|
286
|
+
}, indent=2), encoding="utf-8")
|
|
287
|
+
|
|
288
|
+
# Ensure target project root .gitignore excludes .torusguard/memory/
|
|
289
|
+
root_gitignore = target_root / ".gitignore"
|
|
290
|
+
if root_gitignore.exists():
|
|
291
|
+
try:
|
|
292
|
+
gi_content = root_gitignore.read_text(encoding="utf-8")
|
|
293
|
+
if ".torusguard/memory" not in gi_content:
|
|
294
|
+
root_gitignore.write_text(gi_content.rstrip() + "\n\n# TorusGuard security memory (local only)\n.torusguard/memory/\n", encoding="utf-8")
|
|
295
|
+
except Exception:
|
|
296
|
+
pass
|
|
297
|
+
|
|
298
|
+
# ── Step 2: Security Profile & Coverage (In-Process, Zero Subprocess) ──
|
|
299
|
+
# Execute stack detection in-process without spawning child processes (Socket.dev safe)
|
|
300
|
+
detected_stack = None
|
|
104
301
|
stack_detect_script = torusguard_target / "scripts" / "stack_detect.py"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if stack_detect_script.exists():
|
|
302
|
+
if stack_detect_script.is_file():
|
|
108
303
|
try:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
print(f" [DETECTED] Framework: {detected_stack.get('framework')}")
|
|
119
|
-
print(f" [DETECTED] Data Layer: {detected_stack.get('data_layer')}")
|
|
120
|
-
except Exception as e:
|
|
121
|
-
print(f" [WARN] Stack detection encountered error: {e}")
|
|
304
|
+
import importlib.util
|
|
305
|
+
spec = importlib.util.spec_from_file_location("stack_detect", str(stack_detect_script))
|
|
306
|
+
if spec and spec.loader:
|
|
307
|
+
sd_mod = importlib.util.module_from_spec(spec)
|
|
308
|
+
spec.loader.exec_module(sd_mod)
|
|
309
|
+
if hasattr(sd_mod, "detect_stack"):
|
|
310
|
+
detected_stack = sd_mod.detect_stack(target_root)
|
|
311
|
+
except Exception:
|
|
312
|
+
detected_stack = None
|
|
122
313
|
|
|
123
|
-
# 4. Update torusguard.json configuration
|
|
124
314
|
config_file = torusguard_target / "config" / "torusguard.json"
|
|
125
315
|
if config_file.exists():
|
|
126
316
|
try:
|
|
127
317
|
with open(config_file, "r", encoding="utf-8") as f:
|
|
128
318
|
cfg = json.load(f)
|
|
129
|
-
|
|
130
|
-
"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
319
|
+
if detected_stack and detected_stack.get("framework") != "None":
|
|
320
|
+
cfg["detected_stack"] = {
|
|
321
|
+
"language": detected_stack.get("language"),
|
|
322
|
+
"framework": detected_stack.get("framework"),
|
|
323
|
+
"data_layer": detected_stack.get("data_layer")
|
|
324
|
+
}
|
|
325
|
+
else:
|
|
326
|
+
cfg["detected_stack"] = {
|
|
327
|
+
"language": "Unknown",
|
|
328
|
+
"framework": "None",
|
|
329
|
+
"data_layer": "None"
|
|
330
|
+
}
|
|
134
331
|
with open(config_file, "w", encoding="utf-8") as f:
|
|
135
332
|
json.dump(cfg, f, indent=2)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
333
|
+
except Exception:
|
|
334
|
+
pass
|
|
335
|
+
|
|
336
|
+
print_step_2_profile(detected_stack)
|
|
337
|
+
|
|
338
|
+
# ── Step 3: Register Slash Commands for AI IDEs ─────────────────────────
|
|
339
|
+
registered_ides = []
|
|
340
|
+
tg_workflow_content = """---
|
|
341
|
+
description: TorusGuard Autonomous Security Command Engine — run static security audits, authorized runtime web validation, governed remediation, and SARIF exports.
|
|
342
|
+
version: 1.0.0
|
|
343
|
+
tools: Read, Grep, Glob, Bash, Edit, Write
|
|
344
|
+
agent: auditor
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
# /torusguard — Autonomous Application Security Guardrails
|
|
348
|
+
|
|
349
|
+
$ARGUMENTS
|
|
350
|
+
|
|
351
|
+
## Objective
|
|
352
|
+
Execute TorusGuard security workflows across Python and TypeScript codebases.
|
|
353
|
+
|
|
354
|
+
## Execution
|
|
355
|
+
Parse the requested action from `$ARGUMENTS` (e.g. `audit`, `verify`, `web-validate`, `exploit-check`, `harden`, `apply`, `recheck`, `report`, `status`, `init`):
|
|
356
|
+
1. **If action is omitted or 'status':** View `.torusguard/workflows/status.md` and report posture.
|
|
357
|
+
2. **If action is specified:** Load the dedicated workflow from `.torusguard/workflows/<action>.md` and matching skill from `.torusguard/skills/torusguard-<action>/SKILL.md`.
|
|
358
|
+
3. Follow the phase execution steps defined in the workflow.
|
|
359
|
+
"""
|
|
360
|
+
|
|
361
|
+
# Ensure .agent/workflows and .agents/workflows are created
|
|
362
|
+
dest_workflow_dirs = []
|
|
363
|
+
if (target_root / ".agents").exists():
|
|
364
|
+
agents_wf = target_root / ".agents" / "workflows"
|
|
365
|
+
agents_wf.mkdir(parents=True, exist_ok=True)
|
|
366
|
+
(agents_wf / "torusguard.md").write_text(tg_workflow_content, encoding="utf-8")
|
|
367
|
+
dest_workflow_dirs.append(agents_wf)
|
|
368
|
+
registered_ides.append("Antigravity / Gemini .agents/workflows/torusguard.md")
|
|
369
|
+
|
|
370
|
+
agent_wf = target_root / ".agent" / "workflows"
|
|
371
|
+
agent_wf.mkdir(parents=True, exist_ok=True)
|
|
372
|
+
(agent_wf / "torusguard.md").write_text(tg_workflow_content, encoding="utf-8")
|
|
373
|
+
dest_workflow_dirs.append(agent_wf)
|
|
374
|
+
registered_ides.append("Tribunal Agent Kit .agent/workflows/torusguard.md")
|
|
375
|
+
|
|
376
|
+
# When full_commands is requested (e.g. via NPM package npx torusguard init),
|
|
377
|
+
# unlock and register all 11 individual slash commands
|
|
378
|
+
if full_commands:
|
|
379
|
+
src_wf = torusguard_target / "workflows"
|
|
380
|
+
if src_wf.is_dir():
|
|
381
|
+
count = 0
|
|
382
|
+
for wf_file in src_wf.glob("*.md"):
|
|
383
|
+
if wf_file.name == "torusguard.md":
|
|
384
|
+
continue
|
|
385
|
+
cmd_filename = f"torusguard-{wf_file.name}"
|
|
386
|
+
for d in dest_workflow_dirs:
|
|
387
|
+
shutil.copy2(wf_file, d / cmd_filename)
|
|
388
|
+
count += 1
|
|
389
|
+
registered_ides.append(f"{count} Slash Commands /torusguard-audit, -harden, -apply, ...")
|
|
390
|
+
|
|
391
|
+
# Claude Code (.claude/commands)
|
|
392
|
+
claude_dir = target_root / ".claude"
|
|
393
|
+
if claude_dir.exists():
|
|
394
|
+
claude_commands = claude_dir / "commands"
|
|
395
|
+
claude_commands.mkdir(parents=True, exist_ok=True)
|
|
396
|
+
(claude_commands / "torusguard.md").write_text(tg_workflow_content, encoding="utf-8")
|
|
397
|
+
registered_ides.append("Claude Code .claude/commands/torusguard.md")
|
|
398
|
+
|
|
399
|
+
# Cursor (.cursor/rules)
|
|
400
|
+
cursor_dir = target_root / ".cursor"
|
|
401
|
+
if cursor_dir.exists():
|
|
402
|
+
cursor_rules = cursor_dir / "rules"
|
|
403
|
+
cursor_rules.mkdir(parents=True, exist_ok=True)
|
|
404
|
+
(cursor_rules / "torusguard.mdc").write_text(tg_workflow_content, encoding="utf-8")
|
|
405
|
+
registered_ides.append("Cursor .cursor/rules/torusguard.mdc")
|
|
406
|
+
|
|
407
|
+
# Windsurf (.windsurfrules)
|
|
408
|
+
if (target_root / ".windsurfrules").exists() or (target_root / ".windsurf").exists():
|
|
409
|
+
windsurf_rules = target_root / ".windsurfrules"
|
|
410
|
+
current_content = windsurf_rules.read_text(encoding="utf-8") if windsurf_rules.exists() else ""
|
|
411
|
+
if "TorusGuard" not in current_content:
|
|
412
|
+
windsurf_rules.write_text(current_content + "\n\n" + tg_workflow_content, encoding="utf-8")
|
|
413
|
+
registered_ides.append("Windsurf .windsurfrules")
|
|
414
|
+
|
|
415
|
+
# VS Code / GitHub Copilot (.github/copilot-instructions.md)
|
|
416
|
+
github_dir = target_root / ".github"
|
|
417
|
+
if github_dir.exists():
|
|
418
|
+
copilot_file = github_dir / "copilot-instructions.md"
|
|
419
|
+
current_content = copilot_file.read_text(encoding="utf-8") if copilot_file.exists() else ""
|
|
420
|
+
if "TorusGuard" not in current_content:
|
|
421
|
+
copilot_file.write_text(current_content + "\n\n# TorusGuard Security Instructions\n" + tg_workflow_content, encoding="utf-8")
|
|
422
|
+
registered_ides.append("VS Code / Copilot .github/copilot-instructions.md")
|
|
423
|
+
|
|
424
|
+
# Universal AGENTS.md (Kimi, Codex, Open Agent Standard)
|
|
425
|
+
agents_md = target_root / "AGENTS.md"
|
|
426
|
+
current_agents = agents_md.read_text(encoding="utf-8") if agents_md.exists() else ""
|
|
427
|
+
if "TorusGuard" not in current_agents:
|
|
428
|
+
agents_md.write_text(current_agents + ("\n\n" if current_agents else "") + "# TorusGuard Security Guardrails\n\nRun `/torusguard audit` to scan the codebase or refer to `.torusguard/` for security guidelines.\n", encoding="utf-8")
|
|
429
|
+
registered_ides.append("Universal AGENTS.md Kimi / Open Agent Standard")
|
|
430
|
+
|
|
431
|
+
print_step_3_bridges(registered_ides)
|
|
432
|
+
|
|
433
|
+
# ── Success Card ────────────────────────────────────────────────────────
|
|
434
|
+
print_success_card()
|
|
148
435
|
return True
|
|
149
436
|
|
|
150
437
|
|
|
@@ -152,7 +439,8 @@ if __name__ == "__main__":
|
|
|
152
439
|
parser = argparse.ArgumentParser(description="TorusGuard Autonomous Workspace Bootstrapper")
|
|
153
440
|
parser.add_argument("--target", type=str, help="Target project root directory")
|
|
154
441
|
parser.add_argument("--force", action="store_true", help="Force overwrite existing workspace")
|
|
442
|
+
parser.add_argument("--full-commands", action="store_true", help="Unlock and register all 11 individual slash commands")
|
|
155
443
|
args = parser.parse_args()
|
|
156
444
|
|
|
157
|
-
success = scaffold_workspace(target_root=args.target, force=args.force)
|
|
445
|
+
success = scaffold_workspace(target_root=args.target, force=args.force, full_commands=args.full_commands)
|
|
158
446
|
sys.exit(0 if success else 1)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# TorusGuard Skill Reference: C# & ASP.NET Core Security
|
|
2
|
+
|
|
3
|
+
> **Loaded When:** A project is identified as a C# / .NET application (`*.csproj`, `*.sln`, ASP.NET Core detected).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🛡️ Key Inspection Areas & Rules
|
|
8
|
+
|
|
9
|
+
### 1. Authentication & Authorization
|
|
10
|
+
* `TG-AUTH-001`: Ensure controllers and endpoints have `[Authorize]` attributes.
|
|
11
|
+
* Prohibit unvetted `[AllowAnonymous]` on sensitive business logic or user data endpoints.
|
|
12
|
+
|
|
13
|
+
### 2. Entity Framework Core & SQL Injection
|
|
14
|
+
* `TG-INPUT-002`: Use LINQ expressions or `FromSqlInterpolated` with interpolated string syntax (EF Core converts parameters automatically).
|
|
15
|
+
* Prohibit raw `FromSqlRaw` with un-parameterized string concatenations.
|
|
16
|
+
* `TG-DB-004`: Configure Global Query Filters (`HasQueryFilter(e => e.TenantId == _currentTenant)`) for multi-tenant safety.
|
|
17
|
+
|
|
18
|
+
### 3. Anti-Forgery & TLS
|
|
19
|
+
* `TG-CSRF-001`: Ensure `[ValidateAntiForgeryToken]` or `[AutoValidateAntiforgeryToken]` is applied to POST/PUT/DELETE actions.
|
|
20
|
+
* Prohibit `DangerousAcceptAnyServerCertificateValidator`.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🛠️ Safe Patterns Summary
|
|
25
|
+
|
|
26
|
+
```csharp
|
|
27
|
+
// Safe Entity Framework Parameterized Query
|
|
28
|
+
var user = await context.Users
|
|
29
|
+
.Where(u => u.Id == userId && u.TenantId == currentTenantId)
|
|
30
|
+
.FirstOrDefaultAsync();
|
|
31
|
+
|
|
32
|
+
// Safe Global Query Filter in DbContext
|
|
33
|
+
modelBuilder.Entity<Invoice>()
|
|
34
|
+
.HasQueryFilter(i => i.TenantId == _tenantProvider.GetTenantId());
|
|
35
|
+
|
|
36
|
+
// Safe Controller Security
|
|
37
|
+
[Authorize]
|
|
38
|
+
[ApiController]
|
|
39
|
+
[Route("api/[controller]")]
|
|
40
|
+
public class InvoicesController : ControllerBase { ... }
|
|
41
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# TorusGuard Skill Reference: Go Security
|
|
2
|
+
|
|
3
|
+
> **Loaded When:** A project is identified as a Go application (`go.mod`, `go.sum`, or Go source files detected).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🛡️ Key Inspection Areas & Rules
|
|
8
|
+
|
|
9
|
+
### 1. Database & SQL Injection
|
|
10
|
+
* `TG-INPUT-002`: Ensure raw queries use parameterized placeholders (`?`, `$1`), never `fmt.Sprintf` or string concatenation.
|
|
11
|
+
* `TG-DB-004`: Enforce tenant isolation in GORM queries (`db.Where("tenant_id = ?", tenantID)`).
|
|
12
|
+
|
|
13
|
+
### 2. TLS & Network Security
|
|
14
|
+
* `TG-DIFF-001`: Prohibit `InsecureSkipVerify: true` in `tls.Config`. Always use valid root CA pools.
|
|
15
|
+
* `TG-SSRF-001`: Validate outbound URLs before issuing `http.Get` or `http.Post`.
|
|
16
|
+
|
|
17
|
+
### 3. Concurrency & Goroutine Safety
|
|
18
|
+
* `TG-BIZ-001`: Ensure context cancellation propagation (`ctx.Done()`) to prevent goroutine leaks.
|
|
19
|
+
* Use mutexes or channels to prevent data races on shared state.
|
|
20
|
+
|
|
21
|
+
### 4. Input Validation & Path Traversal
|
|
22
|
+
* `TG-INPUT-006`: Sanitize file paths with `filepath.Clean` and check `strings.HasPrefix(cleanPath, baseDir)`.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 🛠️ Safe Patterns Summary
|
|
27
|
+
|
|
28
|
+
```go
|
|
29
|
+
// Safe Parameterized Query
|
|
30
|
+
row := db.QueryRowContext(ctx, "SELECT id, email FROM users WHERE id = ? AND tenant_id = ?", userID, tenantID)
|
|
31
|
+
|
|
32
|
+
// Safe GORM Scoping
|
|
33
|
+
var invoice Invoice
|
|
34
|
+
result := db.Where("id = ? AND tenant_id = ?", invoiceID, currentTenantID).First(&invoice)
|
|
35
|
+
|
|
36
|
+
// Safe TLS Client
|
|
37
|
+
tlsConfig := &tls.Config{
|
|
38
|
+
MinVersion: tls.VersionTLS13,
|
|
39
|
+
}
|
|
40
|
+
client := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
|
|
41
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# TorusGuard Skill Reference: Java & Spring Security
|
|
2
|
+
|
|
3
|
+
> **Loaded When:** A project is identified as a Java/Kotlin application (`pom.xml`, `build.gradle`, Spring Boot detected).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🛡️ Key Inspection Areas & Rules
|
|
8
|
+
|
|
9
|
+
### 1. Spring Security & CSRF
|
|
10
|
+
* `TG-CSRF-001`: Prohibit `.csrf().disable()` or `AbstractHttpConfigurer::disable` on state-changing browser routes.
|
|
11
|
+
* `TG-PLATFORM-001`: Avoid `@CrossOrigin(origins = "*")` with `allowCredentials = "true"`.
|
|
12
|
+
|
|
13
|
+
### 2. JPA & Hibernate SQL Injection
|
|
14
|
+
* `TG-INPUT-002`: Use named parameters (`:param`) or `CriteriaBuilder`. Never concatenate strings into JPQL queries.
|
|
15
|
+
* `TG-DB-004`: Enforce tenant isolation via `@Filter` or explicit where clauses.
|
|
16
|
+
|
|
17
|
+
### 3. Insecure Deserialization & XML
|
|
18
|
+
* Prohibit `ObjectInputStream.readObject()` on untrusted input without look-ahead verification.
|
|
19
|
+
* Disable external entity resolution (`setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)`).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 🛠️ Safe Patterns Summary
|
|
24
|
+
|
|
25
|
+
```java
|
|
26
|
+
// Safe JPA Query
|
|
27
|
+
@Query("SELECT u FROM User u WHERE u.id = :id AND u.tenantId = :tenantId")
|
|
28
|
+
Optional<User> findByIdAndTenantId(@Param("id") Long id, @Param("tenantId") String tenantId);
|
|
29
|
+
|
|
30
|
+
// Safe Spring Security Configuration
|
|
31
|
+
@Bean
|
|
32
|
+
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
33
|
+
http
|
|
34
|
+
.authorizeHttpRequests(auth -> auth
|
|
35
|
+
.requestMatchers("/public/**").permitAll()
|
|
36
|
+
.anyRequest().authenticated()
|
|
37
|
+
);
|
|
38
|
+
return http.build();
|
|
39
|
+
}
|
|
40
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# TorusGuard Universal Polyglot Security Matrix
|
|
2
|
+
|
|
3
|
+
> **Loaded When:** Any language or framework is detected. Maps universal security invariants across major programming language ecosystems.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🛡️ Cross-Language Invariant Mappings
|
|
8
|
+
|
|
9
|
+
| Rule Family | Python | TypeScript / Node.js | Go | Rust | Java / Kotlin | C# / .NET |
|
|
10
|
+
|---|---|---|---|---|---|---|
|
|
11
|
+
| **TG-SEC (Secrets)** | `os.environ["KEY"]` | `process.env.KEY` | `os.Getenv("KEY")` | `std::env::var("KEY")` | `System.getenv("KEY")` | `Environment.GetEnvironmentVariable()` |
|
|
12
|
+
| **TG-DB (SQL Injection)** | `%s` / ORM bound | `$1` / Prisma / Drizzle | `?` / `$1` / GORM `?` | `sqlx::query!` / Diesel | Named parameters `:param` | `@p0` / `FromSqlInterpolated` |
|
|
13
|
+
| **TG-DB-004 (Tenant Scope)** | `.filter(tenant=...)` | `where: { tenantId }` | `.Where("tenant_id = ?", tid)` | `filter(tenant_id.eq(tid))` | `WHERE e.tenantId = :tid` | `.Where(x => x.TenantId == tid)` |
|
|
14
|
+
| **TG-AUTH (Access Control)** | `@login_required` / Depends | Middleware auth / Guards | Middleware handlers | Tower layer / extractors | `@PreAuthorize` / Spring Sec | `[Authorize]` attributes |
|
|
15
|
+
| **TG-CSRF (Request Forgery)** | CSRF Middleware | SameSite / csurf | Gorilla CSRF | Anti-CSRF token middleware | Spring Security CSRF | `[ValidateAntiForgeryToken]` |
|
|
16
|
+
| **TG-DIFF (Bypass Comments)** | No `# nosec` | No `// nosec` | No `/* nosec */` | No `#![allow(unsafe)]` | No `@SuppressWarnings` | No pragma disable |
|
|
17
|
+
| **TG-DIFF (TLS Verification)** | No `verify=False` | No `rejectUnauthorized:false` | No `InsecureSkipVerify: true` | No `danger_accept_invalid_certs`| No `TrustAllStrategy` | No `DangerousAcceptAny...` |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 🚀 Polyglot Hardening Rules of Thumb
|
|
22
|
+
|
|
23
|
+
1. **Parameterize Everything:** Never concatenate raw user input into SQL, shell commands, LDAP filters, or template strings, regardless of language.
|
|
24
|
+
2. **Fail Closed on Auth:** Default all endpoints to authenticated; explicitly mark public routes rather than remembering to protect private ones.
|
|
25
|
+
3. **Strict Bounds:** Keep remediation diffs minimal ($\le 35$ additions, $\le 25$ deletions) to ensure auditability across all codebases.
|