@soulbatical/tetra-dev-toolkit 1.3.0 → 1.3.1
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/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# @soulbatical/tetra-dev-toolkit
|
|
2
|
+
|
|
3
|
+
Quality, security, and hygiene checks for all Soulbatical projects.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --save-dev @soulbatical/tetra-dev-toolkit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup (A-Z)
|
|
12
|
+
|
|
13
|
+
One command installs everything — hooks, CI, config:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx tetra-setup
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This creates:
|
|
20
|
+
- `.husky/pre-commit` — quick security checks before every commit
|
|
21
|
+
- `.husky/pre-push` — hygiene check before every push (blocks clutter)
|
|
22
|
+
- `.github/workflows/quality.yml` — full audit on PR/push to main
|
|
23
|
+
- `.tetra-quality.json` — project config (override defaults)
|
|
24
|
+
|
|
25
|
+
To install individual components:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx tetra-setup hooks # Husky hooks only
|
|
29
|
+
npx tetra-setup ci # GitHub Actions only
|
|
30
|
+
npx tetra-setup config # Config file only
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Re-running `tetra-setup hooks` on an existing project adds missing hooks without overwriting existing ones.
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx tetra-audit # Run all checks
|
|
39
|
+
npx tetra-audit security # Security checks only
|
|
40
|
+
npx tetra-audit stability # Stability checks only
|
|
41
|
+
npx tetra-audit codeQuality # Code quality checks only
|
|
42
|
+
npx tetra-audit supabase # Supabase checks only
|
|
43
|
+
npx tetra-audit hygiene # Repo hygiene checks only
|
|
44
|
+
npx tetra-audit quick # Quick critical checks (pre-commit)
|
|
45
|
+
npx tetra-audit --ci # CI mode (GitHub Actions annotations)
|
|
46
|
+
npx tetra-audit --json # JSON output
|
|
47
|
+
npx tetra-audit --verbose # Detailed output with fix suggestions
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Exit codes: `0` = passed, `1` = failed, `2` = error.
|
|
51
|
+
|
|
52
|
+
## Check Suites
|
|
53
|
+
|
|
54
|
+
### Security (5 checks)
|
|
55
|
+
|
|
56
|
+
| Check | Severity | What it catches |
|
|
57
|
+
|-------|----------|-----------------|
|
|
58
|
+
| Hardcoded Secrets | critical | API keys, tokens, JWTs in source code |
|
|
59
|
+
| Service Key Exposure | critical | Supabase service role keys in frontend |
|
|
60
|
+
| Deprecated Supabase Admin | high | Legacy `createClient(serviceKey)` patterns |
|
|
61
|
+
| SystemDB Whitelist | high | Unauthorized system database access |
|
|
62
|
+
| Gitignore Validation | high | Missing .gitignore entries, tracked .env files |
|
|
63
|
+
|
|
64
|
+
### Stability (3 checks)
|
|
65
|
+
|
|
66
|
+
| Check | Severity | What it catches |
|
|
67
|
+
|-------|----------|-----------------|
|
|
68
|
+
| Husky Hooks | medium | Missing pre-commit/pre-push hooks |
|
|
69
|
+
| CI Pipeline | medium | Missing or incomplete GitHub Actions config |
|
|
70
|
+
| NPM Audit | high | Known vulnerabilities in dependencies |
|
|
71
|
+
|
|
72
|
+
### Code Quality (1 check)
|
|
73
|
+
|
|
74
|
+
| Check | Severity | What it catches |
|
|
75
|
+
|-------|----------|-----------------|
|
|
76
|
+
| API Response Format | medium | Non-standard `{ success, data }` response format |
|
|
77
|
+
|
|
78
|
+
### Supabase (2 checks, auto-detected)
|
|
79
|
+
|
|
80
|
+
| Check | Severity | What it catches |
|
|
81
|
+
|-------|----------|-----------------|
|
|
82
|
+
| RLS Policy Audit | critical | Tables without Row Level Security |
|
|
83
|
+
| RPC Param Mismatch | critical | TypeScript `.rpc()` calls with wrong parameter names vs SQL |
|
|
84
|
+
|
|
85
|
+
### Hygiene (1 check)
|
|
86
|
+
|
|
87
|
+
| Check | Severity | What it catches |
|
|
88
|
+
|-------|----------|-----------------|
|
|
89
|
+
| File Organization | high | Stray .md, .sh, clutter in code dirs, root mess, nested docs/ |
|
|
90
|
+
|
|
91
|
+
## Health Checks
|
|
92
|
+
|
|
93
|
+
Separate from audit suites, health checks provide a scored assessment (0-N points) used by the Ralph Manager dashboard:
|
|
94
|
+
|
|
95
|
+
| Check | Max | What it measures |
|
|
96
|
+
|-------|-----|------------------|
|
|
97
|
+
| File Organization | 6pt | Docs in /docs, scripts in /scripts, clean root & code dirs |
|
|
98
|
+
| Git | 4pt | Clean working tree, branch hygiene, commit frequency |
|
|
99
|
+
| Gitignore | 3pt | Critical entries present |
|
|
100
|
+
| CLAUDE.md | 3pt | Project instructions for AI assistants |
|
|
101
|
+
| Secrets | 3pt | No exposed secrets |
|
|
102
|
+
| Tests | 4pt | Test framework, coverage, test files |
|
|
103
|
+
| Naming Conventions | 5pt | File/dir naming consistency |
|
|
104
|
+
| Infrastructure YML | 3pt | Railway/Docker config |
|
|
105
|
+
| Doppler Compliance | 2pt | Secrets management via Doppler |
|
|
106
|
+
| MCP Servers | 2pt | MCP configuration |
|
|
107
|
+
| Stella Integration | 2pt | Stella package integration |
|
|
108
|
+
| Quality Toolkit | 2pt | Tetra dev-toolkit installed |
|
|
109
|
+
| Repo Visibility | 1pt | Private repo |
|
|
110
|
+
| RLS Audit | 3pt | Row Level Security policies |
|
|
111
|
+
| Plugins | 2pt | Claude Code plugin config |
|
|
112
|
+
| VinciFox Widget | 1pt | Widget installation |
|
|
113
|
+
|
|
114
|
+
## Auto-fix: Cleanup Script
|
|
115
|
+
|
|
116
|
+
For hygiene issues, an auto-fix script is included:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Dry run (shows what would change)
|
|
120
|
+
bash node_modules/@soulbatical/tetra-dev-toolkit/bin/cleanup-repos.sh
|
|
121
|
+
|
|
122
|
+
# Execute
|
|
123
|
+
bash node_modules/@soulbatical/tetra-dev-toolkit/bin/cleanup-repos.sh --execute
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
What it does:
|
|
127
|
+
- `.md` files in code dirs -> `docs/_moved/`
|
|
128
|
+
- `.sh` scripts in code dirs -> `scripts/_moved/`
|
|
129
|
+
- Root clutter (`.txt`, `.png`, `.csv`) -> `docs/_cleanup/`
|
|
130
|
+
- Code dir clutter -> `docs/_cleanup/{dir}/`
|
|
131
|
+
- `.env` secrets in code dirs -> deleted
|
|
132
|
+
- `tmp/`, `logs/`, `data/` dirs -> added to `.gitignore`
|
|
133
|
+
|
|
134
|
+
## Configuration
|
|
135
|
+
|
|
136
|
+
Override defaults in `.tetra-quality.json` or `"tetra-quality"` key in `package.json`:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"suites": {
|
|
141
|
+
"security": true,
|
|
142
|
+
"stability": true,
|
|
143
|
+
"codeQuality": true,
|
|
144
|
+
"supabase": "auto",
|
|
145
|
+
"hygiene": true
|
|
146
|
+
},
|
|
147
|
+
"supabase": {
|
|
148
|
+
"publicRpcFunctions": ["get_public_data"],
|
|
149
|
+
"publicTables": ["public_lookup"]
|
|
150
|
+
},
|
|
151
|
+
"stability": {
|
|
152
|
+
"allowedVulnerabilities": {
|
|
153
|
+
"critical": 0,
|
|
154
|
+
"high": 0,
|
|
155
|
+
"moderate": 10
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## CLI Tools
|
|
162
|
+
|
|
163
|
+
| Command | Description |
|
|
164
|
+
|---------|-------------|
|
|
165
|
+
| `tetra-audit` | Run quality/security/hygiene checks |
|
|
166
|
+
| `tetra-setup` | Install hooks, CI, and config |
|
|
167
|
+
| `tetra-dev-token` | Generate development tokens |
|
|
168
|
+
|
|
169
|
+
## Changelog
|
|
170
|
+
|
|
171
|
+
### 1.3.0 (2025-02-21)
|
|
172
|
+
|
|
173
|
+
**New: Hygiene suite**
|
|
174
|
+
- Added `tetra-audit hygiene` — detects stray docs, scripts, clutter in code dirs, root mess
|
|
175
|
+
- Added `cleanup-repos.sh` auto-fix script in `bin/`
|
|
176
|
+
- `tetra-setup hooks` now creates pre-push hook with hygiene gate
|
|
177
|
+
- Re-running `tetra-setup hooks` on existing repos adds hygiene check without overwriting
|
|
178
|
+
|
|
179
|
+
**New: RPC Param Mismatch check**
|
|
180
|
+
- Added `rpc-param-mismatch` check in supabase suite
|
|
181
|
+
- Statically compares `.rpc()` calls in TypeScript with SQL function parameter names
|
|
182
|
+
- Catches PGRST202 errors before they hit production
|
|
183
|
+
|
|
184
|
+
**Improved: File Organization health check**
|
|
185
|
+
- Extended from 5pt to 6pt — added root clutter detection
|
|
186
|
+
- Root clutter: `.txt`, `.png`, `.csv`, `.pdf`, `.py` files and `tmp/`, `logs/`, `data/` dirs
|
|
187
|
+
- Gitignored dirs no longer counted as clutter
|
|
188
|
+
- `CLAUDE.md` allowed anywhere (not just root)
|
|
189
|
+
|
|
190
|
+
### 1.2.0
|
|
191
|
+
|
|
192
|
+
- Initial public version
|
|
193
|
+
- Security suite: hardcoded secrets, service key exposure, deprecated admin, systemdb whitelist, gitignore
|
|
194
|
+
- Stability suite: husky hooks, CI pipeline, npm audit
|
|
195
|
+
- Code quality suite: API response format
|
|
196
|
+
- Supabase suite: RLS policy audit
|
|
197
|
+
- Health checks: 16 checks, max 37pt
|
|
198
|
+
- CLI: `tetra-audit`, `tetra-setup`, `tetra-dev-token`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Health Checks — All
|
|
2
|
+
* Health Checks — All 16 project health checks
|
|
3
3
|
*
|
|
4
4
|
* Main entry: scanProjectHealth(projectPath, projectName, options?)
|
|
5
5
|
* Individual checks available via named imports.
|
|
@@ -25,3 +25,4 @@ export { check as checkClaudeMd } from './claude-md.js'
|
|
|
25
25
|
export { check as checkDopplerCompliance } from './doppler-compliance.js'
|
|
26
26
|
export { check as checkInfrastructureYml } from './infrastructure-yml.js'
|
|
27
27
|
export { check as checkFileOrganization } from './file-organization.js'
|
|
28
|
+
export { check as checkRpcParamMismatch } from './rpc-param-mismatch.js'
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Check: RPC Parameter Mismatch
|
|
3
|
+
*
|
|
4
|
+
* Compares .rpc() calls in TypeScript with SQL function definitions
|
|
5
|
+
* to detect parameter name mismatches that cause PGRST202 runtime errors.
|
|
6
|
+
*
|
|
7
|
+
* Score: 3 (full) with deductions:
|
|
8
|
+
* - Critical mismatch (extra param in TS): -1.5 per finding (max -3)
|
|
9
|
+
* - Low (missing params): -0.25 per finding (max -1)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createCheck } from './types.js'
|
|
13
|
+
import { run as runAuditCheck } from '../supabase/rpc-param-mismatch.js'
|
|
14
|
+
|
|
15
|
+
export async function check(projectPath) {
|
|
16
|
+
const result = createCheck('rpc-param-mismatch', 3, {
|
|
17
|
+
sqlFunctionsFound: 0,
|
|
18
|
+
rpcCallsFound: 0,
|
|
19
|
+
rpcCallsChecked: 0,
|
|
20
|
+
criticalMismatches: [],
|
|
21
|
+
missingParams: [],
|
|
22
|
+
message: ''
|
|
23
|
+
})
|
|
24
|
+
result.score = 3 // Start full, deduct for issues
|
|
25
|
+
|
|
26
|
+
// Re-use the audit check with default config paths
|
|
27
|
+
const config = {
|
|
28
|
+
paths: {
|
|
29
|
+
backend: ['backend/src', 'src'],
|
|
30
|
+
migrations: ['supabase/migrations', 'backend/supabase/migrations', 'migrations']
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let auditResult
|
|
35
|
+
try {
|
|
36
|
+
auditResult = await runAuditCheck(config, projectPath)
|
|
37
|
+
} catch {
|
|
38
|
+
result.details.message = 'Failed to run RPC param mismatch check'
|
|
39
|
+
return result
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (auditResult.skipped) {
|
|
43
|
+
result.score = 3
|
|
44
|
+
result.details.message = auditResult.skipReason || 'Skipped'
|
|
45
|
+
return result
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
result.details.sqlFunctionsFound = auditResult.details.sqlFunctionsFound
|
|
49
|
+
result.details.rpcCallsFound = auditResult.details.rpcCallsFound
|
|
50
|
+
result.details.rpcCallsChecked = auditResult.details.rpcCallsChecked
|
|
51
|
+
|
|
52
|
+
// Process findings
|
|
53
|
+
const criticals = auditResult.findings.filter(f => f.severity === 'critical')
|
|
54
|
+
const lows = auditResult.findings.filter(f => f.severity === 'low')
|
|
55
|
+
|
|
56
|
+
result.details.criticalMismatches = criticals.map(f => ({
|
|
57
|
+
file: f.file,
|
|
58
|
+
line: f.line,
|
|
59
|
+
function: f.rpcFunction,
|
|
60
|
+
extraParams: f.extraInTs,
|
|
61
|
+
expectedParams: f.sqlParams
|
|
62
|
+
}))
|
|
63
|
+
|
|
64
|
+
result.details.missingParams = lows.map(f => ({
|
|
65
|
+
file: f.file,
|
|
66
|
+
line: f.line,
|
|
67
|
+
function: f.rpcFunction,
|
|
68
|
+
tsParamCount: f.tsParams?.length,
|
|
69
|
+
sqlParamCount: f.sqlParams?.length
|
|
70
|
+
}))
|
|
71
|
+
|
|
72
|
+
// Score deductions
|
|
73
|
+
if (criticals.length > 0) {
|
|
74
|
+
const deduction = Math.min(3, criticals.length * 1.5)
|
|
75
|
+
result.score -= deduction
|
|
76
|
+
result.status = 'error'
|
|
77
|
+
result.details.message = `${criticals.length} RPC parameter mismatch(es) — will cause PGRST202 runtime errors`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (lows.length > 0 && result.status === 'ok') {
|
|
81
|
+
const deduction = Math.min(1, lows.length * 0.25)
|
|
82
|
+
result.score -= deduction
|
|
83
|
+
if (result.status === 'ok' && lows.length > 5) result.status = 'warning'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (result.status === 'ok') {
|
|
87
|
+
result.details.message = `${auditResult.details.rpcCallsChecked} RPC calls verified against SQL definitions`
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
result.score = Math.max(0, result.score)
|
|
91
|
+
return result
|
|
92
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Project Health Scanner
|
|
3
3
|
*
|
|
4
|
-
* Orchestrates all
|
|
4
|
+
* Orchestrates all 16 health checks and produces a HealthReport.
|
|
5
5
|
* This is the main entry point — consumers call scanProjectHealth().
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -21,6 +21,7 @@ import { check as checkClaudeMd } from './claude-md.js'
|
|
|
21
21
|
import { check as checkDopplerCompliance } from './doppler-compliance.js'
|
|
22
22
|
import { check as checkInfrastructureYml } from './infrastructure-yml.js'
|
|
23
23
|
import { check as checkFileOrganization } from './file-organization.js'
|
|
24
|
+
import { check as checkRpcParamMismatch } from './rpc-param-mismatch.js'
|
|
24
25
|
import { calculateHealthStatus } from './types.js'
|
|
25
26
|
|
|
26
27
|
/**
|
|
@@ -50,7 +51,8 @@ export async function scanProjectHealth(projectPath, projectName, options = {})
|
|
|
50
51
|
checkClaudeMd(projectPath),
|
|
51
52
|
checkDopplerCompliance(projectPath),
|
|
52
53
|
checkInfrastructureYml(projectPath),
|
|
53
|
-
checkFileOrganization(projectPath)
|
|
54
|
+
checkFileOrganization(projectPath),
|
|
55
|
+
checkRpcParamMismatch(projectPath)
|
|
54
56
|
])
|
|
55
57
|
|
|
56
58
|
const totalScore = checks.reduce((sum, c) => sum + c.score, 0)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @typedef {'plugins'|'mcps'|'git'|'tests'|'secrets'|'quality-toolkit'|'naming-conventions'|'rls-audit'|'gitignore'|'repo-visibility'|'vincifox-widget'|'stella-integration'|'claude-md'|'doppler-compliance'|'infrastructure-yml'|'file-organization'} HealthCheckType
|
|
8
|
+
* @typedef {'plugins'|'mcps'|'git'|'tests'|'secrets'|'quality-toolkit'|'naming-conventions'|'rls-audit'|'rpc-param-mismatch'|'gitignore'|'repo-visibility'|'vincifox-widget'|'stella-integration'|'claude-md'|'doppler-compliance'|'infrastructure-yml'|'file-organization'} HealthCheckType
|
|
9
9
|
*
|
|
10
10
|
* @typedef {'ok'|'warning'|'error'} HealthStatus
|
|
11
11
|
*
|
|
@@ -66,7 +66,7 @@ export function calculateHealthStatus(checks) {
|
|
|
66
66
|
|
|
67
67
|
// Critical checks override percentage
|
|
68
68
|
if (checks.some(c =>
|
|
69
|
-
(c.type === 'secrets' || c.type === 'rls-audit' || c.type === 'repo-visibility') && c.status === 'error'
|
|
69
|
+
(c.type === 'secrets' || c.type === 'rls-audit' || c.type === 'rpc-param-mismatch' || c.type === 'repo-visibility') && c.status === 'error'
|
|
70
70
|
)) {
|
|
71
71
|
return 'unhealthy'
|
|
72
72
|
}
|