torusguard 0.9.2
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 +95 -0
- package/.torusguard/ARCHITECTURE.md +168 -0
- package/.torusguard/TORUSGUARD.md +145 -0
- package/.torusguard/agents/auditor.md +41 -0
- package/.torusguard/agents/profiler.md +49 -0
- package/.torusguard/agents/remediator.md +41 -0
- package/.torusguard/agents/reviewer.md +39 -0
- package/.torusguard/agents/validator.md +46 -0
- package/.torusguard/config/scope.json +24 -0
- package/.torusguard/config/slash-commands.json +102 -0
- package/.torusguard/config/torusguard.json +30 -0
- package/.torusguard/references/django-security.md +43 -0
- package/.torusguard/references/drf-security.md +20 -0
- package/.torusguard/references/express-security.md +103 -0
- package/.torusguard/references/fastapi-security.md +20 -0
- package/.torusguard/references/firebase-security.md +78 -0
- package/.torusguard/references/flask-security.md +20 -0
- package/.torusguard/references/nextjs-security.md +96 -0
- package/.torusguard/references/react-vite-security.md +97 -0
- package/.torusguard/references/sqlalchemy-security.md +16 -0
- package/.torusguard/references/supabase-security.md +84 -0
- package/.torusguard/rules/README.md +62 -0
- package/.torusguard/rules/TORUSGUARD.md +145 -0
- package/.torusguard/rules/active/.gitkeep +0 -0
- package/.torusguard/rules/active/TG-DIFF-001.md +20 -0
- package/.torusguard/rules/active/TG-DIFF-002.md +20 -0
- package/.torusguard/rules/active/TG-DIFF-003.md +19 -0
- package/.torusguard/runs/.gitkeep +0 -0
- package/.torusguard/schemas/authorization.schema.json +81 -0
- package/.torusguard/schemas/confidence.schema.json +72 -0
- package/.torusguard/schemas/evidence.schema.json +66 -0
- package/.torusguard/schemas/finding.schema.json +164 -0
- package/.torusguard/schemas/provenance.schema.json +46 -0
- package/.torusguard/schemas/remediation.schema.json +59 -0
- package/.torusguard/schemas/retest.schema.json +53 -0
- package/.torusguard/schemas/runtime-evidence.schema.json +72 -0
- package/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
- package/.torusguard/scripts/diff_guard.py +171 -0
- package/.torusguard/scripts/finding_scorer.py +86 -0
- package/.torusguard/scripts/manifest_builder.py +130 -0
- package/.torusguard/scripts/monorepo_detector.py +164 -0
- package/.torusguard/scripts/run_manager.py +89 -0
- package/.torusguard/scripts/safety_gate.py +64 -0
- package/.torusguard/scripts/sarif_exporter.py +116 -0
- package/.torusguard/scripts/stack_detect.py +152 -0
- package/.torusguard/skills/torusguard/SKILL.md +37 -0
- package/.torusguard/skills/torusguard/bootstrap.py +158 -0
- package/.torusguard/skills/torusguard/references/auth-and-sessions.md +56 -0
- package/.torusguard/skills/torusguard/references/business-logic-and-abuse.md +23 -0
- package/.torusguard/skills/torusguard/references/cache-and-sensitive-responses.md +10 -0
- package/.torusguard/skills/torusguard/references/client-code-exposure.md +55 -0
- package/.torusguard/skills/torusguard/references/csrf-and-cross-origin.md +11 -0
- package/.torusguard/skills/torusguard/references/dependency-and-supply-chain.md +22 -0
- package/.torusguard/skills/torusguard/references/django-security.md +43 -0
- package/.torusguard/skills/torusguard/references/drf-security.md +20 -0
- package/.torusguard/skills/torusguard/references/fastapi-security.md +20 -0
- package/.torusguard/skills/torusguard/references/flask-security.md +20 -0
- package/.torusguard/skills/torusguard/references/frontend-no-db.md +53 -0
- package/.torusguard/skills/torusguard/references/graphql-security.md +12 -0
- package/.torusguard/skills/torusguard/references/input-and-injection.md +51 -0
- package/.torusguard/skills/torusguard/references/mass-assignment-and-property-auth.md +22 -0
- package/.torusguard/skills/torusguard/references/platform-hardening.md +56 -0
- package/.torusguard/skills/torusguard/references/python-dependencies.md +16 -0
- package/.torusguard/skills/torusguard/references/python-security-overview.md +12 -0
- package/.torusguard/skills/torusguard/references/rate-limit-and-abuse.md +57 -0
- package/.torusguard/skills/torusguard/references/secrets-and-config.md +64 -0
- package/.torusguard/skills/torusguard/references/sqlalchemy-security.md +16 -0
- package/.torusguard/skills/torusguard/references/ssrf-and-outbound-requests.md +46 -0
- package/.torusguard/skills/torusguard/references/webhook-security.md +15 -0
- package/.torusguard/skills/torusguard/references/websocket-security.md +12 -0
- package/.torusguard/skills/torusguard-apply/SKILL.md +46 -0
- package/.torusguard/skills/torusguard-audit/SKILL.md +70 -0
- package/.torusguard/skills/torusguard-authorize/SKILL.md +47 -0
- package/.torusguard/skills/torusguard-exploit-check/SKILL.md +64 -0
- package/.torusguard/skills/torusguard-full/SKILL.md +70 -0
- package/.torusguard/skills/torusguard-harden/SKILL.md +63 -0
- package/.torusguard/skills/torusguard-init/SKILL.md +52 -0
- package/.torusguard/skills/torusguard-recheck/SKILL.md +53 -0
- package/.torusguard/skills/torusguard-report/SKILL.md +54 -0
- package/.torusguard/skills/torusguard-status/SKILL.md +42 -0
- package/.torusguard/skills/torusguard-verify/SKILL.md +55 -0
- package/.torusguard/skills/torusguard-web-validate/SKILL.md +64 -0
- package/.torusguard/templates/audit-report.template.md +54 -0
- package/.torusguard/templates/authorization.template.md +34 -0
- package/.torusguard/templates/finding-card.template.md +32 -0
- package/.torusguard/templates/remediation-bundle.template.md +35 -0
- package/.torusguard/workflows/apply.md +95 -0
- package/.torusguard/workflows/audit.md +93 -0
- package/.torusguard/workflows/authorize.md +95 -0
- package/.torusguard/workflows/exploit-check.md +97 -0
- package/.torusguard/workflows/harden.md +93 -0
- package/.torusguard/workflows/init.md +95 -0
- package/.torusguard/workflows/recheck.md +95 -0
- package/.torusguard/workflows/report.md +95 -0
- package/.torusguard/workflows/status.md +95 -0
- package/.torusguard/workflows/verify.md +95 -0
- package/.torusguard/workflows/web-validate.md +95 -0
- package/LICENSE +21 -0
- package/README.md +319 -0
- package/bin/torusguard.js +110 -0
- package/install.py +98 -0
- package/package.json +48 -0
- package/skills/torusguard/SKILL.md +41 -0
- package/skills/torusguard/__pycache__/bootstrap.cpython-311.pyc +0 -0
- package/skills/torusguard/bootstrap.py +256 -0
- package/skills/torusguard/payload/.manifest.json +95 -0
- package/skills/torusguard/payload/ARCHITECTURE.md +168 -0
- package/skills/torusguard/payload/TORUSGUARD.md +145 -0
- package/skills/torusguard/payload/agents/auditor.md +41 -0
- package/skills/torusguard/payload/agents/profiler.md +49 -0
- package/skills/torusguard/payload/agents/remediator.md +41 -0
- package/skills/torusguard/payload/agents/reviewer.md +39 -0
- package/skills/torusguard/payload/agents/validator.md +46 -0
- package/skills/torusguard/payload/config/scope.json +24 -0
- package/skills/torusguard/payload/config/slash-commands.json +102 -0
- package/skills/torusguard/payload/config/torusguard.json +30 -0
- package/skills/torusguard/payload/references/django-security.md +43 -0
- package/skills/torusguard/payload/references/drf-security.md +20 -0
- package/skills/torusguard/payload/references/express-security.md +103 -0
- package/skills/torusguard/payload/references/fastapi-security.md +20 -0
- package/skills/torusguard/payload/references/firebase-security.md +78 -0
- package/skills/torusguard/payload/references/flask-security.md +20 -0
- package/skills/torusguard/payload/references/nextjs-security.md +96 -0
- package/skills/torusguard/payload/references/react-vite-security.md +97 -0
- package/skills/torusguard/payload/references/sqlalchemy-security.md +16 -0
- package/skills/torusguard/payload/references/supabase-security.md +84 -0
- package/skills/torusguard/payload/rules/README.md +62 -0
- package/skills/torusguard/payload/rules/TORUSGUARD.md +145 -0
- package/skills/torusguard/payload/rules/active/.gitkeep +0 -0
- package/skills/torusguard/payload/rules/active/TG-DIFF-001.md +20 -0
- package/skills/torusguard/payload/rules/active/TG-DIFF-002.md +20 -0
- package/skills/torusguard/payload/rules/active/TG-DIFF-003.md +19 -0
- package/skills/torusguard/payload/schemas/authorization.schema.json +81 -0
- package/skills/torusguard/payload/schemas/confidence.schema.json +72 -0
- package/skills/torusguard/payload/schemas/evidence.schema.json +66 -0
- package/skills/torusguard/payload/schemas/finding.schema.json +164 -0
- package/skills/torusguard/payload/schemas/provenance.schema.json +46 -0
- package/skills/torusguard/payload/schemas/remediation.schema.json +59 -0
- package/skills/torusguard/payload/schemas/retest.schema.json +53 -0
- package/skills/torusguard/payload/schemas/runtime-evidence.schema.json +72 -0
- package/skills/torusguard/payload/scripts/diff_guard.py +171 -0
- package/skills/torusguard/payload/scripts/finding_scorer.py +86 -0
- package/skills/torusguard/payload/scripts/manifest_builder.py +130 -0
- package/skills/torusguard/payload/scripts/monorepo_detector.py +164 -0
- package/skills/torusguard/payload/scripts/run_manager.py +89 -0
- package/skills/torusguard/payload/scripts/safety_gate.py +64 -0
- package/skills/torusguard/payload/scripts/sarif_exporter.py +116 -0
- package/skills/torusguard/payload/scripts/stack_detect.py +152 -0
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +37 -0
- package/skills/torusguard/payload/skills/torusguard/bootstrap.py +158 -0
- package/skills/torusguard/payload/skills/torusguard/references/auth-and-sessions.md +56 -0
- package/skills/torusguard/payload/skills/torusguard/references/business-logic-and-abuse.md +23 -0
- package/skills/torusguard/payload/skills/torusguard/references/cache-and-sensitive-responses.md +10 -0
- package/skills/torusguard/payload/skills/torusguard/references/client-code-exposure.md +55 -0
- package/skills/torusguard/payload/skills/torusguard/references/csrf-and-cross-origin.md +11 -0
- package/skills/torusguard/payload/skills/torusguard/references/dependency-and-supply-chain.md +22 -0
- package/skills/torusguard/payload/skills/torusguard/references/django-security.md +43 -0
- package/skills/torusguard/payload/skills/torusguard/references/drf-security.md +20 -0
- package/skills/torusguard/payload/skills/torusguard/references/fastapi-security.md +20 -0
- package/skills/torusguard/payload/skills/torusguard/references/flask-security.md +20 -0
- package/skills/torusguard/payload/skills/torusguard/references/frontend-no-db.md +53 -0
- package/skills/torusguard/payload/skills/torusguard/references/graphql-security.md +12 -0
- package/skills/torusguard/payload/skills/torusguard/references/input-and-injection.md +51 -0
- package/skills/torusguard/payload/skills/torusguard/references/mass-assignment-and-property-auth.md +22 -0
- package/skills/torusguard/payload/skills/torusguard/references/platform-hardening.md +56 -0
- package/skills/torusguard/payload/skills/torusguard/references/python-dependencies.md +16 -0
- package/skills/torusguard/payload/skills/torusguard/references/python-security-overview.md +12 -0
- package/skills/torusguard/payload/skills/torusguard/references/rate-limit-and-abuse.md +57 -0
- package/skills/torusguard/payload/skills/torusguard/references/secrets-and-config.md +64 -0
- package/skills/torusguard/payload/skills/torusguard/references/sqlalchemy-security.md +16 -0
- package/skills/torusguard/payload/skills/torusguard/references/ssrf-and-outbound-requests.md +46 -0
- package/skills/torusguard/payload/skills/torusguard/references/webhook-security.md +15 -0
- package/skills/torusguard/payload/skills/torusguard/references/websocket-security.md +12 -0
- package/skills/torusguard/payload/skills/torusguard-apply/SKILL.md +46 -0
- package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +70 -0
- package/skills/torusguard/payload/skills/torusguard-authorize/SKILL.md +47 -0
- package/skills/torusguard/payload/skills/torusguard-exploit-check/SKILL.md +64 -0
- package/skills/torusguard/payload/skills/torusguard-full/SKILL.md +70 -0
- package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +63 -0
- package/skills/torusguard/payload/skills/torusguard-init/SKILL.md +52 -0
- package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +53 -0
- package/skills/torusguard/payload/skills/torusguard-report/SKILL.md +54 -0
- package/skills/torusguard/payload/skills/torusguard-status/SKILL.md +42 -0
- package/skills/torusguard/payload/skills/torusguard-verify/SKILL.md +55 -0
- package/skills/torusguard/payload/skills/torusguard-web-validate/SKILL.md +64 -0
- package/skills/torusguard/payload/templates/audit-report.template.md +54 -0
- package/skills/torusguard/payload/templates/authorization.template.md +34 -0
- package/skills/torusguard/payload/templates/finding-card.template.md +32 -0
- package/skills/torusguard/payload/templates/remediation-bundle.template.md +35 -0
- package/skills/torusguard/payload/workflows/apply.md +95 -0
- package/skills/torusguard/payload/workflows/audit.md +93 -0
- package/skills/torusguard/payload/workflows/authorize.md +95 -0
- package/skills/torusguard/payload/workflows/exploit-check.md +97 -0
- package/skills/torusguard/payload/workflows/harden.md +93 -0
- package/skills/torusguard/payload/workflows/init.md +95 -0
- package/skills/torusguard/payload/workflows/recheck.md +95 -0
- package/skills/torusguard/payload/workflows/report.md +95 -0
- package/skills/torusguard/payload/workflows/status.md +95 -0
- package/skills/torusguard/payload/workflows/verify.md +95 -0
- package/skills/torusguard/payload/workflows/web-validate.md +95 -0
- package/skills/torusguard/references/auth-and-sessions.md +56 -0
- package/skills/torusguard/references/business-logic-and-abuse.md +23 -0
- package/skills/torusguard/references/cache-and-sensitive-responses.md +10 -0
- package/skills/torusguard/references/client-code-exposure.md +55 -0
- package/skills/torusguard/references/csrf-and-cross-origin.md +11 -0
- package/skills/torusguard/references/dependency-and-supply-chain.md +22 -0
- package/skills/torusguard/references/django-security.md +43 -0
- package/skills/torusguard/references/drf-security.md +20 -0
- package/skills/torusguard/references/fastapi-security.md +20 -0
- package/skills/torusguard/references/flask-security.md +20 -0
- package/skills/torusguard/references/frontend-no-db.md +53 -0
- package/skills/torusguard/references/graphql-security.md +12 -0
- package/skills/torusguard/references/input-and-injection.md +51 -0
- package/skills/torusguard/references/mass-assignment-and-property-auth.md +22 -0
- package/skills/torusguard/references/platform-hardening.md +56 -0
- package/skills/torusguard/references/python-dependencies.md +16 -0
- package/skills/torusguard/references/python-security-overview.md +12 -0
- package/skills/torusguard/references/rate-limit-and-abuse.md +57 -0
- package/skills/torusguard/references/secrets-and-config.md +64 -0
- package/skills/torusguard/references/sqlalchemy-security.md +16 -0
- package/skills/torusguard/references/ssrf-and-outbound-requests.md +46 -0
- package/skills/torusguard/references/webhook-security.md +15 -0
- package/skills/torusguard/references/websocket-security.md +12 -0
- package/skills/torusguard-apply/SKILL.md +46 -0
- package/skills/torusguard-audit/SKILL.md +70 -0
- package/skills/torusguard-authorize/SKILL.md +47 -0
- package/skills/torusguard-exploit-check/SKILL.md +64 -0
- package/skills/torusguard-full/SKILL.md +70 -0
- package/skills/torusguard-harden/SKILL.md +63 -0
- package/skills/torusguard-init/SKILL.md +52 -0
- package/skills/torusguard-recheck/SKILL.md +53 -0
- package/skills/torusguard-report/SKILL.md +54 -0
- package/skills/torusguard-status/SKILL.md +42 -0
- package/skills/torusguard-verify/SKILL.md +55 -0
- package/skills/torusguard-web-validate/SKILL.md +64 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard Monorepo & Multi-Package Workspace Detector (v0.9.3)
|
|
4
|
+
Discovers and profiles sub-projects across Turborepo, pnpm, npm, and Python workspaces.
|
|
5
|
+
Pure Python 3.10+ standard library (zero external dependencies).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
import json
|
|
11
|
+
import re
|
|
12
|
+
import argparse
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, List, Any, Optional
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def detect_package_info(abs_pkg_dir: Path, root: Path) -> Dict[str, Any]:
|
|
18
|
+
"""Inspects a single directory to detect language and framework."""
|
|
19
|
+
rel_path = str(abs_pkg_dir.relative_to(root)).replace('\\', '/')
|
|
20
|
+
name = abs_pkg_dir.name
|
|
21
|
+
language = "unknown"
|
|
22
|
+
framework = "generic"
|
|
23
|
+
|
|
24
|
+
pkg_dir = abs_pkg_dir
|
|
25
|
+
|
|
26
|
+
# Check typescript / javascript
|
|
27
|
+
package_json = pkg_dir / "package.json"
|
|
28
|
+
if package_json.is_file() or list(pkg_dir.glob("*.ts")) or list(pkg_dir.glob("*.js")):
|
|
29
|
+
language = "typescript"
|
|
30
|
+
if package_json.is_file():
|
|
31
|
+
try:
|
|
32
|
+
with open(package_json, "r", encoding="utf-8") as f:
|
|
33
|
+
pj = json.load(f)
|
|
34
|
+
name = pj.get("name", name)
|
|
35
|
+
deps = {**pj.get("dependencies", {}), **pj.get("devDependencies", {})}
|
|
36
|
+
if "next" in deps:
|
|
37
|
+
framework = "nextjs"
|
|
38
|
+
elif "express" in deps:
|
|
39
|
+
framework = "express"
|
|
40
|
+
elif "react" in deps:
|
|
41
|
+
framework = "react"
|
|
42
|
+
elif "vue" in deps or "nuxt" in deps:
|
|
43
|
+
framework = "vue"
|
|
44
|
+
except Exception:
|
|
45
|
+
pass
|
|
46
|
+
elif list(pkg_dir.glob("*next*")) or "next" in pkg_dir.name:
|
|
47
|
+
framework = "nextjs"
|
|
48
|
+
|
|
49
|
+
# Check python
|
|
50
|
+
pyproject = pkg_dir / "pyproject.toml"
|
|
51
|
+
reqs = pkg_dir / "requirements.txt"
|
|
52
|
+
if pyproject.is_file() or reqs.is_file() or list(pkg_dir.glob("*.py")):
|
|
53
|
+
if language == "unknown":
|
|
54
|
+
language = "python"
|
|
55
|
+
content = ""
|
|
56
|
+
if pyproject.is_file():
|
|
57
|
+
content += pyproject.read_text(encoding="utf-8", errors="replace").lower()
|
|
58
|
+
if reqs.is_file():
|
|
59
|
+
content += reqs.read_text(encoding="utf-8", errors="replace").lower()
|
|
60
|
+
for pyf in pkg_dir.glob("*.py"):
|
|
61
|
+
content += pyf.read_text(encoding="utf-8", errors="replace").lower()
|
|
62
|
+
|
|
63
|
+
if "fastapi" in content or "fastapi" in pkg_dir.name:
|
|
64
|
+
framework = "fastapi"
|
|
65
|
+
elif "django" in content or "django" in pkg_dir.name:
|
|
66
|
+
framework = "django"
|
|
67
|
+
elif "flask" in content or "flask" in pkg_dir.name:
|
|
68
|
+
framework = "flask"
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
"name": name,
|
|
72
|
+
"path": rel_path,
|
|
73
|
+
"language": language,
|
|
74
|
+
"framework": framework
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def scan_workspace(root_dir: str = ".") -> Dict[str, Any]:
|
|
79
|
+
"""Scans root directory for monorepo configuration and sub-packages."""
|
|
80
|
+
root = Path(root_dir).resolve()
|
|
81
|
+
monorepo_type = "single-project"
|
|
82
|
+
sub_packages: List[Dict[str, Any]] = []
|
|
83
|
+
|
|
84
|
+
# 1. Turborepo
|
|
85
|
+
if (root / "turbo.json").is_file():
|
|
86
|
+
monorepo_type = "turborepo"
|
|
87
|
+
|
|
88
|
+
# 2. pnpm workspace
|
|
89
|
+
pnpm_ws = root / "pnpm-workspace.yaml"
|
|
90
|
+
if pnpm_ws.is_file():
|
|
91
|
+
monorepo_type = "pnpm-workspace"
|
|
92
|
+
|
|
93
|
+
# 3. npm / yarn workspaces
|
|
94
|
+
root_pj = root / "package.json"
|
|
95
|
+
if root_pj.is_file():
|
|
96
|
+
try:
|
|
97
|
+
with open(root_pj, "r", encoding="utf-8") as f:
|
|
98
|
+
data = json.load(f)
|
|
99
|
+
if "workspaces" in data:
|
|
100
|
+
monorepo_type = "npm/yarn-workspaces"
|
|
101
|
+
except Exception:
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
# Scan common monorepo container directories and direct project subfolders
|
|
105
|
+
candidate_folders = ["apps", "packages", "services", "libs", "modules"]
|
|
106
|
+
found_dirs = []
|
|
107
|
+
|
|
108
|
+
for cf in candidate_folders:
|
|
109
|
+
container = root / cf
|
|
110
|
+
if container.is_dir():
|
|
111
|
+
for child in container.iterdir():
|
|
112
|
+
if child.is_dir() and not child.name.startswith(('.', '_')):
|
|
113
|
+
if any((child / m).exists() for m in ["package.json", "pyproject.toml", "requirements.txt", "setup.py", "Cargo.toml", "main.py"]):
|
|
114
|
+
found_dirs.append(child)
|
|
115
|
+
|
|
116
|
+
# Also scan direct subdirectories if not already captured
|
|
117
|
+
for child in root.iterdir():
|
|
118
|
+
if child.is_dir() and not child.name.startswith(('.', '_')) and child.name not in candidate_folders:
|
|
119
|
+
if any((child / m).exists() for m in ["package.json", "pyproject.toml", "requirements.txt", "setup.py", "Cargo.toml", "main.py", "actions.ts"]):
|
|
120
|
+
if child not in found_dirs:
|
|
121
|
+
found_dirs.append(child)
|
|
122
|
+
|
|
123
|
+
if found_dirs:
|
|
124
|
+
if monorepo_type == "single-project":
|
|
125
|
+
monorepo_type = "multi-package-directory"
|
|
126
|
+
for d in found_dirs:
|
|
127
|
+
sub_packages.append(detect_package_info(d, root))
|
|
128
|
+
|
|
129
|
+
# If no monorepo sub-packages found, treat root as primary
|
|
130
|
+
if not sub_packages:
|
|
131
|
+
sub_packages.append(detect_package_info(root, root))
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
"root": str(root).replace('\\', '/'),
|
|
135
|
+
"monorepo_type": monorepo_type,
|
|
136
|
+
"is_monorepo": monorepo_type != "single-project",
|
|
137
|
+
"package_count": len(sub_packages),
|
|
138
|
+
"packages": sub_packages
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def main():
|
|
143
|
+
parser = argparse.ArgumentParser(description="TorusGuard Monorepo & Multi-Package Detector")
|
|
144
|
+
parser.add_argument("--scan", default=".", help="Root directory to scan (default: .)")
|
|
145
|
+
parser.add_argument("--write", action="store_true", help="Write to .torusguard/config/workspaces.json")
|
|
146
|
+
parser.add_argument("--json", action="store_true", help="Output JSON to stdout")
|
|
147
|
+
args = parser.parse_args()
|
|
148
|
+
|
|
149
|
+
res = scan_workspace(args.scan)
|
|
150
|
+
|
|
151
|
+
if args.write:
|
|
152
|
+
config_dir = Path(args.scan) / ".torusguard" / "config"
|
|
153
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
154
|
+
out_file = config_dir / "workspaces.json"
|
|
155
|
+
with open(out_file, "w", encoding="utf-8") as f:
|
|
156
|
+
json.dump(res, f, indent=2)
|
|
157
|
+
print(f"[SUCCESS] Wrote workspace registry to {out_file}")
|
|
158
|
+
|
|
159
|
+
if args.json or not args.write:
|
|
160
|
+
print(json.dumps(res, indent=2))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
if __name__ == "__main__":
|
|
164
|
+
main()
|
|
@@ -0,0 +1,89 @@
|
|
|
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()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard Runtime Safety Gate Evaluator
|
|
4
|
+
Evaluates prospective HTTP/browser validation probes against non-destruction policies.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import json
|
|
9
|
+
import argparse
|
|
10
|
+
from typing import Dict, Any, Tuple
|
|
11
|
+
|
|
12
|
+
def evaluate_safety_gate(method: str, path: str, body: str = "") -> Tuple[str, str]:
|
|
13
|
+
"""
|
|
14
|
+
Returns (decision, rationale)
|
|
15
|
+
Decisions:
|
|
16
|
+
- Auto-Allowed
|
|
17
|
+
- Approval Required
|
|
18
|
+
- Manual Only (Blocked)
|
|
19
|
+
"""
|
|
20
|
+
method_upper = method.upper()
|
|
21
|
+
|
|
22
|
+
# Block destructive verbs
|
|
23
|
+
if method_upper in ("DELETE", "DROP"):
|
|
24
|
+
return "Manual Only", f"Method '{method_upper}' is destructive and strictly blocked from automated runtime validation."
|
|
25
|
+
|
|
26
|
+
# Block sensitive administrative paths
|
|
27
|
+
destructive_keywords = ["/admin/delete", "/shutdown", "/drop-database", "/purge", "/reset-system"]
|
|
28
|
+
for kw in destructive_keywords:
|
|
29
|
+
if kw in path.lower():
|
|
30
|
+
return "Manual Only", f"Path '{path}' targets destructive administrative endpoint '{kw}'."
|
|
31
|
+
|
|
32
|
+
# Safe read methods
|
|
33
|
+
if method_upper in ("GET", "HEAD", "OPTIONS"):
|
|
34
|
+
return "Auto-Allowed", f"Read-only method '{method_upper}' with non-destructive path."
|
|
35
|
+
|
|
36
|
+
# State-changing methods (POST, PUT, PATCH)
|
|
37
|
+
if method_upper in ("POST", "PUT", "PATCH"):
|
|
38
|
+
# Check if safe canary marker exists
|
|
39
|
+
if "tg-canary" in body.lower() or "torusguard" in body.lower():
|
|
40
|
+
return "Approval Required", f"State-changing method '{method_upper}' contains benign TorusGuard test marker; requires user approval."
|
|
41
|
+
else:
|
|
42
|
+
return "Approval Required", f"State-changing method '{method_upper}' requires operator approval before execution."
|
|
43
|
+
|
|
44
|
+
return "Approval Required", f"Unknown probe profile for {method_upper} {path}."
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def main():
|
|
48
|
+
parser = argparse.ArgumentParser(description="TorusGuard Safety Gate Evaluator")
|
|
49
|
+
parser.add_argument("--method", "-m", default="GET", help="HTTP Method")
|
|
50
|
+
parser.add_argument("--path", "-p", default="/api/test", help="Endpoint path")
|
|
51
|
+
parser.add_argument("--body", "-b", default="", help="Request payload body")
|
|
52
|
+
parser.add_argument("--json", action="store_true", help="Output JSON")
|
|
53
|
+
args = parser.parse_args()
|
|
54
|
+
|
|
55
|
+
decision, rationale = evaluate_safety_gate(args.method, args.path, args.body)
|
|
56
|
+
|
|
57
|
+
if args.json:
|
|
58
|
+
print(json.dumps({"decision": decision, "rationale": rationale}, indent=2))
|
|
59
|
+
else:
|
|
60
|
+
print(f"Safety Decision: {decision}")
|
|
61
|
+
print(f"Rationale: {rationale}")
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
main()
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard OASIS SARIF v2.1.0 Exporter
|
|
4
|
+
Converts normalized TorusGuard findings into standard SARIF v2.1.0 format with
|
|
5
|
+
GitHub Code Scanning multi-analysis category separation and partialFingerprints deduplication.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
import hashlib
|
|
11
|
+
import argparse
|
|
12
|
+
from typing import List, Dict, Any
|
|
13
|
+
|
|
14
|
+
def generate_sarif(findings: List[Dict[str, Any]], run_id: str = "default", category: str = "torusguard/static") -> Dict[str, Any]:
|
|
15
|
+
rules_map: Dict[str, Dict[str, Any]] = {}
|
|
16
|
+
results: List[Dict[str, Any]] = []
|
|
17
|
+
|
|
18
|
+
for f in findings:
|
|
19
|
+
rule_id = f.get("rule_id", "TG-GEN-001")
|
|
20
|
+
if rule_id not in rules_map:
|
|
21
|
+
rules_map[rule_id] = {
|
|
22
|
+
"id": rule_id,
|
|
23
|
+
"name": f.get("title", rule_id),
|
|
24
|
+
"shortDescription": {"text": f.get("title", rule_id)},
|
|
25
|
+
"fullDescription": {"text": f.get("description", f.get("title", rule_id))},
|
|
26
|
+
"defaultConfiguration": {
|
|
27
|
+
"level": "error" if f.get("severity") in ("Critical", "High") else "warning"
|
|
28
|
+
},
|
|
29
|
+
"properties": {
|
|
30
|
+
"tags": ["security", "torusguard", f.get("category", "general")]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
target = f.get("target", {})
|
|
35
|
+
file_path = target.get("file_path", "unknown")
|
|
36
|
+
line = target.get("start_line", 1)
|
|
37
|
+
|
|
38
|
+
# Generate deduplication fingerprint
|
|
39
|
+
seed = f"{rule_id}:{file_path}:{line}"
|
|
40
|
+
line_hash = hashlib.sha256(seed.encode("utf-8")).hexdigest()[:16]
|
|
41
|
+
|
|
42
|
+
result: Dict[str, Any] = {
|
|
43
|
+
"ruleId": rule_id,
|
|
44
|
+
"message": {"text": f.get("title", "TorusGuard Security Finding")},
|
|
45
|
+
"level": "error" if f.get("severity") in ("Critical", "High") else "warning",
|
|
46
|
+
"locations": [
|
|
47
|
+
{
|
|
48
|
+
"physicalLocation": {
|
|
49
|
+
"artifactLocation": {
|
|
50
|
+
"uri": file_path,
|
|
51
|
+
"uriBaseId": "%SRCROOT%"
|
|
52
|
+
},
|
|
53
|
+
"region": {
|
|
54
|
+
"startLine": line,
|
|
55
|
+
"startColumn": 1
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"partialFingerprints": {
|
|
61
|
+
"primaryLocationLineHash": line_hash
|
|
62
|
+
},
|
|
63
|
+
"properties": {
|
|
64
|
+
"confidence": f.get("confidence", 70),
|
|
65
|
+
"status": f.get("status", "Confirmed"),
|
|
66
|
+
"finding_id": f.get("finding_id", "TG-FIND-UNKNOWN")
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
results.append(result)
|
|
70
|
+
|
|
71
|
+
sarif = {
|
|
72
|
+
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
|
73
|
+
"version": "2.1.0",
|
|
74
|
+
"runs": [
|
|
75
|
+
{
|
|
76
|
+
"tool": {
|
|
77
|
+
"driver": {
|
|
78
|
+
"name": "TorusGuard",
|
|
79
|
+
"semanticVersion": "0.8.0",
|
|
80
|
+
"informationUri": "https://github.com/githubmofo/TorusGuard",
|
|
81
|
+
"rules": list(rules_map.values())
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"automationDetails": {
|
|
85
|
+
"id": f"{category}/{run_id}"
|
|
86
|
+
},
|
|
87
|
+
"results": results
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
return sarif
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def main():
|
|
95
|
+
parser = argparse.ArgumentParser(description="TorusGuard SARIF v2.1.0 Exporter")
|
|
96
|
+
parser.add_argument("--input", "-i", help="Path to findings JSON file")
|
|
97
|
+
parser.add_argument("--output", "-o", help="Output path for sarif.json")
|
|
98
|
+
parser.add_argument("--run-id", default="run-default", help="Unique execution Run ID")
|
|
99
|
+
args = parser.parse_args()
|
|
100
|
+
|
|
101
|
+
findings = []
|
|
102
|
+
if args.input:
|
|
103
|
+
with open(args.input, "r", encoding="utf-8") as f:
|
|
104
|
+
findings = json.load(f)
|
|
105
|
+
|
|
106
|
+
sarif = generate_sarif(findings, run_id=args.run_id)
|
|
107
|
+
|
|
108
|
+
if args.output:
|
|
109
|
+
with open(args.output, "w", encoding="utf-8") as f:
|
|
110
|
+
json.dump(sarif, f, indent=2)
|
|
111
|
+
print(f"SARIF log written to: {args.output}")
|
|
112
|
+
else:
|
|
113
|
+
print(json.dumps(sarif, indent=2))
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
main()
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
TorusGuard Stack Detector Utility
|
|
4
|
+
Inspects project directory to detect programming language, frameworks, ORM/data layer,
|
|
5
|
+
and dependency manifests. Outputs canonical stack block and structured JSON.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
import argparse
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, Any, List
|
|
13
|
+
|
|
14
|
+
def detect_stack(project_root: Path) -> Dict[str, Any]:
|
|
15
|
+
profile = {
|
|
16
|
+
"language": "Unknown",
|
|
17
|
+
"framework": "None",
|
|
18
|
+
"data_layer": "None",
|
|
19
|
+
"dependency_files": [],
|
|
20
|
+
"detection_evidence": [],
|
|
21
|
+
"confidence": "Needs Review",
|
|
22
|
+
"recommended_rules": [
|
|
23
|
+
"TG-SEC-*",
|
|
24
|
+
"TG-INPUT-*",
|
|
25
|
+
"TG-AUTH-*"
|
|
26
|
+
],
|
|
27
|
+
"recommended_references": []
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# 1. Inspect dependency manifests
|
|
31
|
+
dep_candidates = ["pyproject.toml", "requirements.txt", "Pipfile", "package.json", "package-lock.json", "pnpm-lock.yaml"]
|
|
32
|
+
for dc in dep_candidates:
|
|
33
|
+
if (project_root / dc).is_file():
|
|
34
|
+
profile["dependency_files"].append(dc)
|
|
35
|
+
|
|
36
|
+
# 2. Check Python ecosystem
|
|
37
|
+
manage_py = project_root / "manage.py"
|
|
38
|
+
settings_py = list(project_root.glob("**/settings.py"))
|
|
39
|
+
|
|
40
|
+
if manage_py.is_file() or settings_py:
|
|
41
|
+
profile["language"] = "Python"
|
|
42
|
+
profile["framework"] = "Django"
|
|
43
|
+
profile["data_layer"] = "Django ORM"
|
|
44
|
+
profile["confidence"] = "Confirmed"
|
|
45
|
+
profile["detection_evidence"].append({
|
|
46
|
+
"file": "manage.py" if manage_py.is_file() else str(settings_py[0].relative_to(project_root)),
|
|
47
|
+
"indicator": "Django management or settings configuration"
|
|
48
|
+
})
|
|
49
|
+
profile["recommended_rules"].extend(["TG-DB-004", "TG-RATE-001", "TG-PLATFORM-*"])
|
|
50
|
+
profile["recommended_references"].extend(["django-security.md", "python-security-overview.md"])
|
|
51
|
+
|
|
52
|
+
# Check for DRF
|
|
53
|
+
for py_file in project_root.glob("**/*.py"):
|
|
54
|
+
try:
|
|
55
|
+
content = py_file.read_text(encoding="utf-8", errors="ignore")
|
|
56
|
+
if "rest_framework" in content:
|
|
57
|
+
profile["framework"] = "Django / DRF"
|
|
58
|
+
profile["recommended_references"].append("drf-security.md")
|
|
59
|
+
break
|
|
60
|
+
except Exception:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
# Check for FastAPI / Flask if not Django
|
|
64
|
+
if profile["framework"] == "None":
|
|
65
|
+
for py_file in list(project_root.glob("*.py")) + list(project_root.glob("app/**/*.py")) + list(project_root.glob("src/**/*.py")):
|
|
66
|
+
try:
|
|
67
|
+
content = py_file.read_text(encoding="utf-8", errors="ignore")
|
|
68
|
+
if "FastAPI(" in content or "from fastapi" in content:
|
|
69
|
+
profile["language"] = "Python"
|
|
70
|
+
profile["framework"] = "FastAPI"
|
|
71
|
+
profile["confidence"] = "Confirmed"
|
|
72
|
+
profile["detection_evidence"].append({
|
|
73
|
+
"file": str(py_file.relative_to(project_root)),
|
|
74
|
+
"indicator": "FastAPI application instantiation"
|
|
75
|
+
})
|
|
76
|
+
profile["recommended_references"].append("fastapi-security.md")
|
|
77
|
+
elif "Flask(__name__)" in content or "from flask" in content:
|
|
78
|
+
profile["language"] = "Python"
|
|
79
|
+
profile["framework"] = "Flask"
|
|
80
|
+
profile["confidence"] = "Confirmed"
|
|
81
|
+
profile["detection_evidence"].append({
|
|
82
|
+
"file": str(py_file.relative_to(project_root)),
|
|
83
|
+
"indicator": "Flask application instantiation"
|
|
84
|
+
})
|
|
85
|
+
profile["recommended_references"].append("flask-security.md")
|
|
86
|
+
|
|
87
|
+
if "sqlalchemy" in content:
|
|
88
|
+
profile["data_layer"] = "SQLAlchemy"
|
|
89
|
+
profile["recommended_references"].append("sqlalchemy-security.md")
|
|
90
|
+
except Exception:
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
# 3. Check JavaScript / TypeScript ecosystem
|
|
94
|
+
pkg_json_path = project_root / "package.json"
|
|
95
|
+
if pkg_json_path.is_file():
|
|
96
|
+
profile["language"] = "TypeScript" if list(project_root.glob("**/*.ts*")) else "JavaScript"
|
|
97
|
+
try:
|
|
98
|
+
with open(pkg_json_path, "r", encoding="utf-8") as f:
|
|
99
|
+
pkg = json.load(f)
|
|
100
|
+
deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
|
|
101
|
+
|
|
102
|
+
if "next" in deps:
|
|
103
|
+
profile["framework"] = "Next.js"
|
|
104
|
+
profile["confidence"] = "Confirmed"
|
|
105
|
+
profile["detection_evidence"].append({"file": "package.json", "indicator": "next dependency"})
|
|
106
|
+
profile["recommended_references"].append("nextjs-security.md")
|
|
107
|
+
profile["recommended_rules"].extend(["TG-CLIENT-*", "TG-PLATFORM-001"])
|
|
108
|
+
elif "express" in deps:
|
|
109
|
+
profile["framework"] = "Express"
|
|
110
|
+
profile["confidence"] = "Confirmed"
|
|
111
|
+
profile["detection_evidence"].append({"file": "package.json", "indicator": "express dependency"})
|
|
112
|
+
profile["recommended_references"].append("express-security.md")
|
|
113
|
+
elif "react" in deps:
|
|
114
|
+
profile["framework"] = "React / Vite"
|
|
115
|
+
profile["confidence"] = "Confirmed"
|
|
116
|
+
profile["detection_evidence"].append({"file": "package.json", "indicator": "react dependency"})
|
|
117
|
+
profile["recommended_references"].append("react-vite-security.md")
|
|
118
|
+
|
|
119
|
+
if "@supabase/supabase-js" in deps:
|
|
120
|
+
profile["data_layer"] = "Supabase"
|
|
121
|
+
profile["recommended_references"].append("supabase-security.md")
|
|
122
|
+
elif "firebase" in deps or "firebase-admin" in deps:
|
|
123
|
+
profile["data_layer"] = "Firebase"
|
|
124
|
+
profile["recommended_references"].append("firebase-security.md")
|
|
125
|
+
except Exception:
|
|
126
|
+
pass
|
|
127
|
+
|
|
128
|
+
return profile
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def main():
|
|
132
|
+
parser = argparse.ArgumentParser(description="TorusGuard Stack Detector")
|
|
133
|
+
parser.add_argument("path", nargs="?", default=".", help="Target project root directory")
|
|
134
|
+
parser.add_argument("--json", action="store_true", help="Output raw JSON")
|
|
135
|
+
args = parser.parse_args()
|
|
136
|
+
|
|
137
|
+
project_root = Path(args.path).resolve()
|
|
138
|
+
profile = detect_stack(project_root)
|
|
139
|
+
|
|
140
|
+
if args.json:
|
|
141
|
+
print(json.dumps(profile, indent=2))
|
|
142
|
+
else:
|
|
143
|
+
evidence = profile["detection_evidence"][0]["file"] if profile["detection_evidence"] else "heuristic"
|
|
144
|
+
print(f"## Detected Stack")
|
|
145
|
+
print(f"- Language: {profile['language']}")
|
|
146
|
+
print(f"- Framework: {profile['framework']}")
|
|
147
|
+
print(f"- Data layer: {profile['data_layer']}")
|
|
148
|
+
print(f"- Dependency files: {', '.join(profile['dependency_files']) if profile['dependency_files'] else 'None'}")
|
|
149
|
+
print(f"- Detection confidence: {profile['confidence']} ({evidence})")
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
main()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: torusguard
|
|
3
|
+
description: Security guardrails, governed remediation, and authorized runtime validation for AI-built web applications across Python and TypeScript.
|
|
4
|
+
version: 0.9.2
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# TorusGuard Master Router
|
|
8
|
+
|
|
9
|
+
**Principle:** If the browser receives it, users can inspect it. Keep secrets, direct database access, and authorization on trusted server-side code.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚡ Workspace Bootstrap Check
|
|
14
|
+
1. **If `.torusguard/` exists:** Load matching specialist skill on demand per command.
|
|
15
|
+
2. **If `.torusguard/` is missing:** Run `python skills/torusguard/bootstrap.py --target .` or `/torusguard init`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Specialist Skill Routing (Lazy Loading)
|
|
20
|
+
Load **only** the designated sub-skill when a slash command is executed to maintain strict 1,000–1,500 token budget:
|
|
21
|
+
|
|
22
|
+
| Command | Specialist Skill | Agent |
|
|
23
|
+
| :--- | :--- | :--- |
|
|
24
|
+
| `/torusguard init` | `skills/torusguard-init/SKILL.md` | `profiler` |
|
|
25
|
+
| `/torusguard authorize` | `skills/torusguard-authorize/SKILL.md` | `reviewer` |
|
|
26
|
+
| `/torusguard audit` | `skills/torusguard-audit/SKILL.md` | `auditor` |
|
|
27
|
+
| `/torusguard verify` | `skills/torusguard-verify/SKILL.md` | `validator` |
|
|
28
|
+
| `/torusguard web-validate` | `skills/torusguard-web-validate/SKILL.md` | `validator` |
|
|
29
|
+
| `/torusguard exploit-check` | `skills/torusguard-exploit-check/SKILL.md` | `validator` |
|
|
30
|
+
| `/torusguard harden` | `skills/torusguard-harden/SKILL.md` | `remediator` |
|
|
31
|
+
| `/torusguard apply` | `skills/torusguard-apply/SKILL.md` | `remediator` |
|
|
32
|
+
| `/torusguard recheck` | `skills/torusguard-recheck/SKILL.md` | `reviewer` |
|
|
33
|
+
| `/torusguard report` | `skills/torusguard-report/SKILL.md` | `reviewer` |
|
|
34
|
+
| `/torusguard status` | `skills/torusguard-status/SKILL.md` | `reviewer` |
|
|
35
|
+
| `/torusguard full` | `skills/torusguard-full/SKILL.md` | *All* |
|
|
36
|
+
|
|
37
|
+
*Note: Never load all skills simultaneously. Lazy-load strictly on demand.*
|