@luanpdd/kit-mcp 1.20.0 → 1.21.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/LICENSE +21 -21
- package/README.md +648 -648
- package/gates/dept-cycle-prevention.md +179 -0
- package/gates/multi-tenant-rls-coverage.md +102 -0
- package/gates/service-role-not-in-user-facing.md +113 -0
- package/kit/COMANDOS.md +138 -138
- package/kit/README.md +52 -52
- package/kit/agents/advisor-researcher.md +106 -106
- package/kit/agents/assumptions-analyzer.md +107 -107
- package/kit/agents/audit-log-implementer.md +175 -0
- package/kit/agents/b2b-saas-architect.md +156 -0
- package/kit/agents/codebase-mapper.md +768 -768
- package/kit/agents/crm-pipeline-implementer.md +150 -0
- package/kit/agents/debugger.md +772 -772
- package/kit/agents/evolution-go-integrator.md +179 -0
- package/kit/agents/example-reviewer.md +21 -21
- package/kit/agents/executor.md +523 -523
- package/kit/agents/integration-checker.md +200 -200
- package/kit/agents/invite-flow-implementer.md +137 -0
- package/kit/agents/lgpd-compliance-auditor.md +206 -0
- package/kit/agents/multi-tenant-isolation-auditor.md +243 -0
- package/kit/agents/multi-tenant-rls-writer.md +262 -0
- package/kit/agents/nyquist-auditor.md +178 -178
- package/kit/agents/org-onboarding-implementer.md +202 -0
- package/kit/agents/phase-researcher.md +696 -696
- package/kit/agents/plan-checker.md +272 -272
- package/kit/agents/planner.md +891 -891
- package/kit/agents/project-researcher.md +652 -652
- package/kit/agents/research-synthesizer.md +245 -245
- package/kit/agents/roadmapper.md +677 -677
- package/kit/agents/super-admin-implementer.md +182 -0
- package/kit/agents/ui-auditor.md +437 -437
- package/kit/agents/ui-checker.md +302 -302
- package/kit/agents/ui-researcher.md +355 -355
- package/kit/agents/user-profiler.md +175 -175
- package/kit/agents/verifier.md +728 -728
- package/kit/commands/adicionar-backlog.md +75 -75
- package/kit/commands/adicionar-fase.md +42 -42
- package/kit/commands/adicionar-tarefa.md +45 -45
- package/kit/commands/adicionar-testes.md +41 -41
- package/kit/commands/ajuda.md +21 -21
- package/kit/commands/atualizar.md +37 -37
- package/kit/commands/auditar-marco.md +179 -179
- package/kit/commands/auditar-uat.md +23 -23
- package/kit/commands/autonomo.md +40 -40
- package/kit/commands/branch-pr.md +24 -24
- package/kit/commands/concluir-marco.md +247 -247
- package/kit/commands/configuracoes.md +36 -36
- package/kit/commands/definir-perfil.md +10 -10
- package/kit/commands/depurar.md +190 -190
- package/kit/commands/discutir-fase.md +131 -131
- package/kit/commands/entrar-discord.md +17 -17
- package/kit/commands/estatisticas.md +18 -18
- package/kit/commands/example-greeting.md +33 -33
- package/kit/commands/executar-fase.md +58 -58
- package/kit/commands/expresso.md +56 -56
- package/kit/commands/fase-ui.md +34 -34
- package/kit/commands/fazer.md +57 -57
- package/kit/commands/fio.md +125 -125
- package/kit/commands/fluxos-trabalho.md +64 -64
- package/kit/commands/forense.md +176 -176
- package/kit/commands/gerenciador.md +38 -38
- package/kit/commands/inserir-fase.md +31 -31
- package/kit/commands/limpeza.md +17 -17
- package/kit/commands/listar-hipoteses-fase.md +45 -45
- package/kit/commands/listar-workspaces.md +18 -18
- package/kit/commands/mapear-codebase.md +70 -70
- package/kit/commands/multi-tenant.md +163 -0
- package/kit/commands/nota.md +33 -33
- package/kit/commands/novo-marco.md +43 -43
- package/kit/commands/novo-projeto.md +41 -41
- package/kit/commands/novo-workspace.md +43 -43
- package/kit/commands/pausar-trabalho.md +37 -37
- package/kit/commands/perfil-usuario.md +45 -45
- package/kit/commands/pesquisar-fase.md +195 -195
- package/kit/commands/planejar-fase.md +67 -67
- package/kit/commands/planejar-lacunas.md +33 -33
- package/kit/commands/plantar-ideia.md +25 -25
- package/kit/commands/progresso.md +24 -24
- package/kit/commands/proximo.md +30 -30
- package/kit/commands/publicar.md +490 -490
- package/kit/commands/rapido.md +35 -35
- package/kit/commands/reaplicar-patches.md +124 -124
- package/kit/commands/relatorio-sessao.md +19 -19
- package/kit/commands/remover-fase.md +31 -31
- package/kit/commands/remover-workspace.md +26 -26
- package/kit/commands/resumo-marco.md +50 -50
- package/kit/commands/retomar-trabalho.md +40 -40
- package/kit/commands/revisar-backlog.md +60 -60
- package/kit/commands/revisar-ui.md +32 -32
- package/kit/commands/revisar.md +37 -37
- package/kit/commands/saude.md +21 -21
- package/kit/commands/setup-notion.md +93 -93
- package/kit/commands/sync-main.md +68 -68
- package/kit/commands/validar-fase.md +35 -35
- package/kit/commands/verificar-tarefas.md +44 -44
- package/kit/commands/verificar-trabalho.md +64 -64
- package/kit/file-manifest.json +30 -3
- package/kit/framework/bin/lib/commands.cjs +959 -959
- package/kit/framework/bin/lib/config.cjs +442 -442
- package/kit/framework/bin/lib/core.cjs +1230 -1230
- package/kit/framework/bin/lib/frontmatter.cjs +336 -336
- package/kit/framework/bin/lib/init.cjs +1442 -1442
- package/kit/framework/bin/lib/milestone.cjs +252 -252
- package/kit/framework/bin/lib/model-profiles.cjs +68 -68
- package/kit/framework/bin/lib/phase.cjs +888 -888
- package/kit/framework/bin/lib/profile-output.cjs +952 -952
- package/kit/framework/bin/lib/profile-pipeline.cjs +539 -539
- package/kit/framework/bin/lib/roadmap.cjs +329 -329
- package/kit/framework/bin/lib/security.cjs +382 -382
- package/kit/framework/bin/lib/state.cjs +1031 -1031
- package/kit/framework/bin/lib/template.cjs +222 -222
- package/kit/framework/bin/lib/uat.cjs +282 -282
- package/kit/framework/bin/lib/verify.cjs +888 -888
- package/kit/framework/bin/lib/workstream.cjs +491 -491
- package/kit/framework/bin/tools.cjs +918 -918
- package/kit/framework/commands/workstreams.md +63 -63
- package/kit/framework/references/checkpoints.md +778 -778
- package/kit/framework/references/continuation-format.md +249 -249
- package/kit/framework/references/decimal-phase-calculation.md +64 -64
- package/kit/framework/references/git-integration.md +295 -295
- package/kit/framework/references/git-planning-commit.md +38 -38
- package/kit/framework/references/model-profile-resolution.md +36 -36
- package/kit/framework/references/model-profiles.md +139 -139
- package/kit/framework/references/phase-argument-parsing.md +61 -61
- package/kit/framework/references/planning-config.md +202 -202
- package/kit/framework/references/questioning.md +162 -162
- package/kit/framework/references/tdd.md +263 -263
- package/kit/framework/references/ui-brand.md +160 -160
- package/kit/framework/references/user-profiling.md +657 -657
- package/kit/framework/references/verification-patterns.md +612 -612
- package/kit/framework/references/workstream-flag.md +58 -58
- package/kit/framework/templates/DEBUG.md +164 -164
- package/kit/framework/templates/UAT.md +265 -265
- package/kit/framework/templates/UI-SPEC.md +100 -100
- package/kit/framework/templates/VALIDATION.md +76 -76
- package/kit/framework/templates/claude-md.md +122 -122
- package/kit/framework/templates/codebase/architecture.md +185 -185
- package/kit/framework/templates/codebase/concerns.md +205 -205
- package/kit/framework/templates/codebase/conventions.md +204 -204
- package/kit/framework/templates/codebase/integrations.md +192 -192
- package/kit/framework/templates/codebase/stack.md +158 -158
- package/kit/framework/templates/codebase/structure.md +199 -199
- package/kit/framework/templates/codebase/testing.md +301 -301
- package/kit/framework/templates/config.json +44 -44
- package/kit/framework/templates/context.md +352 -352
- package/kit/framework/templates/continue-here.md +78 -78
- package/kit/framework/templates/copilot-instructions.md +7 -7
- package/kit/framework/templates/debug-subagent-prompt.md +91 -91
- package/kit/framework/templates/dev-preferences.md +20 -20
- package/kit/framework/templates/discovery.md +146 -146
- package/kit/framework/templates/discussion-log.md +63 -63
- package/kit/framework/templates/milestone-archive.md +123 -123
- package/kit/framework/templates/milestone.md +115 -115
- package/kit/framework/templates/phase-prompt.md +610 -610
- package/kit/framework/templates/planner-subagent-prompt.md +117 -117
- package/kit/framework/templates/project.md +186 -186
- package/kit/framework/templates/requirements.md +231 -231
- package/kit/framework/templates/research-project/ARCHITECTURE.md +204 -204
- package/kit/framework/templates/research-project/FEATURES.md +147 -147
- package/kit/framework/templates/research-project/PITFALLS.md +200 -200
- package/kit/framework/templates/research-project/STACK.md +120 -120
- package/kit/framework/templates/research-project/SUMMARY.md +170 -170
- package/kit/framework/templates/research.md +419 -419
- package/kit/framework/templates/retrospective.md +54 -54
- package/kit/framework/templates/roadmap.md +202 -202
- package/kit/framework/templates/state.md +176 -176
- package/kit/framework/templates/summary-complex.md +59 -59
- package/kit/framework/templates/summary-minimal.md +41 -41
- package/kit/framework/templates/summary-standard.md +48 -48
- package/kit/framework/templates/summary.md +209 -209
- package/kit/framework/templates/user-profile.md +146 -146
- package/kit/framework/templates/user-setup.md +256 -256
- package/kit/framework/templates/verification-report.md +258 -258
- package/kit/framework/workflows/add-phase.md +112 -112
- package/kit/framework/workflows/add-tests.md +351 -351
- package/kit/framework/workflows/add-todo.md +158 -158
- package/kit/framework/workflows/audit-milestone.md +340 -340
- package/kit/framework/workflows/audit-uat.md +109 -109
- package/kit/framework/workflows/autonomous.md +891 -891
- package/kit/framework/workflows/check-todos.md +177 -177
- package/kit/framework/workflows/cleanup.md +152 -152
- package/kit/framework/workflows/complete-milestone.md +696 -696
- package/kit/framework/workflows/diagnose-issues.md +231 -231
- package/kit/framework/workflows/discovery-phase.md +289 -289
- package/kit/framework/workflows/discuss-phase-assumptions.md +653 -653
- package/kit/framework/workflows/discuss-phase.md +784 -784
- package/kit/framework/workflows/do.md +104 -104
- package/kit/framework/workflows/execute-phase.md +838 -838
- package/kit/framework/workflows/execute-plan.md +510 -510
- package/kit/framework/workflows/fast.md +102 -102
- package/kit/framework/workflows/forensics.md +265 -265
- package/kit/framework/workflows/health.md +181 -181
- package/kit/framework/workflows/help.md +619 -619
- package/kit/framework/workflows/insert-phase.md +130 -130
- package/kit/framework/workflows/list-phase-assumptions.md +178 -178
- package/kit/framework/workflows/list-workspaces.md +56 -56
- package/kit/framework/workflows/manager.md +362 -362
- package/kit/framework/workflows/map-codebase.md +377 -377
- package/kit/framework/workflows/milestone-summary.md +223 -223
- package/kit/framework/workflows/new-milestone.md +486 -486
- package/kit/framework/workflows/new-project.md +1159 -1159
- package/kit/framework/workflows/new-workspace.md +237 -237
- package/kit/framework/workflows/next.md +97 -97
- package/kit/framework/workflows/node-repair.md +92 -92
- package/kit/framework/workflows/note.md +156 -156
- package/kit/framework/workflows/pause-work.md +176 -176
- package/kit/framework/workflows/plan-milestone-gaps.md +273 -273
- package/kit/framework/workflows/plan-phase.md +765 -765
- package/kit/framework/workflows/plant-seed.md +169 -169
- package/kit/framework/workflows/pr-branch.md +129 -129
- package/kit/framework/workflows/profile-user.md +450 -450
- package/kit/framework/workflows/progress.md +507 -507
- package/kit/framework/workflows/quick.md +757 -757
- package/kit/framework/workflows/remove-phase.md +155 -155
- package/kit/framework/workflows/remove-workspace.md +90 -90
- package/kit/framework/workflows/research-phase.md +82 -82
- package/kit/framework/workflows/resume-project.md +326 -326
- package/kit/framework/workflows/review.md +228 -228
- package/kit/framework/workflows/session-report.md +146 -146
- package/kit/framework/workflows/settings.md +283 -283
- package/kit/framework/workflows/ship.md +228 -228
- package/kit/framework/workflows/stats.md +60 -60
- package/kit/framework/workflows/transition.md +671 -671
- package/kit/framework/workflows/ui-phase.md +302 -302
- package/kit/framework/workflows/ui-review.md +165 -165
- package/kit/framework/workflows/update.md +323 -323
- package/kit/framework/workflows/validate-phase.md +174 -174
- package/kit/framework/workflows/verify-phase.md +252 -252
- package/kit/framework/workflows/verify-work.md +637 -637
- package/kit/hooks/check-update.js +118 -118
- package/kit/hooks/context-monitor.js +163 -163
- package/kit/hooks/prompt-guard.js +103 -103
- package/kit/hooks/statusline.js +125 -125
- package/kit/hooks/workflow-guard.js +101 -101
- package/kit/settings.json +45 -45
- package/kit/skills/_shared-multi-tenant/glossary.md +186 -0
- package/kit/skills/audit-log-multi-tenant/SKILL.md +334 -0
- package/kit/skills/b2b-saas-architecture/SKILL.md +300 -0
- package/kit/skills/crm-lead-pipeline-patterns/SKILL.md +326 -0
- package/kit/skills/evolution-go-whatsapp-integration/SKILL.md +322 -0
- package/kit/skills/example-skill/SKILL.md +42 -42
- package/kit/skills/lgpd-multi-tenant-compliance/SKILL.md +340 -0
- package/kit/skills/member-invite-flow/SKILL.md +305 -0
- package/kit/skills/member-management-react-shadcn/SKILL.md +328 -0
- package/kit/skills/multi-tenant-performance-scaling/SKILL.md +312 -0
- package/kit/skills/multi-tenant-rls-hierarchy/SKILL.md +338 -0
- package/kit/skills/org-onboarding-flow/SKILL.md +257 -0
- package/kit/skills/org-switcher-react-pattern/SKILL.md +349 -0
- package/kit/skills/permission-gate-react-pattern/SKILL.md +271 -0
- package/kit/skills/rbac-permissions-matrix-supabase/SKILL.md +301 -0
- package/kit/skills/super-admin-platform-pattern/SKILL.md +322 -0
- package/kit/skills/whatsapp-conversation-state-machine/SKILL.md +287 -0
- package/package.json +63 -63
- package/src/core/kit.js +216 -216
- package/src/core/reflect.js +247 -247
- package/src/core/reverse-sync.js +372 -372
- package/src/core/sync.js +418 -418
- package/src/core/watch.js +121 -121
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: dept-cycle-prevention
|
|
3
|
+
stage: pre-verify
|
|
4
|
+
blocking: true
|
|
5
|
+
description: Detecta tabela departments (ou similar) com parent_id FK self-referencial mas sem trigger anti-cycle. Loop circular em dept hierarchy esgota connection pool via WITH RECURSIVE infinito. Skip se projeto não tem supabase/migrations/.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Department Cycle Prevention gate
|
|
9
|
+
|
|
10
|
+
**When to run:** pre-verify (blocking — anti-pitfall P0 multi-tenant hierarchy).
|
|
11
|
+
|
|
12
|
+
## Check
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
# PT-BR: detecta departments com parent_id self-referencial sem trigger anti-cycle.
|
|
17
|
+
# Anti-pitfall #3 multi-tenant: dept hierarchy com loop circular (A.parent=B, B.parent=A) → WITH RECURSIVE infinito → connection pool exhaustion.
|
|
18
|
+
# Bash 3.2-portable (macOS default).
|
|
19
|
+
set -e
|
|
20
|
+
|
|
21
|
+
MIGRATIONS_DIR="supabase/migrations"
|
|
22
|
+
|
|
23
|
+
if [ ! -d "$MIGRATIONS_DIR" ]; then
|
|
24
|
+
echo "INFO: $MIGRATIONS_DIR não existe — projeto não usa Supabase migrations. Gate skipped."
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# PT-BR: nomes comuns de tabelas hierárquicas (departments + variantes)
|
|
29
|
+
HIERARCHY_TABLE_PATTERNS="departments|teams|groups|categories|nodes|tree"
|
|
30
|
+
|
|
31
|
+
VIOLATIONS=0
|
|
32
|
+
VIOLATIONS_DETAIL=""
|
|
33
|
+
|
|
34
|
+
# PT-BR: iterar migrations em ordem cronológica
|
|
35
|
+
MIGRATION_FILES=$(ls "$MIGRATIONS_DIR"/*.sql 2>/dev/null | sort)
|
|
36
|
+
|
|
37
|
+
if [ -z "$MIGRATION_FILES" ]; then
|
|
38
|
+
echo "INFO: nenhum arquivo .sql em $MIGRATIONS_DIR — gate skipped."
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# PT-BR: encontrar tabelas com parent_id auto-referencial (heurística: parent_id + REFERENCES <self>)
|
|
43
|
+
SELF_REF_TABLES=""
|
|
44
|
+
|
|
45
|
+
for f in $MIGRATION_FILES; do
|
|
46
|
+
# PT-BR: detecta padrão "parent_id ... references public.<table>(id)" onde <table> bate com nome da tabela sendo criada
|
|
47
|
+
# (case-insensitive, multi-line awk porque DDL pode ter quebras de linha)
|
|
48
|
+
TABLES_IN_FILE=$(awk '
|
|
49
|
+
BEGIN { in_create = 0; current_table = "" }
|
|
50
|
+
/create[ \t]+table[ \t]+(if[ \t]+not[ \t]+exists[ \t]+)?[a-z_]+\.[a-z_]+/ {
|
|
51
|
+
in_create = 1
|
|
52
|
+
match($0, /create[ \t]+table[ \t]+(if[ \t]+not[ \t]+exists[ \t]+)?([a-z_]+\.[a-z_]+)/)
|
|
53
|
+
if (RSTART > 0) {
|
|
54
|
+
# extrair só o último match group (table name)
|
|
55
|
+
s = substr($0, RSTART, RLENGTH)
|
|
56
|
+
n = split(s, parts, /[ \t]+/)
|
|
57
|
+
current_table = parts[n]
|
|
58
|
+
}
|
|
59
|
+
next
|
|
60
|
+
}
|
|
61
|
+
in_create && /parent_id[ \t]+uuid[ \t]+references[ \t]+([a-z_]+\.[a-z_]+)/ {
|
|
62
|
+
match($0, /references[ \t]+([a-z_]+\.[a-z_]+)/)
|
|
63
|
+
if (RSTART > 0) {
|
|
64
|
+
ref_table = substr($0, RSTART + 11, RLENGTH - 11)
|
|
65
|
+
gsub(/[ \t]/, "", ref_table)
|
|
66
|
+
if (ref_table == current_table) {
|
|
67
|
+
print current_table
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/;[ \t]*$/ && in_create { in_create = 0; current_table = "" }
|
|
72
|
+
' "$f" 2>/dev/null)
|
|
73
|
+
|
|
74
|
+
if [ -n "$TABLES_IN_FILE" ]; then
|
|
75
|
+
SELF_REF_TABLES="$SELF_REF_TABLES
|
|
76
|
+
$TABLES_IN_FILE"
|
|
77
|
+
fi
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
# PT-BR: filtrar entries vazias
|
|
81
|
+
SELF_REF_TABLES=$(echo "$SELF_REF_TABLES" | grep -v "^$" | sort -u)
|
|
82
|
+
|
|
83
|
+
if [ -z "$SELF_REF_TABLES" ]; then
|
|
84
|
+
echo "INFO: nenhuma tabela com parent_id self-referencial detectada — gate skipped."
|
|
85
|
+
exit 0
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# PT-BR: para cada tabela self-ref, verificar se há trigger ou function anti-cycle
|
|
89
|
+
for table in $SELF_REF_TABLES; do
|
|
90
|
+
# PT-BR: extrair só nome da tabela (sem schema)
|
|
91
|
+
table_name=$(echo "$table" | awk -F. '{print $2}')
|
|
92
|
+
|
|
93
|
+
# PT-BR: heurística: procurar trigger com nome contendo cycle/loop/recursion + tabela
|
|
94
|
+
CYCLE_GUARD_FOUND=0
|
|
95
|
+
for f in $MIGRATION_FILES; do
|
|
96
|
+
if grep -iE "(create[ \t]+(or[ \t]+replace[ \t]+)?(function|trigger))[ \t]+[a-z_]*(cycle|loop|recurs|hierarchy_check|anti_cycle)" "$f" 2>/dev/null \
|
|
97
|
+
| grep -iqE "$table_name|$(echo "$table" | tr '.' '_')"; then
|
|
98
|
+
CYCLE_GUARD_FOUND=1
|
|
99
|
+
break
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# PT-BR: pattern alternativo: trigger genérico que menciona a tabela e WITH RECURSIVE em corpo
|
|
103
|
+
if grep -iqE "create[ \t]+trigger.*on[ \t]+$table" "$f" 2>/dev/null \
|
|
104
|
+
&& grep -iqE "with[ \t]+recursive.*parent_id" "$f" 2>/dev/null; then
|
|
105
|
+
CYCLE_GUARD_FOUND=1
|
|
106
|
+
break
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
109
|
+
|
|
110
|
+
if [ "$CYCLE_GUARD_FOUND" -eq 0 ]; then
|
|
111
|
+
VIOLATIONS=$((VIOLATIONS + 1))
|
|
112
|
+
VIOLATIONS_DETAIL="${VIOLATIONS_DETAIL}
|
|
113
|
+
Tabela '$table' tem parent_id self-referencial mas sem trigger anti-cycle detectado"
|
|
114
|
+
fi
|
|
115
|
+
done
|
|
116
|
+
|
|
117
|
+
if [ "$VIOLATIONS" -eq 0 ]; then
|
|
118
|
+
echo "PASS: todas as tabelas hierárquicas têm proteção anti-cycle."
|
|
119
|
+
exit 0
|
|
120
|
+
else
|
|
121
|
+
echo "FAIL: $VIOLATIONS tabela(s) hierárquica(s) sem trigger anti-cycle:$VIOLATIONS_DETAIL"
|
|
122
|
+
echo ""
|
|
123
|
+
echo "Fix: adicionar trigger BEFORE INSERT/UPDATE que detecta cycle via WITH RECURSIVE:"
|
|
124
|
+
cat << 'EOF'
|
|
125
|
+
|
|
126
|
+
create or replace function private.check_no_dept_cycle()
|
|
127
|
+
returns trigger
|
|
128
|
+
language plpgsql
|
|
129
|
+
security invoker
|
|
130
|
+
set search_path = ''
|
|
131
|
+
as $$
|
|
132
|
+
declare
|
|
133
|
+
cycle_detected boolean;
|
|
134
|
+
begin
|
|
135
|
+
if new.parent_id is null then return new; end if;
|
|
136
|
+
|
|
137
|
+
with recursive ancestors as (
|
|
138
|
+
select id, parent_id, 1 as depth from public.departments where id = new.parent_id
|
|
139
|
+
union all
|
|
140
|
+
select d.id, d.parent_id, a.depth + 1
|
|
141
|
+
from public.departments d
|
|
142
|
+
join ancestors a on d.id = a.parent_id
|
|
143
|
+
where a.depth < 10 -- max 10 níveis
|
|
144
|
+
)
|
|
145
|
+
select exists (select 1 from ancestors where id = new.id) into cycle_detected;
|
|
146
|
+
|
|
147
|
+
if cycle_detected then
|
|
148
|
+
raise exception 'department hierarchy cycle detected: % cannot be parent of %',
|
|
149
|
+
new.parent_id, new.id;
|
|
150
|
+
end if;
|
|
151
|
+
|
|
152
|
+
return new;
|
|
153
|
+
end;
|
|
154
|
+
$$;
|
|
155
|
+
|
|
156
|
+
create trigger check_no_dept_cycle_trigger
|
|
157
|
+
before insert or update of parent_id on public.departments
|
|
158
|
+
for each row execute function private.check_no_dept_cycle();
|
|
159
|
+
|
|
160
|
+
EOF
|
|
161
|
+
echo "Ref: kit/skills/_shared-multi-tenant/glossary.md (Department Hierarchy)"
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Verdict
|
|
167
|
+
|
|
168
|
+
- **passed** — todas tabelas hierárquicas têm proteção anti-cycle → continuar
|
|
169
|
+
- **block** — apresentar tabelas violadoras + DDL pronto do trigger anti-cycle
|
|
170
|
+
|
|
171
|
+
## Notes
|
|
172
|
+
|
|
173
|
+
Detecção é heurística baseada em naming (`parent_id` + `references <self_table>`). Pode produzir:
|
|
174
|
+
- **Falso-negativo** se a coluna se chamar `parent` em vez de `parent_id`, ou referenciar tabela diferente (não self-ref)
|
|
175
|
+
- **Falso-positivo** se o nome do trigger não contém palavras-chave (`cycle`, `loop`, `recurs`, `anti_cycle`) — neste caso, renomear o trigger ou estender a allowlist do gate
|
|
176
|
+
|
|
177
|
+
Tabelas hierárquicas tipicamente afetadas: `departments`, `teams`, `groups`, `categories`, `nodes`, `tree`.
|
|
178
|
+
|
|
179
|
+
Limit recursivo padrão sugerido: 10 níveis. Hierarquia mais profunda que isso indica modelagem questionável (Linear/Notion suportam até 5 níveis).
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: multi-tenant-rls-coverage
|
|
3
|
+
stage: pre-verify
|
|
4
|
+
blocking: true
|
|
5
|
+
description: Detecta CREATE TABLE em supabase/migrations/ sem ENABLE ROW LEVEL SECURITY no mesmo arquivo. Cross-tenant data leak silencioso é a falha #1 de apps multi-tenant Supabase. Skip se projeto não tem supabase/migrations/.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Multi-Tenant RLS Coverage gate
|
|
9
|
+
|
|
10
|
+
**When to run:** pre-verify (blocking — multi-tenant phase não verifica até cobertura completa).
|
|
11
|
+
|
|
12
|
+
## Check
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
# PT-BR: detecta CREATE TABLE em supabase/migrations/ sem ENABLE ROW LEVEL SECURITY no mesmo arquivo.
|
|
17
|
+
# Anti-pitfall #1 multi-tenant: tabela nova sem RLS = cross-tenant leak silencioso (Postgres não aplica policies automaticamente).
|
|
18
|
+
# Bash 3.2-portable (macOS default).
|
|
19
|
+
set -e
|
|
20
|
+
|
|
21
|
+
MIGRATIONS_DIR="supabase/migrations"
|
|
22
|
+
|
|
23
|
+
# PT-BR: skip gracioso se projeto não tem migrations Supabase
|
|
24
|
+
if [ ! -d "$MIGRATIONS_DIR" ]; then
|
|
25
|
+
echo "INFO: $MIGRATIONS_DIR não existe — projeto não usa Supabase migrations. Gate skipped."
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# PT-BR: tabelas em schemas system não exigem RLS (auth, storage, realtime, vault, supabase_*)
|
|
30
|
+
SYSTEM_SCHEMA_PREFIXES="auth\\.|storage\\.|realtime\\.|vault\\.|supabase_|extensions\\."
|
|
31
|
+
|
|
32
|
+
# PT-BR: allowlist de tabelas que conscientemente não têm RLS (ex: lookup tables públicas)
|
|
33
|
+
ALLOWLIST_TABLES=(
|
|
34
|
+
"public.permissions" # catálogo global de permissions, leitura pública por design
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
is_allowlisted() {
|
|
38
|
+
local table="$1"
|
|
39
|
+
for at in "${ALLOWLIST_TABLES[@]}"; do
|
|
40
|
+
[ "$table" = "$at" ] && return 0
|
|
41
|
+
done
|
|
42
|
+
return 1
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
VIOLATIONS=0
|
|
46
|
+
VIOLATIONS_DETAIL=""
|
|
47
|
+
|
|
48
|
+
# PT-BR: iterar migrations em ordem cronológica
|
|
49
|
+
MIGRATION_FILES=$(ls "$MIGRATIONS_DIR"/*.sql 2>/dev/null | sort)
|
|
50
|
+
|
|
51
|
+
if [ -z "$MIGRATION_FILES" ]; then
|
|
52
|
+
echo "INFO: nenhum arquivo .sql em $MIGRATIONS_DIR — gate skipped."
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
for f in $MIGRATION_FILES; do
|
|
57
|
+
# PT-BR: extrair tabelas criadas via CREATE TABLE (case-insensitive, ignora IF NOT EXISTS)
|
|
58
|
+
CREATED_TABLES=$(grep -iE "^create\s+table\s+(if\s+not\s+exists\s+)?[a-z_]+\." "$f" 2>/dev/null \
|
|
59
|
+
| sed -E 's/.*create\s+table\s+(if\s+not\s+exists\s+)?([a-z_]+\.[a-z_]+).*/\2/i' \
|
|
60
|
+
| grep -viE "$SYSTEM_SCHEMA_PREFIXES" || true)
|
|
61
|
+
|
|
62
|
+
# PT-BR: extrair tabelas com RLS habilitada no MESMO arquivo
|
|
63
|
+
RLS_TABLES=$(grep -iE "alter\s+table\s+[a-z_]+\.[a-z_]+\s+enable\s+row\s+level\s+security" "$f" 2>/dev/null \
|
|
64
|
+
| sed -E 's/.*alter\s+table\s+([a-z_]+\.[a-z_]+)\s+enable.*/\1/i' || true)
|
|
65
|
+
|
|
66
|
+
# PT-BR: para cada tabela criada, checar se RLS foi habilitada
|
|
67
|
+
for table in $CREATED_TABLES; do
|
|
68
|
+
[ -z "$table" ] && continue
|
|
69
|
+
is_allowlisted "$table" && continue
|
|
70
|
+
|
|
71
|
+
if ! echo "$RLS_TABLES" | grep -qFx "$table"; then
|
|
72
|
+
VIOLATIONS=$((VIOLATIONS + 1))
|
|
73
|
+
VIOLATIONS_DETAIL="${VIOLATIONS_DETAIL}
|
|
74
|
+
$(basename "$f"): tabela '$table' criada sem ENABLE ROW LEVEL SECURITY"
|
|
75
|
+
fi
|
|
76
|
+
done
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
if [ "$VIOLATIONS" -eq 0 ]; then
|
|
80
|
+
echo "PASS: todas as tabelas em supabase/migrations/ têm RLS habilitada no mesmo arquivo de criação."
|
|
81
|
+
exit 0
|
|
82
|
+
else
|
|
83
|
+
echo "FAIL: $VIOLATIONS tabela(s) criada(s) sem ENABLE ROW LEVEL SECURITY:$VIOLATIONS_DETAIL"
|
|
84
|
+
echo ""
|
|
85
|
+
echo "Fix: adicione 'alter table <schema>.<table> enable row level security;' no MESMO arquivo de migration que criou a tabela."
|
|
86
|
+
echo "Ref: kit/skills/multi-tenant-rls-hierarchy/SKILL.md (REGRA #1)"
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Verdict
|
|
92
|
+
|
|
93
|
+
- **passed** — todas tabelas multi-tenant têm RLS habilitada → continuar
|
|
94
|
+
- **block** — apresentar tabela de violations + sugestão de fix; sem opção de skip (anti-pitfall P0 — cross-tenant leak)
|
|
95
|
+
|
|
96
|
+
## Notes
|
|
97
|
+
|
|
98
|
+
Este gate só checa **habilitação** de RLS — não checa se as policies cobrem todos os casos. Ver `multi-tenant-isolation-auditor` agent para análise completa de policies (requer MCP Supabase ativo para query a `pg_policies`).
|
|
99
|
+
|
|
100
|
+
Tabelas em schemas system (`auth.*`, `storage.*`, `realtime.*`, `vault.*`, `supabase_*`, `extensions.*`) são automaticamente skipped — Supabase já aplica RLS interno nelas.
|
|
101
|
+
|
|
102
|
+
Allowlist mínima: `public.permissions` (catálogo global de permissions, leitura pública por design — tem `to authenticated` em SELECT mas sem isolamento por tenant).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: service-role-not-in-user-facing
|
|
3
|
+
stage: pre-verify
|
|
4
|
+
blocking: true
|
|
5
|
+
description: Detecta uso de SUPABASE_SERVICE_ROLE_KEY em Edge Functions com verify_jwt:true (user-facing). Service role bypassa RLS — uso em rota acessível a usuário desliga toda autorização. Skip se projeto não tem supabase/functions/.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Service Role Not In User-Facing gate
|
|
9
|
+
|
|
10
|
+
**When to run:** pre-verify (blocking — anti-pitfall P0 multi-tenant).
|
|
11
|
+
|
|
12
|
+
## Check
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
# PT-BR: detecta uso de SUPABASE_SERVICE_ROLE_KEY em Edge Functions com verify_jwt:true.
|
|
17
|
+
# Anti-pitfall #2 multi-tenant: service role em rota user-facing = bypass total de RLS.
|
|
18
|
+
# Bash 3.2-portable (macOS default).
|
|
19
|
+
set -e
|
|
20
|
+
|
|
21
|
+
FUNCTIONS_DIR="supabase/functions"
|
|
22
|
+
CONFIG_FILE="supabase/config.toml"
|
|
23
|
+
|
|
24
|
+
if [ ! -d "$FUNCTIONS_DIR" ]; then
|
|
25
|
+
echo "INFO: $FUNCTIONS_DIR não existe — projeto não usa Supabase Edge Functions. Gate skipped."
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# PT-BR: env vars que indicam uso de service role
|
|
30
|
+
SERVICE_ROLE_PATTERNS="SUPABASE_SERVICE_ROLE_KEY|SERVICE_ROLE_KEY|service_role_key|serviceRoleKey"
|
|
31
|
+
|
|
32
|
+
VIOLATIONS=0
|
|
33
|
+
VIOLATIONS_DETAIL=""
|
|
34
|
+
|
|
35
|
+
# PT-BR: iterar cada Edge Function (cada subdir em functions/)
|
|
36
|
+
FUNCTION_DIRS=$(find "$FUNCTIONS_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
|
|
37
|
+
|
|
38
|
+
if [ -z "$FUNCTION_DIRS" ]; then
|
|
39
|
+
echo "INFO: nenhuma Edge Function em $FUNCTIONS_DIR — gate skipped."
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
for fn_dir in $FUNCTION_DIRS; do
|
|
44
|
+
fn_name=$(basename "$fn_dir")
|
|
45
|
+
|
|
46
|
+
# PT-BR: skip _shared (não é Edge Function deployable)
|
|
47
|
+
[ "$fn_name" = "_shared" ] && continue
|
|
48
|
+
|
|
49
|
+
# PT-BR: descobrir verify_jwt setting da função (default: true se ausente)
|
|
50
|
+
VERIFY_JWT="true" # default Supabase
|
|
51
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
52
|
+
# PT-BR: parsing leve — procurar [functions.<name>] block + verify_jwt
|
|
53
|
+
SECTION_VERIFY=$(awk -v fn="$fn_name" '
|
|
54
|
+
$0 ~ "^\\[functions\\." fn "\\]" { in_section = 1; next }
|
|
55
|
+
in_section && /^\[/ { in_section = 0 }
|
|
56
|
+
in_section && /verify_jwt/ {
|
|
57
|
+
gsub(/[ \t]/, "")
|
|
58
|
+
split($0, a, "=")
|
|
59
|
+
print a[2]
|
|
60
|
+
exit
|
|
61
|
+
}
|
|
62
|
+
' "$CONFIG_FILE" 2>/dev/null)
|
|
63
|
+
|
|
64
|
+
if [ -n "$SECTION_VERIFY" ]; then
|
|
65
|
+
VERIFY_JWT="$SECTION_VERIFY"
|
|
66
|
+
fi
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# PT-BR: se verify_jwt=false (webhook/internal), skip — service role é OK aqui
|
|
70
|
+
if [ "$VERIFY_JWT" = "false" ]; then
|
|
71
|
+
continue
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# PT-BR: buscar uso de service role em arquivos .ts/.js da function
|
|
75
|
+
SERVICE_ROLE_FILES=$(grep -rlE "$SERVICE_ROLE_PATTERNS" "$fn_dir" --include="*.ts" --include="*.js" --include="*.mjs" 2>/dev/null || true)
|
|
76
|
+
|
|
77
|
+
if [ -n "$SERVICE_ROLE_FILES" ]; then
|
|
78
|
+
VIOLATIONS=$((VIOLATIONS + 1))
|
|
79
|
+
VIOLATIONS_DETAIL="${VIOLATIONS_DETAIL}
|
|
80
|
+
Edge Function '$fn_name' (verify_jwt=$VERIFY_JWT) usa service role:
|
|
81
|
+
$(echo "$SERVICE_ROLE_FILES" | sed 's/^/ /')"
|
|
82
|
+
fi
|
|
83
|
+
done
|
|
84
|
+
|
|
85
|
+
if [ "$VIOLATIONS" -eq 0 ]; then
|
|
86
|
+
echo "PASS: nenhuma Edge Function user-facing (verify_jwt=true) usa SERVICE_ROLE_KEY."
|
|
87
|
+
exit 0
|
|
88
|
+
else
|
|
89
|
+
echo "FAIL: $VIOLATIONS Edge Function(s) user-facing usam SERVICE_ROLE_KEY:$VIOLATIONS_DETAIL"
|
|
90
|
+
echo ""
|
|
91
|
+
echo "Fix: use ANON_KEY com JWT do user para preservar RLS. Se realmente precisa de service role:"
|
|
92
|
+
echo " - Mover lógica privilegiada para Edge Function separada com verify_jwt=false (webhook ou cron-only)"
|
|
93
|
+
echo " - OU validar manualmente quem está chamando antes de usar service role (anti-pattern, mas explícito)"
|
|
94
|
+
echo "Ref: kit/skills/_shared-multi-tenant/glossary.md (sub-seção super_admin) + kit/skills/supabase-rls-policies/SKILL.md"
|
|
95
|
+
exit 1
|
|
96
|
+
fi
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Verdict
|
|
100
|
+
|
|
101
|
+
- **passed** — nenhum service role em Edge Function user-facing → continuar
|
|
102
|
+
- **block** — apresentar lista de Edge Functions violadoras + fix recomendado
|
|
103
|
+
|
|
104
|
+
## Notes
|
|
105
|
+
|
|
106
|
+
Edge Functions com `verify_jwt = false` (webhooks Evolution Go, Stripe, schedulers internos via pg_cron) podem usar service role legitimamente — gate skippa essas.
|
|
107
|
+
|
|
108
|
+
Detecção pode produzir falso-positivo se code referencia o nome da var em comentário ou string literal (ex: documentação dentro do code). Para suprimir, mover documentação para arquivo externo ou usar comentário JSDoc fora do regex match.
|
|
109
|
+
|
|
110
|
+
Para super-admin operations user-facing (impersonation, cross-tenant queries), pattern correto é:
|
|
111
|
+
1. Endpoint user-facing valida `super_admin: true` em JWT app_metadata
|
|
112
|
+
2. Endpoint chama segunda Edge Function interna (verify_jwt=false) que usa service role
|
|
113
|
+
3. Audit log obrigatório no caminho
|