@soulbatical/tetra-dev-toolkit 1.20.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +235 -238
- package/bin/tetra-setup.js +2 -172
- package/lib/checks/health/index.js +0 -1
- package/lib/checks/health/scanner.js +1 -3
- package/lib/checks/health/types.js +1 -1
- package/lib/checks/hygiene/stella-compliance.js +2 -2
- package/lib/checks/security/deprecated-supabase-admin.js +6 -15
- package/lib/checks/security/direct-supabase-client.js +4 -22
- package/lib/checks/security/frontend-supabase-queries.js +1 -1
- package/lib/checks/security/hardcoded-secrets.js +2 -5
- package/lib/checks/security/systemdb-whitelist.js +27 -116
- package/lib/config.js +1 -7
- package/lib/runner.js +7 -120
- package/package.json +2 -7
- package/bin/tetra-check-peers.js +0 -359
- package/bin/tetra-db-push.js +0 -91
- package/bin/tetra-migration-lint.js +0 -317
- package/bin/tetra-security-gate.js +0 -293
- package/bin/tetra-smoke.js +0 -532
- package/lib/checks/health/smoke-readiness.js +0 -150
- package/lib/checks/security/config-rls-alignment.js +0 -637
- package/lib/checks/security/mixed-db-usage.js +0 -204
- package/lib/checks/security/rls-live-audit.js +0 -255
- package/lib/checks/security/route-config-alignment.js +0 -342
- package/lib/checks/security/rpc-security-mode.js +0 -175
- package/lib/checks/security/tetra-core-compliance.js +0 -197
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tetra Core Compliance — HARD BLOCK
|
|
3
|
-
*
|
|
4
|
-
* If a project has @soulbatical/tetra-core as a dependency, it MUST use:
|
|
5
|
-
* 1. configureAuth() — sets up authentication middleware
|
|
6
|
-
* 2. authenticateToken — middleware on protected routes
|
|
7
|
-
* 3. adminDB/userDB/systemDB — db helpers (NOT raw createClient)
|
|
8
|
-
*
|
|
9
|
-
* If ANY of these are missing, the project is NOT secure.
|
|
10
|
-
* There is no "skip" — if you have tetra-core, you use it fully or not at all.
|
|
11
|
-
*
|
|
12
|
-
* This check also detects projects that SHOULD have tetra-core but don't:
|
|
13
|
-
* - Has a backend/ dir with Express + Supabase → MUST have tetra-core
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { readFileSync, existsSync } from 'fs'
|
|
17
|
-
import { join } from 'path'
|
|
18
|
-
import { glob } from 'glob'
|
|
19
|
-
|
|
20
|
-
export const meta = {
|
|
21
|
-
id: 'tetra-core-compliance',
|
|
22
|
-
name: 'Tetra Core Compliance',
|
|
23
|
-
category: 'security',
|
|
24
|
-
severity: 'critical',
|
|
25
|
-
description: 'Ensures projects using @soulbatical/tetra-core implement ALL required security patterns — auth, middleware, db helpers'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function run(config, projectRoot) {
|
|
29
|
-
const results = {
|
|
30
|
-
passed: true,
|
|
31
|
-
findings: [],
|
|
32
|
-
summary: { total: 0, critical: 0, high: 0, medium: 0, low: 0 }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// ─── Step 1: Does this project have tetra-core? ────────────────
|
|
36
|
-
|
|
37
|
-
const packageJsonPaths = [
|
|
38
|
-
join(projectRoot, 'package.json'),
|
|
39
|
-
join(projectRoot, 'backend', 'package.json')
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
let hasTetraCore = false
|
|
43
|
-
let tetraCoreLocation = null
|
|
44
|
-
|
|
45
|
-
for (const pkgPath of packageJsonPaths) {
|
|
46
|
-
if (!existsSync(pkgPath)) continue
|
|
47
|
-
try {
|
|
48
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
49
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
50
|
-
if (deps['@soulbatical/tetra-core']) {
|
|
51
|
-
hasTetraCore = true
|
|
52
|
-
tetraCoreLocation = pkgPath.replace(projectRoot + '/', '')
|
|
53
|
-
break
|
|
54
|
-
}
|
|
55
|
-
} catch { /* skip */ }
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ─── Step 2: Check if project SHOULD have tetra-core ───────────
|
|
59
|
-
|
|
60
|
-
if (!hasTetraCore) {
|
|
61
|
-
// Check if this is an Express + Supabase backend that should have it
|
|
62
|
-
const backendDirs = ['backend/src', 'src']
|
|
63
|
-
let hasExpress = false
|
|
64
|
-
let hasSupabase = false
|
|
65
|
-
|
|
66
|
-
for (const dir of backendDirs) {
|
|
67
|
-
const pkgPath = dir === 'src' ? join(projectRoot, 'package.json') : join(projectRoot, 'backend', 'package.json')
|
|
68
|
-
if (!existsSync(pkgPath)) continue
|
|
69
|
-
try {
|
|
70
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
71
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
72
|
-
if (deps['express']) hasExpress = true
|
|
73
|
-
if (deps['@supabase/supabase-js']) hasSupabase = true
|
|
74
|
-
} catch { /* skip */ }
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (hasExpress && hasSupabase) {
|
|
78
|
-
results.passed = false
|
|
79
|
-
results.findings.push({
|
|
80
|
-
type: 'missing-tetra-core',
|
|
81
|
-
severity: 'critical',
|
|
82
|
-
message: 'Project has Express + Supabase but does NOT have @soulbatical/tetra-core. This means NO standard auth middleware, NO db helpers, NO RLS enforcement. Install tetra-core and follow the architecture guide.',
|
|
83
|
-
fix: 'npm install @soulbatical/tetra-core && see stella_howto_get slug="tetra-architecture-guide"'
|
|
84
|
-
})
|
|
85
|
-
results.summary.critical++
|
|
86
|
-
results.summary.total++
|
|
87
|
-
} else {
|
|
88
|
-
// Not a backend project, skip
|
|
89
|
-
results.skipped = true
|
|
90
|
-
results.skipReason = 'Not a Tetra backend project (no Express + Supabase)'
|
|
91
|
-
return results
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return results
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ─── Step 3: Has tetra-core → check FULL compliance ────────────
|
|
98
|
-
|
|
99
|
-
const backendSrc = existsSync(join(projectRoot, 'backend', 'src')) ? 'backend/src' : 'src'
|
|
100
|
-
|
|
101
|
-
// Check 3a: configureAuth() is called somewhere
|
|
102
|
-
const tsFiles = await glob(`${backendSrc}/**/*.ts`, {
|
|
103
|
-
cwd: projectRoot,
|
|
104
|
-
ignore: ['**/node_modules/**', '**/*.test.ts', '**/*.spec.ts', '**/*.d.ts']
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
let hasConfigureAuth = false
|
|
108
|
-
let hasAuthenticateToken = false
|
|
109
|
-
let hasDbHelpers = false
|
|
110
|
-
let dbHelperImports = { adminDB: false, userDB: false, systemDB: false, publicDB: false, superadminDB: false }
|
|
111
|
-
let hasRawCreateClient = false
|
|
112
|
-
let rawCreateClientFiles = []
|
|
113
|
-
|
|
114
|
-
for (const file of tsFiles) {
|
|
115
|
-
try {
|
|
116
|
-
const content = readFileSync(join(projectRoot, file), 'utf-8')
|
|
117
|
-
|
|
118
|
-
if (content.includes('configureAuth')) hasConfigureAuth = true
|
|
119
|
-
if (content.includes('authenticateToken')) hasAuthenticateToken = true
|
|
120
|
-
|
|
121
|
-
// Check for db helper usage
|
|
122
|
-
if (/(?:import|from).*(?:adminDB|userDB|systemDB|publicDB|superadminDB)/.test(content)) {
|
|
123
|
-
hasDbHelpers = true
|
|
124
|
-
if (content.includes('adminDB')) dbHelperImports.adminDB = true
|
|
125
|
-
if (content.includes('userDB')) dbHelperImports.userDB = true
|
|
126
|
-
if (content.includes('systemDB')) dbHelperImports.systemDB = true
|
|
127
|
-
if (content.includes('publicDB')) dbHelperImports.publicDB = true
|
|
128
|
-
if (content.includes('superadminDB')) dbHelperImports.superadminDB = true
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Check for raw createClient usage (should be caught by direct-supabase-client check too)
|
|
132
|
-
if (/import\s*\{[^}]*createClient[^}]*\}\s*from\s*['"]@supabase\/supabase-js['"]/.test(content)) {
|
|
133
|
-
if (!/import\s+type/.test(content)) {
|
|
134
|
-
// Not in core wrapper files
|
|
135
|
-
if (!/core\//.test(file) && !/SupabaseUserClient/.test(file) && !/scripts\//.test(file)) {
|
|
136
|
-
hasRawCreateClient = true
|
|
137
|
-
rawCreateClientFiles.push(file)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
} catch { /* skip */ }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// ─── Report findings ──────────────────────────────────────────
|
|
145
|
-
|
|
146
|
-
if (!hasConfigureAuth) {
|
|
147
|
-
results.passed = false
|
|
148
|
-
results.findings.push({
|
|
149
|
-
type: 'missing-configureAuth',
|
|
150
|
-
severity: 'critical',
|
|
151
|
-
message: 'Project has @soulbatical/tetra-core but NEVER calls configureAuth(). This means the auth middleware is not initialized — all routes are potentially unprotected.',
|
|
152
|
-
fix: 'Create an auth-config.ts that calls configureAuth({ loadUserContext, roleHierarchy }). See sparkbuddy-live/backend/src/auth-config.ts for reference.'
|
|
153
|
-
})
|
|
154
|
-
results.summary.critical++
|
|
155
|
-
results.summary.total++
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!hasAuthenticateToken) {
|
|
159
|
-
results.passed = false
|
|
160
|
-
results.findings.push({
|
|
161
|
-
type: 'missing-authenticateToken',
|
|
162
|
-
severity: 'critical',
|
|
163
|
-
message: 'Project has @soulbatical/tetra-core but NO route uses authenticateToken middleware. All API endpoints are unprotected.',
|
|
164
|
-
fix: 'Add authenticateToken middleware to all protected routes: router.use(authenticateToken, requireOrganizationAdmin)'
|
|
165
|
-
})
|
|
166
|
-
results.summary.critical++
|
|
167
|
-
results.summary.total++
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (!hasDbHelpers) {
|
|
171
|
-
results.passed = false
|
|
172
|
-
results.findings.push({
|
|
173
|
-
type: 'missing-db-helpers',
|
|
174
|
-
severity: 'critical',
|
|
175
|
-
message: 'Project has @soulbatical/tetra-core but does NOT use any db helpers (adminDB, userDB, systemDB, publicDB). Database access has no RLS enforcement.',
|
|
176
|
-
fix: 'Use adminDB(req) for admin routes, userDB(req) for user routes, systemDB(context) for system operations. See stella_howto_get slug="tetra-architecture-guide"'
|
|
177
|
-
})
|
|
178
|
-
results.summary.critical++
|
|
179
|
-
results.summary.total++
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Info: which helpers are used
|
|
183
|
-
const usedHelpers = Object.entries(dbHelperImports).filter(([_, used]) => used).map(([name]) => name)
|
|
184
|
-
const unusedHelpers = Object.entries(dbHelperImports).filter(([_, used]) => !used).map(([name]) => name)
|
|
185
|
-
|
|
186
|
-
results.info = {
|
|
187
|
-
tetraCoreLocation,
|
|
188
|
-
configureAuth: hasConfigureAuth,
|
|
189
|
-
authenticateToken: hasAuthenticateToken,
|
|
190
|
-
dbHelpers: {
|
|
191
|
-
used: usedHelpers,
|
|
192
|
-
unused: unusedHelpers
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return results
|
|
197
|
-
}
|