torusguard 1.3.6 → 1.4.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 +9 -8
- package/.torusguard/runs/report-latest.html +3529 -364
- package/.torusguard/runs/run-20260918-105940-audit/manifest.json +2 -1
- package/.torusguard/runs/run-20260918-105940-audit/remediation.md +7 -0
- package/.torusguard/runs/run-20260919-145701-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-145701-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-145701-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-145701-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-151729-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-151729-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-151729-audit/manifest.json +13 -0
- package/.torusguard/runs/run-20260919-151729-audit/remediation.md +7 -0
- package/.torusguard/runs/run-20260919-151729-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-152340-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-152340-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-152340-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-152340-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-152345-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-152345-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-152345-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-152345-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260919-153500-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260919-153500-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260919-153500-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260919-153500-audit/summary.md +5 -0
- package/.torusguard/scripts/__pycache__/apply_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/harden_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/manifest_builder.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/recipes_runner.cpython-314.pyc +0 -0
- package/.torusguard/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
- package/.torusguard/scripts/apply_runner.py +101 -8
- package/.torusguard/scripts/audit_runner.py +116 -11
- package/.torusguard/scripts/harden_runner.py +122 -68
- package/.torusguard/scripts/html_reporter.py +1170 -253
- package/.torusguard/scripts/manifest_builder.py +2 -0
- package/.torusguard/scripts/recheck_runner.py +2 -1
- package/.torusguard/scripts/recipes_runner.py +91 -8
- package/.torusguard/scripts/report_sync.py +134 -7
- package/.torusguard/scripts/status_runner.py +267 -0
- package/README.md +108 -80
- package/bin/torusguard.js +190 -20
- package/package.json +6 -2
- package/skills/torusguard/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/skills/torusguard/bootstrap.py +45 -6
- package/skills/torusguard/payload/.manifest.json +29 -14
- package/skills/torusguard/payload/scripts/__pycache__/audit_runner.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/html_reporter.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/report_sync.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/sarif_exporter.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/__pycache__/term_ui.cpython-314.pyc +0 -0
- package/skills/torusguard/payload/scripts/apply_runner.py +101 -8
- package/skills/torusguard/payload/scripts/audit_runner.py +116 -11
- package/skills/torusguard/payload/scripts/harden_runner.py +122 -68
- package/skills/torusguard/payload/scripts/html_reporter.py +1170 -253
- package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
- package/skills/torusguard/payload/scripts/recheck_runner.py +2 -1
- package/skills/torusguard/payload/scripts/recipes_runner.py +91 -8
- package/skills/torusguard/payload/scripts/report_sync.py +134 -7
- package/skills/torusguard/payload/scripts/status_runner.py +267 -0
- package/skills/torusguard/payload/workflows/apply.md +9 -1
- package/skills/torusguard/payload/workflows/audit.md +8 -2
- package/skills/torusguard/payload/workflows/harden.md +6 -1
- package/skills/torusguard/payload/workflows/init.md +7 -1
- package/skills/torusguard/payload/workflows/recipes.md +55 -0
- package/skills/torusguard/payload/workflows/report.md +59 -55
- package/skills/torusguard/payload/workflows/status.md +4 -1
- package/skills/torusguard/payload/workflows/torusguard-apply.md +110 -0
- package/skills/torusguard/payload/workflows/torusguard-audit.md +105 -0
- package/skills/torusguard/payload/workflows/torusguard-authorize.md +96 -0
- package/skills/torusguard/payload/workflows/torusguard-exploit-check.md +98 -0
- package/skills/torusguard/payload/workflows/torusguard-harden.md +104 -0
- package/skills/torusguard/payload/workflows/torusguard-init.md +106 -0
- package/skills/torusguard/payload/workflows/torusguard-recheck.md +101 -0
- package/skills/torusguard/payload/workflows/torusguard-recipes.md +55 -0
- package/skills/torusguard/payload/workflows/torusguard-report.md +105 -0
- package/skills/torusguard/payload/workflows/torusguard-status.md +103 -0
- package/skills/torusguard/payload/workflows/torusguard-verify.md +100 -0
- package/skills/torusguard/payload/workflows/torusguard-web-validate.md +96 -0
- package/skills/torusguard/payload/workflows/torusguard.md +19 -0
package/README.md
CHANGED
|
@@ -9,15 +9,16 @@
|
|
|
9
9
|
<strong>Zero Telemetry · Zero External Python Dependencies · Pure Standard-Library Architecture · 100% Local-First</strong>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
[](https://www.npmjs.com/package/torusguard)
|
|
13
|
+
[](https://github.com/githubmofo/TorusGuard/pkgs/npm/torusguard)
|
|
14
|
+
[](https://github.com/githubmofo/TorusGuard/releases/latest)
|
|
15
|
+
[](harness/runner.py)
|
|
16
16
|
[](security_report.md)
|
|
17
17
|
[](rules/)
|
|
18
18
|
[](.torusguard/scripts/term_ui.py)
|
|
19
19
|
[](LICENSE)
|
|
20
20
|
[-blue.svg?style=flat-square&logo=python&logoColor=white)](https://python.org)
|
|
21
|
+
[](https://go.dev)
|
|
21
22
|
[](https://nodejs.org)
|
|
22
23
|
[](.torusguard/schemas/)
|
|
23
24
|
[](docs/architecture/SECURITY_ARCHITECTURE.md)
|
|
@@ -26,35 +27,8 @@
|
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
In the emblem above, the **central golden keyhole shield** represents unbreakable secret protection, authentication integrity, and tenant isolation. It is enveloped by a continuous, interlocking **torus ring**—symbolizing TorusGuard's closed-loop autonomous security lifecycle:
|
|
32
|
-
|
|
33
|
-
```mermaid
|
|
34
|
-
flowchart LR
|
|
35
|
-
subgraph Torus ["🔄 360° Closed-Loop Torus Lifecycle"]
|
|
36
|
-
direction LR
|
|
37
|
-
Detect["1. Detect (74 AST Rules)"] --> Verify["2. Verify (Evidence & Fingerprints)"]
|
|
38
|
-
Verify --> Harden["3. Harden (Ponytail Protocol)"]
|
|
39
|
-
Harden --> Apply["4. Apply (Human Gate & Snapshots)"]
|
|
40
|
-
Apply --> Recheck["5. Recheck (Differential Closure)"]
|
|
41
|
-
Recheck --> Memory["6. Memory (Golden Fix Recipes)"]
|
|
42
|
-
Memory -.->|Continuous Guardrail| Detect
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
subgraph Shield ["🛡️ Central Golden Keyhole Shield"]
|
|
46
|
-
direction TB
|
|
47
|
-
Inv1["Browser-Code Truth: Zero Client Secrets"]
|
|
48
|
-
Inv2["Tenant Partitioning: Scoped Lookups"]
|
|
49
|
-
Inv3["Zero Bypasses: No verify=False"]
|
|
50
|
-
Inv4["Living Source of Truth: security_report.md"]
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
Torus === Shield
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
> **The Developer Reality:** AI coding assistants (Cursor, Claude Code, Copilot, Windsurf) build software at superhuman speed, but routinely leak private keys into client bundles, drop tenant partition filters, or inject raw user input into LLM system prompts.
|
|
57
|
-
> **TorusGuard forms an unbroken local guardrail around your codebase.** It audits static ASTs, runtime-verifies exploitability with inert canaries, synthesizes minimal surgical diffs adhering to the **Ponytail Protocol** ($\le 35$ additions, $\le 25$ deletions), and eliminates hallucinations by maintaining a verifiable single source of truth in `security_report.md`.
|
|
30
|
+
> **The Developer Reality:** AI coding assistants (Cursor, Claude Code, Copilot, Windsurf, Antigravity) build software at superhuman speed, but routinely leak private keys into client bundles, drop tenant partition filters, or inject raw user input into LLM system prompts.
|
|
31
|
+
> **TorusGuard forms an unbroken local guardrail around your codebase.** It audits static ASTs across 74 rules, runtime-verifies exploitability with inert canaries, synthesizes minimal surgical diffs adhering to the **Ponytail Protocol** ($\le 35$ additions, $\le 25$ deletions), and eliminates hallucinations by maintaining a verifiable single source of truth in `security_report.md`.
|
|
58
32
|
|
|
59
33
|
---
|
|
60
34
|
|
|
@@ -63,18 +37,20 @@ flowchart LR
|
|
|
63
37
|
1. [Developer Overview & Value Proposition](#-developer-overview--value-proposition)
|
|
64
38
|
2. [End-to-End Autonomous Architecture](#-end-to-end-autonomous-architecture)
|
|
65
39
|
3. [Why TorusGuard? (Traditional SAST vs. AI Coding vs. TorusGuard)](#-why-torusguard)
|
|
66
|
-
4. [Installation & Setup Guide (npm & CLI)](#-installation--setup-guide-npm--cli)
|
|
40
|
+
4. [Installation & Setup Guide (npm, Go & CLI)](#-installation--setup-guide-npm-go--cli)
|
|
67
41
|
5. [Quickstart: The 5-Step Core Lifecycle](#-quickstart-the-5-step-core-lifecycle)
|
|
68
42
|
6. [Dual-Strategy Command Matrix (CLI & AI Chat Parity)](#-dual-strategy-command-matrix-cli--ai-chat-parity)
|
|
69
|
-
7. [
|
|
70
|
-
8. [
|
|
71
|
-
9. [
|
|
72
|
-
10. [
|
|
73
|
-
11. [
|
|
74
|
-
12. [
|
|
75
|
-
13. [
|
|
76
|
-
14. [
|
|
77
|
-
15. [
|
|
43
|
+
7. [Polyglot Go Engine & Native Runner](#-polyglot-go-engine--native-runner)
|
|
44
|
+
8. [Package Self-Update Engine (`update`)](#-package-self-update-engine-update)
|
|
45
|
+
9. [74 Canonical Security Rules Catalog (18 Families Across 6 Pillars)](#-74-canonical-security-rules-catalog-18-families-across-6-pillars)
|
|
46
|
+
10. [Ponytail Remediation Protocol & Rollback Safety](#-ponytail-remediation-protocol--rollback-safety)
|
|
47
|
+
11. [Living Security Report Ground Truth (`security_report.md`)](#-living-security-report-ground-truth-security_reportmd)
|
|
48
|
+
12. [Visual HTML Dashboard & SARIF v2.1.0 Export](#-visual-html-dashboard--sarif-v210-export)
|
|
49
|
+
13. [AI Editor Guardrails Auto-Sync](#-ai-editor-guardrails-auto-sync)
|
|
50
|
+
14. [Monorepo Fleet Support & Git Pre-Commit Diff Guard](#-monorepo-fleet-support--git-pre-commit-diff-guard)
|
|
51
|
+
15. [Verification & Test Harness (133/133 Passing Harness Explained)](#-verification--test-harness)
|
|
52
|
+
16. [Security Policy & Responsible Disclosure](#-security-policy--responsible-disclosure)
|
|
53
|
+
17. [License](#-license)
|
|
78
54
|
|
|
79
55
|
---
|
|
80
56
|
|
|
@@ -155,6 +131,7 @@ TorusGuard is designed to be effortless to adopt in any project. There are no co
|
|
|
155
131
|
### 📋 Prerequisites
|
|
156
132
|
- **Node.js:** 18.0.0 or higher
|
|
157
133
|
- **Python:** 3.10 or higher (**Pure standard library** — **zero `pip` dependencies required**)
|
|
134
|
+
- **Go (Optional):** 1.22 or higher (for native Go CLI compilation & Go module workflows)
|
|
158
135
|
|
|
159
136
|
> [!IMPORTANT]
|
|
160
137
|
> **Zero Pip Dependencies Guarantee:** TorusGuard's core Python engine relies strictly on the Python standard library (`pathlib`, `re`, `json`, `difflib`, `shutil`, `sys`, `os`, `argparse`, `hashlib`). You **never** need to create a Python virtualenv (`venv`), run `pip install`, or configure external wheels. It works out of the box with your system Python.
|
|
@@ -169,6 +146,7 @@ Run TorusGuard instantly in any repository without installing anything globally:
|
|
|
169
146
|
npx torusguard init
|
|
170
147
|
npx torusguard audit
|
|
171
148
|
npx torusguard status
|
|
149
|
+
npx torusguard update
|
|
172
150
|
```
|
|
173
151
|
|
|
174
152
|
### 2. Project Dev Dependency
|
|
@@ -185,19 +163,32 @@ Add convenience scripts to your `package.json`:
|
|
|
185
163
|
"security:audit": "torusguard audit",
|
|
186
164
|
"security:harden": "torusguard harden",
|
|
187
165
|
"security:recheck": "torusguard recheck",
|
|
188
|
-
"security:status": "torusguard status"
|
|
166
|
+
"security:status": "torusguard status",
|
|
167
|
+
"security:update": "torusguard update"
|
|
189
168
|
}
|
|
190
169
|
}
|
|
191
170
|
```
|
|
192
171
|
|
|
193
|
-
### 3.
|
|
172
|
+
### 3. Native Go CLI Runner
|
|
173
|
+
For Go ecosystem developers, TorusGuard ships with a native Go runner module ([go.mod](go.mod)):
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Run zero-dependency Go CLI entrypoint directly
|
|
177
|
+
go run cmd/torusguard/main.go audit
|
|
178
|
+
|
|
179
|
+
# Or install globally into your $GOPATH/bin
|
|
180
|
+
go install github.com/torusguard/torusguard/cmd/torusguard@latest
|
|
181
|
+
torusguard status
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 4. Global NPM Installation
|
|
194
185
|
If you prefer having the `torusguard` binary available system-wide across all terminal sessions:
|
|
195
186
|
|
|
196
187
|
```bash
|
|
197
188
|
npm install -g torusguard
|
|
198
189
|
```
|
|
199
190
|
|
|
200
|
-
###
|
|
191
|
+
### 5. AI Agent Skill Installation
|
|
201
192
|
Install TorusGuard as a native AI assistant skill for Cursor, Claude Code, Cline, or Antigravity:
|
|
202
193
|
|
|
203
194
|
```bash
|
|
@@ -207,7 +198,7 @@ npx skills add torusguard
|
|
|
207
198
|
---
|
|
208
199
|
|
|
209
200
|
### 🔍 What Happens on First Run (`init`)
|
|
210
|
-
When you execute `npx torusguard init` in your repository:
|
|
201
|
+
When you execute `npx torusguard init` (or `npx torusguard init --template golang`) in your repository:
|
|
211
202
|
1. **Polyglot Profiling:** Automatically detects 16+ languages (Go, Rust, Java, C#, PHP, Python, TypeScript) and 30+ frameworks without manual configuration.
|
|
212
203
|
2. **Scaffolding:** Creates a local `.torusguard/` directory containing active security rules, schemas, and runners.
|
|
213
204
|
3. **Editor Rules Synchronization:** Automatically compiles compact, language-specific guardrails into `.cursorrules`, `CLAUDE.md`, `.agent/rules/torusguard.md`, and `.windsurfrules` ($\le 300$ prompt tokens).
|
|
@@ -221,16 +212,16 @@ When you execute `npx torusguard init` in your repository:
|
|
|
221
212
|
Run the complete autonomous governance cycle in 60 seconds from your terminal:
|
|
222
213
|
|
|
223
214
|
```bash
|
|
224
|
-
# Step 1: Initialize workspace and profile stack
|
|
215
|
+
# Step 1: Initialize workspace and profile stack (optional: --template golang|nextjs|fastapi)
|
|
225
216
|
npx torusguard init
|
|
226
217
|
|
|
227
|
-
# Step 2: Run AST static security audit across 74 rules
|
|
218
|
+
# Step 2: Run AST static security audit across 74 rules (optional: --watch, --sarif)
|
|
228
219
|
npx torusguard audit
|
|
229
220
|
|
|
230
|
-
# Step 3: Synthesize minimal surgical candidate patches
|
|
221
|
+
# Step 3: Synthesize minimal surgical candidate patches (optional: --dry-run, --severity high)
|
|
231
222
|
npx torusguard harden
|
|
232
223
|
|
|
233
|
-
# Step 4: Review syntax-highlighted diffs and apply with rollback backup
|
|
224
|
+
# Step 4: Review syntax-highlighted diffs and apply with rollback backup (optional: --diff, --selective)
|
|
234
225
|
npx torusguard apply
|
|
235
226
|
|
|
236
227
|
# Step 5: Differentially recheck modified files to verify fix closure
|
|
@@ -243,37 +234,71 @@ npx torusguard recheck
|
|
|
243
234
|
|
|
244
235
|
## ⌨️ Dual-Strategy Command Matrix (CLI & AI Chat Parity)
|
|
245
236
|
|
|
246
|
-
TorusGuard guarantees **100% operational parity** between terminal CLI execution and AI chat slash commands. Terminal outputs strictly adhere to a **75-column visual width** with Unicode emojis and ANSI stripping.
|
|
237
|
+
TorusGuard guarantees **100% operational parity** between terminal CLI execution and AI chat slash commands. Terminal outputs strictly adhere to a **75-column visual width** with Unicode emojis and ANSI stripping. All commands support `--target <dir>` / `-t <dir>` for monorepo and subproject isolation.
|
|
247
238
|
|
|
248
239
|
### 🔄 Core Remediation Lifecycle
|
|
249
240
|
|
|
250
241
|
| Lifecycle Stage | Mode A: Terminal CLI | Mode B: AI Chat Command | Governed Action & Primary Artifact |
|
|
251
242
|
|:---|:---|:---|:---|
|
|
252
|
-
| **1. Init** | `npx torusguard init` | `/torusguard init` | Profiles workspace, activates rules,
|
|
253
|
-
| **2.
|
|
254
|
-
| **3.
|
|
255
|
-
| **4.
|
|
256
|
-
| **5.
|
|
257
|
-
| **6.
|
|
243
|
+
| **1. Init** | `npx torusguard init [--template <name>] [--audit]` | `/torusguard init` | Profiles workspace, activates rules, scaffolds `.torusguard/` |
|
|
244
|
+
| **2. Status** | `npx torusguard status` | `/torusguard status` | 75-column diagnostic overview of health score, stack, memory & rules |
|
|
245
|
+
| **3. Audit** | `npx torusguard audit [--watch] [--sarif]` | `/torusguard audit` | 74-rule AST scan, line-shift fingerprints, throughput metrics, living ledger |
|
|
246
|
+
| **4. Verify** | `npx torusguard verify` | `/torusguard verify` | Asserts evidence sufficiency & live disk line-shift fingerprint matches |
|
|
247
|
+
| **5. Harden** | `npx torusguard harden [--dry-run] [--severity <s\>]` | `/torusguard harden` | Synthesizes Ponytail diffs ($\le 35$ add, $\le 25$ del) into candidate bundles |
|
|
248
|
+
| **6. Apply** | `npx torusguard apply [--diff] [--selective] [--yes]` | `/torusguard apply` | Human Gate, pre-apply `.bak` snapshots, Golden Fix distillation |
|
|
249
|
+
| **7. Rollback**| `npx torusguard rollback [--run <id>]` | `/torusguard rollback` | Instant restoration from pre-apply snapshots in `.torusguard/snapshots/` |
|
|
250
|
+
| **8. Recheck** | `npx torusguard recheck` | `/torusguard recheck` | Differential AST re-scan; marks findings `RESOLVED 🟢` in living report |
|
|
251
|
+
| **9. Recipes** | `npx torusguard recipes [--search <q>] [--export <p>]`| `/torusguard recipes` | Explores and exports verified Golden Fix patterns from `.torusguard/memory/` |
|
|
252
|
+
| **10. Report** | `npx torusguard report --html [--sarif]` | `/torusguard report` | Emits single-file dark-mode HTML posture dashboard & OASIS SARIF v2.1.0 |
|
|
253
|
+
| **11. Update** | `npx torusguard update [--install]` | `/torusguard update` | Verifies npm registry for latest versions and provides 1-command upgrade |
|
|
254
|
+
| **12. Rules Sync**| `npx torusguard rules sync` | `/torusguard rules sync`| Synchronizes prompt guardrails across Cursor, Claude, Antigravity, Windsurf |
|
|
255
|
+
| **13. Diff Guard**| `npx torusguard diff-guard [--install-hook]` | `/torusguard diff-guard`| Audits git diffs for security bypasses; binds pre-commit git hook |
|
|
256
|
+
| **14. Authorize** | `npx torusguard authorize` | `/torusguard authorize` | Target domain allowlisting, cryptographic ownership proof, TTL limits |
|
|
257
|
+
| **15. Validate** | `npx torusguard web-validate` | `/torusguard web-validate`| Authorized non-destructive HTTP probing with transparent audit headers |
|
|
258
|
+
| **16. Exploit** | `npx torusguard exploit-check` | `/torusguard exploit-check`| Bounded single-step exploitability confirmation using inert sentinels |
|
|
258
259
|
|
|
259
|
-
|
|
260
|
+
---
|
|
260
261
|
|
|
261
|
-
|
|
262
|
-
|:---|:---|:---|:---|
|
|
263
|
-
| **Status** | `npx torusguard status` | `/torusguard status` | 75-column diagnostic overview of health score, stack, memory & rules |
|
|
264
|
-
| **Recipes** | `npx torusguard recipes` | `/torusguard recipes` | Explores verified Golden Fix patterns stored in `.torusguard/memory/` |
|
|
265
|
-
| **Report** | `npx torusguard report --html` | `/torusguard report` | Emits single-file dark-mode HTML posture report & OASIS SARIF v2.1.0 |
|
|
266
|
-
| **Rules Sync**| `npx torusguard rules sync` | `/torusguard rules sync`| Synchronizes prompt guardrails across Cursor, Claude, Antigravity, Windsurf |
|
|
267
|
-
| **Diff Guard**| `npx torusguard diff-guard` | `/torusguard diff-guard`| Audits git diffs for security bypasses; `--install-hook` binds pre-commit |
|
|
262
|
+
## 🐹 Polyglot Go Engine & Native Runner
|
|
268
263
|
|
|
269
|
-
|
|
264
|
+
TorusGuard v1.4.0 introduces native, zero-dependency Go ecosystem support:
|
|
270
265
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
266
|
+
### 1. Go AST Invariant Security Rules
|
|
267
|
+
- **`TG-INPUT-002` (Raw SQL Concatenation):** Detects unparameterized string concatenation and `fmt.Sprintf` query interpolation in `database/sql`, `sqlx`, and GORM.
|
|
268
|
+
- **`TG-INPUT-006` (Path Traversal):** Detects unsanitized file reads (`os.Open`, `os.ReadFile`) using user request parameters.
|
|
269
|
+
- **`TG-SSRF-004` (Unbounded HTTP Requests):** Flags `&http.Client{}` and `http.DefaultClient` lacking explicit timeout boundaries to prevent connection pooling denial-of-service.
|
|
270
|
+
- **`TG-DIFF-001` (Security Bypasses):** Prevents insecure TLS validation (`InsecureSkipVerify: true`).
|
|
271
|
+
- **`TG-SUPPLY-001` (Supply Chain):** Asserts lockfile presence and cryptographic tracking for `go.sum`.
|
|
272
|
+
|
|
273
|
+
### 2. Surgical Ponytail Remediation for Go
|
|
274
|
+
Patches for Go follow strict Ponytail line churn limits ($\le 35$ additions, $\le 25$ deletions):
|
|
275
|
+
```go
|
|
276
|
+
// Example: TG-SSRF-004 Remediation
|
|
277
|
+
- client := &http.Client{}
|
|
278
|
+
+ client := &http.Client{Timeout: 10 * time.Second}
|
|
279
|
+
|
|
280
|
+
// Example: TG-INPUT-006 Path Traversal Remediation
|
|
281
|
+
- data, err := os.ReadFile("/data/" + c.Query("file"))
|
|
282
|
+
+ data, err := os.ReadFile(filepath.Join("/data", filepath.Base(c.Query("file"))))
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 🔄 Package Self-Update Engine (`update`)
|
|
288
|
+
|
|
289
|
+
Keep your security guardrails continuously synchronized with the latest threat models:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Check registry for newer versions
|
|
293
|
+
npx torusguard update
|
|
294
|
+
|
|
295
|
+
# Automatically upgrade to latest version
|
|
296
|
+
npx torusguard update --install
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
- **Zero-Dependency Registry Check:** Queries `https://registry.npmjs.org/torusguard/latest` natively.
|
|
300
|
+
- **SemVer Delta Analysis:** Displays current version against registry latest in standard 75-column cards.
|
|
301
|
+
- **Automated Upgrade Flow:** Executes package installation upon user authorization.
|
|
277
302
|
|
|
278
303
|
---
|
|
279
304
|
|
|
@@ -426,7 +451,7 @@ TorusGuard automatically discovers and profiles multi-package workspaces:
|
|
|
426
451
|
## 🧪 Verification & Test Harness
|
|
427
452
|
|
|
428
453
|
### What Happens When You Run `npm test`?
|
|
429
|
-
TorusGuard enforces a strict **100% pass requirement across
|
|
454
|
+
TorusGuard enforces a strict **100% pass requirement across 133 tests in 21 test suites** before every release.
|
|
430
455
|
The test harness runs with **zero third-party dependencies** via standard Python 3:
|
|
431
456
|
|
|
432
457
|
```bash
|
|
@@ -441,11 +466,14 @@ npm test
|
|
|
441
466
|
The test harness invokes `python harness/runner.py` directly using the Python standard library. It systematically verifies:
|
|
442
467
|
1. **JSON Schema Validity:** 10 formal schemas (`finding`, `evidence`, `remediation`, `rule`, `lifecycle`, `provenance`, etc.).
|
|
443
468
|
2. **74-Rule Catalog Integrity:** AST detection accuracy across all 18 security families.
|
|
444
|
-
3. **
|
|
445
|
-
4. **
|
|
446
|
-
5. **
|
|
447
|
-
6. **
|
|
448
|
-
7. **
|
|
469
|
+
3. **Polyglot Go Engine:** Go module definition, Go stack detection (Gin, Fiber, GORM), and Go AST rules (`TG-INPUT-002`, `TG-INPUT-006`, `TG-SSRF-004`).
|
|
470
|
+
4. **Line-Shift Fingerprinting:** Stable anchor matching across file edits without line number drift.
|
|
471
|
+
5. **Secret Redaction:** Stripe secret keys and JWT tokens safely masked.
|
|
472
|
+
6. **Deterministic Replay:** 3-pass differential validation across Django, DRF, FastAPI, Flask, and SQLAlchemy fixtures.
|
|
473
|
+
7. **Ponytail Patch Churn Bounds:** Verifying line budgets ($\le 35$ additions, $\le 25$ deletions).
|
|
474
|
+
8. **Deepened Command Verification:** Audit watch loop & SARIF export, Harden dry-run & severity floor, Recipes search & export, Apply diff preview & snapshot ledger, and Bootstrap templates.
|
|
475
|
+
9. **Living Security Report State Transitions:** Discovery (`OPEN 🔴`), Candidate (`CANDIDATE 🟡`), Applied (`APPLIED 🔵`), and Verified Closure (`RESOLVED 🟢`).
|
|
476
|
+
10. **Cryptographic Manifest Parity:** 100% SHA-256 match across all indexed workspace files.
|
|
449
477
|
|
|
450
478
|
```bash
|
|
451
479
|
# Run formal TorusGuard test harness
|
|
@@ -453,7 +481,7 @@ npm test
|
|
|
453
481
|
|
|
454
482
|
# Expected Output:
|
|
455
483
|
# ================================================================================
|
|
456
|
-
# SUMMARY:
|
|
484
|
+
# SUMMARY: 133 Passed | 0 Failed
|
|
457
485
|
# ================================================================================
|
|
458
486
|
```
|
|
459
487
|
|
package/bin/torusguard.js
CHANGED
|
@@ -15,6 +15,51 @@ const command = args[0] || 'init';
|
|
|
15
15
|
const rootDir = path.resolve(__dirname, '..');
|
|
16
16
|
const cwd = process.cwd();
|
|
17
17
|
|
|
18
|
+
// Parse version flag immediately
|
|
19
|
+
if (command === '--version' || command === '-v' || command === 'version') {
|
|
20
|
+
let ver = '1.4.0';
|
|
21
|
+
try {
|
|
22
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8'));
|
|
23
|
+
ver = pkg.version || ver;
|
|
24
|
+
} catch (e) {}
|
|
25
|
+
console.log(`torusguard v${ver}`);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseTargetAndArgs(cliArgs) {
|
|
30
|
+
let target = '.';
|
|
31
|
+
const remaining = [];
|
|
32
|
+
for (let i = 1; i < cliArgs.length; i++) {
|
|
33
|
+
const a = cliArgs[i];
|
|
34
|
+
if (a === '--target' || a === '-t' || a === '--root') {
|
|
35
|
+
if (i + 1 < cliArgs.length) {
|
|
36
|
+
target = cliArgs[i + 1];
|
|
37
|
+
i++;
|
|
38
|
+
}
|
|
39
|
+
} else if (a.startsWith('--target=') || a.startsWith('--root=')) {
|
|
40
|
+
target = a.split('=')[1];
|
|
41
|
+
} else {
|
|
42
|
+
remaining.push(a);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (target === '.' && remaining.length > 0 && !remaining[0].startsWith('-')) {
|
|
46
|
+
target = remaining.shift();
|
|
47
|
+
}
|
|
48
|
+
return { target, remaining };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function compareSemver(a, b) {
|
|
52
|
+
const pa = a.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0);
|
|
53
|
+
const pb = b.replace(/^v/, '').split('.').map(n => parseInt(n, 10) || 0);
|
|
54
|
+
for (let i = 0; i < 3; i++) {
|
|
55
|
+
const na = pa[i] || 0;
|
|
56
|
+
const nb = pb[i] || 0;
|
|
57
|
+
if (na > nb) return 1;
|
|
58
|
+
if (na < nb) return -1;
|
|
59
|
+
}
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
18
63
|
// ─── ANSI Color Helpers ───────────────────────────────────────────────────────
|
|
19
64
|
const BOLD = '\x1b[1m';
|
|
20
65
|
const DIM = '\x1b[2m';
|
|
@@ -169,12 +214,13 @@ function cardHeader(title, subtitle = '', version = 'v1.3.6', borderColor = CYAN
|
|
|
169
214
|
|
|
170
215
|
function printHelp() {
|
|
171
216
|
console.log();
|
|
172
|
-
console.log(cardHeader('🛡️ T O R U S G U A R D C L I', 'Autonomous Security Engine for AI-Built Applications', 'v1.
|
|
217
|
+
console.log(cardHeader('🛡️ T O R U S G U A R D C L I', 'Autonomous Security Engine for AI-Built Applications', 'v1.4.0'));
|
|
173
218
|
console.log(`\n ${BOLD}Usage:${RESET} ${GREEN}npx torusguard${RESET} ${WHITE}[command]${RESET} ${GRAY}[options]${RESET}\n`);
|
|
174
219
|
|
|
175
220
|
console.log(cardBorderTop('Commands'));
|
|
176
221
|
console.log(formatBoxLine(`${GREEN}init${RESET} Scaffold ${BOLD}.torusguard/${RESET} workspace + unlock slash commands`));
|
|
177
222
|
console.log(formatBoxLine(`${GREEN}status${RESET} Display active security posture, memory, rules, & stack`));
|
|
223
|
+
console.log(formatBoxLine(`${GREEN}update${RESET} Check npm registry for updates (--install to auto-upgrade)`));
|
|
178
224
|
console.log(formatBoxLine(`${GREEN}rules${RESET} Auto-sync memory to AI IDE rules (.cursorrules, CLAUDE.md)`));
|
|
179
225
|
console.log(formatBoxLine(`${GREEN}memory${RESET} Manage persistent security memory (export, hook, learn)`));
|
|
180
226
|
console.log(formatBoxLine(`${GREEN}audit${RESET} Run static AST security scan on target project`));
|
|
@@ -198,6 +244,7 @@ function printHelp() {
|
|
|
198
244
|
console.log(formatBoxLine(`${GRAY}--target <dir>${RESET} Target directory to analyze or scaffold ${DIM}(default: .)${RESET}`));
|
|
199
245
|
console.log(formatBoxLine(`${GRAY}--force${RESET} Overwrite existing workspace and re-scaffold`));
|
|
200
246
|
console.log(formatBoxLine(`${GRAY}--yes, -y${RESET} Non-interactive auto-approval for patch application`));
|
|
247
|
+
console.log(formatBoxLine(`${GRAY}--version, -v${RESET} Display TorusGuard package version`));
|
|
201
248
|
console.log(cardBorderBottom());
|
|
202
249
|
|
|
203
250
|
console.log(`\n ${BOLD}AI Chat Commands:${RESET}`);
|
|
@@ -219,7 +266,18 @@ if (command === 'help' || command === '--help' || command === '-h') {
|
|
|
219
266
|
}
|
|
220
267
|
|
|
221
268
|
if (command === 'status') {
|
|
222
|
-
const
|
|
269
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
270
|
+
const targetDir = path.resolve(cwd, target);
|
|
271
|
+
const statusScript = path.join(targetDir, '.torusguard', 'scripts', 'status_runner.py');
|
|
272
|
+
const fallbackStatusScript = path.join(rootDir, '.torusguard', 'scripts', 'status_runner.py');
|
|
273
|
+
const actualStatusScript = fs.existsSync(statusScript) ? statusScript : fallbackStatusScript;
|
|
274
|
+
|
|
275
|
+
if (fs.existsSync(actualStatusScript)) {
|
|
276
|
+
const proc = spawnSync(pythonCmd, [actualStatusScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
277
|
+
process.exit(proc.status !== null ? proc.status : 0);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const cfgPath = path.join(targetDir, '.torusguard', 'config', 'torusguard.json');
|
|
223
281
|
if (fs.existsSync(cfgPath)) {
|
|
224
282
|
try {
|
|
225
283
|
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf-8'));
|
|
@@ -441,11 +499,13 @@ if (command === 'rules') {
|
|
|
441
499
|
|
|
442
500
|
// Subcommand: audit
|
|
443
501
|
if (command === 'audit') {
|
|
444
|
-
const
|
|
502
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
503
|
+
const targetDir = path.resolve(cwd, target);
|
|
504
|
+
const auditScript = path.join(targetDir, '.torusguard', 'scripts', 'audit_runner.py');
|
|
445
505
|
const fallbackAuditScript = path.join(rootDir, '.torusguard', 'scripts', 'audit_runner.py');
|
|
446
506
|
const actualAuditScript = fs.existsSync(fallbackAuditScript) ? fallbackAuditScript : auditScript;
|
|
447
507
|
|
|
448
|
-
const proc = spawnSync(pythonCmd, [actualAuditScript, ...
|
|
508
|
+
const proc = spawnSync(pythonCmd, [actualAuditScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
449
509
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
450
510
|
}
|
|
451
511
|
|
|
@@ -455,7 +515,7 @@ if (command === 'report') {
|
|
|
455
515
|
const wantSarif = args.includes('--sarif') || (!wantHtml && args[1] !== 'html');
|
|
456
516
|
|
|
457
517
|
// Resolve target directory (supports --target and --root)
|
|
458
|
-
const rootIdx = args.indexOf('--root') !== -1 ? args.indexOf('--root') : args.indexOf('--target');
|
|
518
|
+
const rootIdx = args.indexOf('--root') !== -1 ? args.indexOf('--root') : (args.indexOf('--target') !== -1 ? args.indexOf('--target') : args.indexOf('-t'));
|
|
459
519
|
let targetRoot = cwd;
|
|
460
520
|
if (rootIdx !== -1 && args[rootIdx + 1]) {
|
|
461
521
|
targetRoot = path.resolve(cwd, args[rootIdx + 1]);
|
|
@@ -518,69 +578,179 @@ if (command === 'report') {
|
|
|
518
578
|
|
|
519
579
|
// Subcommand: harden
|
|
520
580
|
if (command === 'harden') {
|
|
521
|
-
const
|
|
581
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
582
|
+
const targetDir = path.resolve(cwd, target);
|
|
583
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'harden_runner.py');
|
|
522
584
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'harden_runner.py');
|
|
523
585
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
524
586
|
|
|
525
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
587
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
526
588
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
527
589
|
}
|
|
528
590
|
|
|
529
591
|
// Subcommand: apply
|
|
530
592
|
if (command === 'apply') {
|
|
531
|
-
const
|
|
593
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
594
|
+
const targetDir = path.resolve(cwd, target);
|
|
595
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
532
596
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
533
597
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
534
598
|
|
|
535
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
599
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
536
600
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
537
601
|
}
|
|
538
602
|
|
|
539
603
|
// Subcommand: rollback
|
|
540
604
|
if (command === 'rollback') {
|
|
541
|
-
const
|
|
605
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
606
|
+
const targetDir = path.resolve(cwd, target);
|
|
607
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
542
608
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'apply_runner.py');
|
|
543
609
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
544
610
|
|
|
545
|
-
const proc = spawnSync(pythonCmd, [actualScript, '--rollback', ...
|
|
611
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, '--rollback', ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
546
612
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
547
613
|
}
|
|
548
614
|
|
|
549
615
|
// Subcommand: recheck / verify
|
|
550
616
|
if (command === 'recheck' || command === 'verify') {
|
|
551
|
-
const
|
|
617
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
618
|
+
const targetDir = path.resolve(cwd, target);
|
|
619
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'recheck_runner.py');
|
|
552
620
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recheck_runner.py');
|
|
553
621
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
554
622
|
|
|
555
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
623
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
556
624
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
557
625
|
}
|
|
558
626
|
|
|
559
627
|
// Subcommand: recipes
|
|
560
628
|
if (command === 'recipes') {
|
|
561
|
-
const
|
|
629
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
630
|
+
const targetDir = path.resolve(cwd, target);
|
|
631
|
+
const scriptPath = path.join(targetDir, '.torusguard', 'scripts', 'recipes_runner.py');
|
|
562
632
|
const fallbackScript = path.join(rootDir, '.torusguard', 'scripts', 'recipes_runner.py');
|
|
563
633
|
const actualScript = fs.existsSync(fallbackScript) ? fallbackScript : scriptPath;
|
|
564
634
|
|
|
565
|
-
const proc = spawnSync(pythonCmd, [actualScript, ...
|
|
635
|
+
const proc = spawnSync(pythonCmd, [actualScript, targetDir, ...remaining], { stdio: 'inherit', cwd: targetDir });
|
|
566
636
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
567
637
|
}
|
|
568
638
|
|
|
569
639
|
// Subcommand: init (scaffold workspace)
|
|
570
640
|
if (command === 'init') {
|
|
641
|
+
const { target, remaining } = parseTargetAndArgs(args);
|
|
642
|
+
const targetDir = path.resolve(cwd, target);
|
|
571
643
|
const localBootstrap = path.join(rootDir, 'skills', 'torusguard', 'bootstrap.py');
|
|
572
644
|
const localInstall = path.join(rootDir, 'install.py');
|
|
573
645
|
const scriptToRun = fs.existsSync(localBootstrap) ? localBootstrap : localInstall;
|
|
574
646
|
|
|
575
|
-
const scriptArgs = [scriptToRun, '--full-commands', ...
|
|
647
|
+
const scriptArgs = [scriptToRun, '--full-commands', '--target', targetDir, ...remaining];
|
|
576
648
|
const proc = spawnSync(pythonCmd, scriptArgs, {
|
|
577
649
|
stdio: 'inherit',
|
|
578
|
-
cwd:
|
|
650
|
+
cwd: targetDir,
|
|
579
651
|
});
|
|
580
652
|
process.exit(proc.status !== null ? proc.status : 0);
|
|
581
653
|
}
|
|
582
654
|
|
|
655
|
+
// Subcommand: update
|
|
656
|
+
if (command === 'update') {
|
|
657
|
+
const https = require('https');
|
|
658
|
+
const pkgJsonPath = path.join(rootDir, 'package.json');
|
|
659
|
+
let currentVersion = '1.4.0';
|
|
660
|
+
try {
|
|
661
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
662
|
+
currentVersion = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')).version || currentVersion;
|
|
663
|
+
}
|
|
664
|
+
} catch (e) {}
|
|
665
|
+
|
|
666
|
+
console.log();
|
|
667
|
+
console.log(cardHeader('🛡️ TORUSGUARD UPDATE CHECK', 'Package Distribution & Registry Verifier', `v${currentVersion}`));
|
|
668
|
+
console.log(`\n ${DIM}Checking npm registry for updates...${RESET}`);
|
|
669
|
+
|
|
670
|
+
const autoInstall = args.includes('--install') || args.includes('-i') || args.includes('--yes') || args.includes('-y');
|
|
671
|
+
|
|
672
|
+
function printUpdateOffline(reason) {
|
|
673
|
+
console.log();
|
|
674
|
+
console.log(cardBorderTop('Offline / Registry Unreachable', YELLOW));
|
|
675
|
+
console.log(formatBoxLine(`Current: ${WHITE}v${currentVersion}${RESET}`, 67, '│', YELLOW));
|
|
676
|
+
console.log(formatBoxLine(`Notice: ${DIM}${reason}${RESET}`, 67, '│', YELLOW));
|
|
677
|
+
console.log(formatBoxLine(`Manual: ${BOLD}${CYAN}npm update torusguard${RESET} or ${BOLD}${CYAN}npm i -g torusguard@latest${RESET}`, 67, '│', YELLOW));
|
|
678
|
+
console.log(cardBorderBottom(YELLOW));
|
|
679
|
+
console.log();
|
|
680
|
+
process.exit(0);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const req = https.get('https://registry.npmjs.org/torusguard/latest', {
|
|
684
|
+
headers: { 'User-Agent': `torusguard-cli/${currentVersion}` },
|
|
685
|
+
timeout: 6000
|
|
686
|
+
}, (res) => {
|
|
687
|
+
let raw = '';
|
|
688
|
+
res.on('data', chunk => raw += chunk);
|
|
689
|
+
res.on('end', () => {
|
|
690
|
+
try {
|
|
691
|
+
const data = JSON.parse(raw);
|
|
692
|
+
const latestVersion = data.version;
|
|
693
|
+
if (!latestVersion) {
|
|
694
|
+
printUpdateOffline('No version field returned in npm registry response');
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const isNewer = compareSemver(latestVersion, currentVersion) > 0;
|
|
699
|
+
console.log();
|
|
700
|
+
console.log(cardBorderTop('Version Telemetry', CYAN));
|
|
701
|
+
console.log(formatBoxLine(`Installed Version: ${WHITE}v${currentVersion}${RESET}`));
|
|
702
|
+
console.log(formatBoxLine(`Latest on NPM: ${BOLD}${GREEN}v${latestVersion}${RESET}`));
|
|
703
|
+
console.log(cardBorderBottom(CYAN));
|
|
704
|
+
console.log();
|
|
705
|
+
|
|
706
|
+
if (isNewer) {
|
|
707
|
+
console.log(cardBorderTop('Update Available', YELLOW, true));
|
|
708
|
+
console.log(formatBoxLine(`${YELLOW}A new version of TorusGuard is available!${RESET}`, 67, '║', YELLOW));
|
|
709
|
+
console.log(formatBoxLine(`Global: ${BOLD}${WHITE}npm install -g torusguard@latest${RESET}`, 67, '║', YELLOW));
|
|
710
|
+
console.log(formatBoxLine(`Local: ${BOLD}${WHITE}npm install torusguard@latest${RESET}`, 67, '║', YELLOW));
|
|
711
|
+
console.log(cardBorderBottom(YELLOW, true));
|
|
712
|
+
console.log();
|
|
713
|
+
|
|
714
|
+
if (autoInstall) {
|
|
715
|
+
console.log(` ${CYAN}Auto-installing latest version via npm...${RESET}`);
|
|
716
|
+
const npmProc = spawnSync('npm', ['install', '-g', 'torusguard@latest'], { stdio: 'inherit' });
|
|
717
|
+
if (npmProc.status === 0) {
|
|
718
|
+
console.log(`\n ${GREEN}✔ Successfully upgraded TorusGuard to v${latestVersion}!${RESET}\n`);
|
|
719
|
+
} else {
|
|
720
|
+
console.error(`\n ${RED}✖ Failed to auto-install update. Run: npm install -g torusguard@latest${RESET}\n`);
|
|
721
|
+
}
|
|
722
|
+
} else {
|
|
723
|
+
console.log(` ${DIM}Tip: Run with ${CYAN}npx torusguard update --install${DIM} to auto-upgrade.${RESET}\n`);
|
|
724
|
+
}
|
|
725
|
+
} else {
|
|
726
|
+
console.log(cardBorderTop('Status: Up To Date', GREEN, true));
|
|
727
|
+
console.log(formatBoxLine(`${GREEN}✔ TorusGuard is up to date (v${currentVersion})${RESET}`, 67, '║', GREEN));
|
|
728
|
+
console.log(cardBorderBottom(GREEN, true));
|
|
729
|
+
console.log();
|
|
730
|
+
}
|
|
731
|
+
process.exit(0);
|
|
732
|
+
} catch (err) {
|
|
733
|
+
printUpdateOffline(err.message);
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
req.on('error', (err) => printUpdateOffline(err.message));
|
|
739
|
+
req.on('timeout', () => {
|
|
740
|
+
req.destroy();
|
|
741
|
+
printUpdateOffline('npm registry request timed out (6000ms)');
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
|
|
583
745
|
// Unknown command fallback
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
746
|
+
const KNOWN_COMMANDS = new Set([
|
|
747
|
+
'init', 'status', 'rules', 'memory', 'diff-guard', 'audit',
|
|
748
|
+
'report', 'harden', 'apply', 'rollback', 'recheck', 'verify',
|
|
749
|
+
'recipes', 'update', 'help', '--help', '-h', '--version', '-v', 'version'
|
|
750
|
+
]);
|
|
751
|
+
|
|
752
|
+
if (!KNOWN_COMMANDS.has(command)) {
|
|
753
|
+
console.error(`\n ${RED}✖ Unknown command:${RESET} ${WHITE}${command}${RESET}`);
|
|
754
|
+
console.error(` Run ${GREEN}npx torusguard help${RESET} for available commands.\n`);
|
|
755
|
+
process.exit(1);
|
|
756
|
+
}
|