@soulbatical/tetra-dev-toolkit 1.17.0 → 1.17.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.
|
@@ -280,6 +280,35 @@ function isWideOpen(using) {
|
|
|
280
280
|
return using.trim() === 'true' || using.trim() === '(true)'
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Forbidden patterns in RLS policies — these bypass RLS and defeat the purpose.
|
|
285
|
+
* Valid patterns (from sparkbuddy-live):
|
|
286
|
+
* - organization_id IN (SELECT auth_admin_organizations())
|
|
287
|
+
* - user_id = auth.uid()
|
|
288
|
+
* - USING(true) for public tables only
|
|
289
|
+
* - Subquery to parent table with org/user check
|
|
290
|
+
*
|
|
291
|
+
* Everything else that grants blanket access is a security hole.
|
|
292
|
+
*/
|
|
293
|
+
const FORBIDDEN_RLS_PATTERNS = [
|
|
294
|
+
{ pattern: /service_role/i, label: 'service_role bypass' },
|
|
295
|
+
{ pattern: /current_setting\s*\(\s*'role'/i, label: 'PostgreSQL role check bypass' },
|
|
296
|
+
{ pattern: /current_setting\s*\(\s*'request\.jwt\.claims'/i, label: 'JWT claims role bypass' },
|
|
297
|
+
{ pattern: /session_user\s*=\s*'postgres'/i, label: 'session_user postgres bypass' },
|
|
298
|
+
{ pattern: /current_user\s*=\s*'postgres'/i, label: 'current_user postgres bypass' },
|
|
299
|
+
{ pattern: /auth\.role\s*\(\)\s*=\s*'service_role'/i, label: 'auth.role() service_role bypass' },
|
|
300
|
+
{ pattern: /pg_has_role/i, label: 'pg_has_role bypass' },
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Check if a USING/WITH CHECK clause contains forbidden bypass patterns
|
|
305
|
+
* Returns array of { label } for each forbidden pattern found
|
|
306
|
+
*/
|
|
307
|
+
function findForbiddenPatterns(clause) {
|
|
308
|
+
if (!clause) return []
|
|
309
|
+
return FORBIDDEN_RLS_PATTERNS.filter(({ pattern }) => pattern.test(clause)).map(({ label }) => label)
|
|
310
|
+
}
|
|
311
|
+
|
|
283
312
|
export async function run(config, projectRoot) {
|
|
284
313
|
const results = {
|
|
285
314
|
passed: true,
|
|
@@ -446,6 +475,27 @@ export async function run(config, projectRoot) {
|
|
|
446
475
|
}
|
|
447
476
|
}
|
|
448
477
|
|
|
478
|
+
// CHECK 4b: No forbidden bypass patterns in any policy clause
|
|
479
|
+
for (const p of policies) {
|
|
480
|
+
const usingViolations = findForbiddenPatterns(p.using)
|
|
481
|
+
const checkViolations = findForbiddenPatterns(p.withCheck)
|
|
482
|
+
const allViolations = [...new Set([...usingViolations, ...checkViolations])]
|
|
483
|
+
|
|
484
|
+
if (allViolations.length > 0) {
|
|
485
|
+
results.passed = false
|
|
486
|
+
results.findings.push({
|
|
487
|
+
file: p.file,
|
|
488
|
+
line: 1,
|
|
489
|
+
type: 'rls-bypass-pattern',
|
|
490
|
+
severity: 'critical',
|
|
491
|
+
message: `Policy "${p.name}" on table "${tableName}" contains forbidden bypass pattern(s): ${allViolations.join(', ')}. RLS policies must ONLY use auth.uid(), auth_admin_organizations(), or parent-table subqueries. Service role bypasses RLS automatically — adding it to policies defeats the purpose.`,
|
|
492
|
+
fix: `Remove the bypass clause. Valid patterns: USING (organization_id IN (SELECT auth_admin_organizations())) or USING (user_id = auth.uid()).`
|
|
493
|
+
})
|
|
494
|
+
results.summary.critical++
|
|
495
|
+
results.summary.total++
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
449
499
|
// CHECK 5: Write policies (INSERT/UPDATE) must have WITH CHECK for org isolation
|
|
450
500
|
if (cfg.accessLevel === 'admin' || cfg.accessLevel === 'user') {
|
|
451
501
|
const writePoilciesWithoutCheck = [
|