@luanpdd/kit-mcp 1.30.2 → 1.32.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 +168 -168
- package/gates/agent-no-recursive-dispatch.md +84 -82
- package/kit/COMANDOS.md +138 -138
- package/kit/COMPATIBILITY.md +5 -0
- package/kit/README.md +76 -76
- package/kit/agents/advisor-researcher.md +107 -106
- package/kit/agents/ai-mutation-tester.md +1 -0
- package/kit/agents/assumptions-analyzer.md +108 -107
- package/kit/agents/audit-log-implementer.md +314 -313
- package/kit/agents/auditor-consistencia-isolamento.md +414 -413
- package/kit/agents/b2b-saas-architect.md +157 -156
- package/kit/agents/burn-rate-forecaster.md +1 -0
- package/kit/agents/cascading-failures-auditor.md +299 -298
- package/kit/agents/codebase-mapper.md +769 -768
- package/kit/agents/crm-pipeline-implementer.md +257 -256
- package/kit/agents/debugger.md +814 -813
- package/kit/agents/detector-tenant-quente.md +338 -337
- package/kit/agents/evolution-go-integrator.md +201 -200
- package/kit/agents/example-reviewer.md +22 -21
- package/kit/agents/executor.md +565 -564
- package/kit/agents/golden-signals-instrumenter.md +1 -0
- package/kit/agents/incident-investigator.md +1 -0
- package/kit/agents/integration-checker.md +201 -200
- package/kit/agents/invite-flow-implementer.md +190 -189
- package/kit/agents/legacy-characterizer.md +369 -368
- package/kit/agents/lgpd-compliance-auditor.md +296 -295
- package/kit/agents/load-shedding-instrumenter.md +1 -0
- package/kit/agents/multi-tenant-isolation-auditor.md +254 -253
- package/kit/agents/multi-tenant-rls-writer.md +341 -340
- package/kit/agents/nyquist-auditor.md +179 -178
- package/kit/agents/observability-coverage-auditor.md +316 -315
- package/kit/agents/observability-instrumenter.md +1 -0
- package/kit/agents/omm-auditor.md +1 -0
- package/kit/agents/org-onboarding-implementer.md +224 -223
- package/kit/agents/payload-capture-instrumenter.md +274 -273
- package/kit/agents/phase-researcher.md +697 -696
- package/kit/agents/plan-checker.md +273 -272
- package/kit/agents/planner.md +923 -922
- package/kit/agents/postmortem-writer.md +1 -0
- package/kit/agents/project-researcher.md +653 -652
- package/kit/agents/prr-conductor.md +1 -0
- package/kit/agents/refactor-safety-auditor.md +405 -404
- package/kit/agents/release-pipeline-auditor.md +1 -0
- package/kit/agents/research-synthesizer.md +246 -245
- package/kit/agents/roadmapper.md +678 -677
- package/kit/agents/schema-checker.md +1 -0
- package/kit/agents/seam-finder.md +360 -359
- package/kit/agents/shotgun-surgery-detector.md +350 -349
- package/kit/agents/slo-engineer.md +1 -0
- package/kit/agents/storytelling-analyst.md +1 -0
- package/kit/agents/supabase-architect.md +1 -0
- package/kit/agents/supabase-auth-bootstrapper.md +16 -1
- package/kit/agents/supabase-auth-hook-writer.md +418 -0
- package/kit/agents/supabase-branching-architect.md +563 -562
- package/kit/agents/supabase-cicd-pipeline-implementer.md +778 -777
- package/kit/agents/supabase-column-privileges-writer.md +400 -399
- package/kit/agents/supabase-edge-fn-tester.md +2 -1
- package/kit/agents/supabase-edge-fn-writer.md +2 -1
- package/kit/agents/supabase-mfa-implementer.md +439 -0
- package/kit/agents/supabase-migration-writer.md +386 -385
- package/kit/agents/supabase-oauth-server-implementer.md +507 -0
- package/kit/agents/supabase-rbac-implementer.md +393 -392
- package/kit/agents/supabase-realtime-implementer.md +364 -363
- package/kit/agents/supabase-rls-hardener.md +522 -521
- package/kit/agents/supabase-rls-writer.md +324 -323
- package/kit/agents/supabase-roles-implementer.md +356 -355
- package/kit/agents/supabase-social-auth-implementer.md +451 -0
- package/kit/agents/supabase-sso-saml-architect.md +549 -0
- package/kit/agents/supabase-storage-implementer.md +1 -0
- package/kit/agents/super-admin-implementer.md +282 -281
- package/kit/agents/toil-auditor.md +1 -0
- package/kit/agents/ui-auditor.md +438 -437
- package/kit/agents/ui-checker.md +303 -302
- package/kit/agents/ui-researcher.md +356 -355
- package/kit/agents/user-profiler.md +176 -175
- package/kit/agents/validador-evolucao-schema.md +336 -335
- package/kit/agents/verifier.md +729 -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-cascading.md +111 -111
- package/kit/commands/auditar-marco.md +179 -179
- package/kit/commands/auditar-observabilidade-cobertura.md +183 -183
- package/kit/commands/auditar-refactor.md +219 -219
- package/kit/commands/auditar-release.md +109 -109
- 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/burn-rate-status.md +408 -408
- package/kit/commands/capturar-payloads.md +193 -193
- package/kit/commands/caracterizar.md +212 -212
- package/kit/commands/concluir-marco.md +247 -247
- package/kit/commands/configuracoes.md +36 -36
- package/kit/commands/dados-distribuidos.md +188 -188
- package/kit/commands/definir-perfil.md +10 -10
- package/kit/commands/depurar.md +190 -190
- package/kit/commands/detectar-duplicacao.md +197 -197
- package/kit/commands/discutir-fase.md +131 -131
- package/kit/commands/encontrar-seams.md +136 -136
- 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/legacy.md +263 -263
- 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/load-shedding.md +117 -117
- package/kit/commands/mapear-codebase.md +70 -70
- package/kit/commands/multi-tenant.md +163 -163
- 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/refactor-seguro.md +321 -321
- 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/storytelling.md +179 -179
- package/kit/commands/supabase.md +21 -1
- 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 +100 -84
- 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/kit-attribution-reminder.cjs +29 -50
- package/kit/hooks/kit-router.cjs +137 -0
- 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/ai-prompt-characterization/SKILL.md +335 -335
- package/kit/skills/armadilhas-sistemas-distribuidos/SKILL.md +447 -447
- package/kit/skills/audit-log-multi-tenant/SKILL.md +340 -340
- package/kit/skills/b2b-saas-architecture/SKILL.md +300 -300
- package/kit/skills/consistencia-leitura-replica/SKILL.md +385 -385
- package/kit/skills/crm-lead-pipeline-patterns/SKILL.md +343 -343
- package/kit/skills/escolha-modelo-consistencia/SKILL.md +494 -494
- package/kit/skills/evolucao-schema-compativel/SKILL.md +448 -448
- package/kit/skills/evolution-go-whatsapp-integration/SKILL.md +322 -322
- package/kit/skills/example-skill/SKILL.md +42 -42
- package/kit/skills/legacy-api-only-applications/SKILL.md +358 -358
- package/kit/skills/legacy-characterization-tests/SKILL.md +330 -330
- package/kit/skills/legacy-effect-analysis/SKILL.md +331 -331
- package/kit/skills/legacy-extract-class/SKILL.md +203 -203
- package/kit/skills/legacy-programming-by-difference/SKILL.md +252 -252
- package/kit/skills/legacy-seams-and-test-harness/SKILL.md +460 -460
- package/kit/skills/legacy-shotgun-surgery/SKILL.md +286 -286
- package/kit/skills/legacy-sprout-wrap-techniques/SKILL.md +434 -434
- package/kit/skills/legacy-storytelling-naked-crc/SKILL.md +270 -270
- package/kit/skills/lgpd-multi-tenant-compliance/SKILL.md +340 -340
- package/kit/skills/member-invite-flow/SKILL.md +305 -305
- package/kit/skills/member-management-react-shadcn/SKILL.md +328 -328
- package/kit/skills/multi-tenant-performance-scaling/SKILL.md +316 -316
- package/kit/skills/multi-tenant-rls-hierarchy/SKILL.md +342 -342
- package/kit/skills/org-onboarding-flow/SKILL.md +257 -257
- package/kit/skills/org-switcher-react-pattern/SKILL.md +349 -349
- package/kit/skills/permission-gate-react-pattern/SKILL.md +271 -271
- package/kit/skills/postgres-isolamento-concorrencia/SKILL.md +552 -552
- package/kit/skills/pre-refactor-characterization/SKILL.md +421 -421
- package/kit/skills/rbac-permissions-matrix-supabase/SKILL.md +338 -338
- package/kit/skills/streams-eventos-cdc/SKILL.md +711 -711
- package/kit/skills/supabase-auth-hardening/SKILL.md +674 -0
- package/kit/skills/supabase-auth-hooks/SKILL.md +875 -0
- package/kit/skills/supabase-auth-methods/SKILL.md +486 -0
- package/kit/skills/supabase-auth-sessions/SKILL.md +579 -0
- package/kit/skills/supabase-auth-ssr/SKILL.md +60 -14
- package/kit/skills/supabase-branching-workflow/SKILL.md +544 -544
- package/kit/skills/supabase-ci-cd-github-actions/SKILL.md +880 -880
- package/kit/skills/supabase-column-level-security/SKILL.md +426 -426
- package/kit/skills/supabase-config-toml-remotes/SKILL.md +807 -807
- package/kit/skills/supabase-custom-claims-rbac/SKILL.md +472 -472
- package/kit/skills/supabase-edge-functions/SKILL.md +1 -1
- package/kit/skills/supabase-edge-functions-auth/SKILL.md +1 -1
- package/kit/skills/supabase-edge-functions-limits/SKILL.md +1 -1
- package/kit/skills/supabase-edge-functions-mcp-server/SKILL.md +1 -1
- package/kit/skills/supabase-edge-functions-testing/SKILL.md +1 -1
- package/kit/skills/supabase-edge-runtime-builtins/SKILL.md +1 -1
- package/kit/skills/supabase-enterprise-sso-saml/SKILL.md +545 -0
- package/kit/skills/supabase-jwt-signing-keys/SKILL.md +399 -0
- package/kit/skills/supabase-mfa/SKILL.md +488 -0
- package/kit/skills/supabase-migration-repair/SKILL.md +823 -823
- package/kit/skills/supabase-migrations/SKILL.md +297 -297
- package/kit/skills/supabase-oauth-server/SKILL.md +537 -0
- package/kit/skills/supabase-pgtap-testing/SKILL.md +1053 -1053
- package/kit/skills/supabase-postgres-roles/SKILL.md +392 -392
- package/kit/skills/supabase-realtime/SKILL.md +460 -460
- package/kit/skills/supabase-rls-defense-in-depth/SKILL.md +418 -418
- package/kit/skills/supabase-rls-policies/SKILL.md +635 -635
- package/kit/skills/supabase-social-oauth/SKILL.md +480 -0
- package/kit/skills/supabase-third-party-auth/SKILL.md +450 -0
- package/kit/skills/super-admin-platform-pattern/SKILL.md +326 -326
- package/kit/skills/tenant-quente-mitigacao/SKILL.md +605 -605
- package/kit/skills/whatsapp-conversation-state-machine/SKILL.md +287 -287
- package/package.json +1 -1
- 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 +437 -418
- package/src/core/watch.js +121 -121
- package/src/mcp-server/index.js +794 -746
|
@@ -1,426 +1,426 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: supabase-column-level-security
|
|
3
|
-
description: Use ao implementar Column-Level Security (CLS) em Supabase — complementa RLS com privilégios granulares por coluna via GRANT/REVOKE (col1, col2) ON TABLE. Feature AVANÇADA…
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Supabase — Column Level Security
|
|
7
|
-
|
|
8
|
-
## ⚠ Quando usar (e quando NÃO usar)
|
|
9
|
-
|
|
10
|
-
**Column-Level Security é feature AVANÇADA.** Para a maioria dos casos de controle de acesso, **NÃO** recomendamos column-level privileges. Prefira:
|
|
11
|
-
|
|
12
|
-
1. **RLS policies row-level** (skill [`supabase-rls-policies`](../supabase-rls-policies/SKILL.md)) — primeira linha de defesa
|
|
13
|
-
2. **Dedicated role table** — tabela `user_roles` com `is_admin`, `can_edit_billing`, etc.; RLS consulta esta tabela em policies; permite mudança dinâmica de roles sem reescrever GRANT/REVOKE
|
|
14
|
-
|
|
15
|
-
**Use column-level privileges APENAS quando:**
|
|
16
|
-
|
|
17
|
-
- **Compliance LGPD/GDPR** exige restrição granular por coluna (PII columns como SSN, CPF, salary)
|
|
18
|
-
- **Audit log sanitization** — coluna `payload` da audit_log deve ser legível só por security_admin
|
|
19
|
-
- **Billing data restrito** — `credit_card_token`, `bank_account` lisíveis apenas pelo billing_admin role
|
|
20
|
-
- **Token raw em tabelas** — `org_invites.token_raw` (apenas service_role) — depois TTL, hash apenas
|
|
21
|
-
|
|
22
|
-
**NÃO use para:**
|
|
23
|
-
|
|
24
|
-
- Hide/show colunas por user role normal (use view + RLS ao invés)
|
|
25
|
-
- Filtrar dados por linha (isso é RLS, não CLS)
|
|
26
|
-
- "Esconder" colunas no UI (cliente sempre vê o schema; CLS apenas restringe acesso runtime)
|
|
27
|
-
|
|
28
|
-
Trigger phrases:
|
|
29
|
-
|
|
30
|
-
- "column-level privileges", "column privileges Postgres"
|
|
31
|
-
- "GRANT (col) ON TABLE", "REVOKE (col) FROM role"
|
|
32
|
-
- "PII column restriction"
|
|
33
|
-
- "audit log payload column protected"
|
|
34
|
-
|
|
35
|
-
## Princípio canônico
|
|
36
|
-
|
|
37
|
-
Postgres tem **dois níveis** de privileges:
|
|
38
|
-
|
|
39
|
-
1. **Table-level (`GRANT/REVOKE ON TABLE`)** — default, aplica a todas colunas
|
|
40
|
-
2. **Column-level (`GRANT/REVOKE (col1, col2) ON TABLE`)** — granular por coluna; **subset** do table-level
|
|
41
|
-
|
|
42
|
-
**Hierarquia:** se você tem table-level `UPDATE` + column-level `UPDATE (title)` simultaneamente, o table-level **prevalece** (mais permissivo vence). Para restringir, você precisa **REVOKE table-level primeiro**, depois **GRANT column-level apenas nas colunas permitidas**.
|
|
43
|
-
|
|
44
|
-
```sql
|
|
45
|
-
-- ANTES: authenticated tem table-level UPDATE (default)
|
|
46
|
-
-- pode UPDATE todas colunas
|
|
47
|
-
|
|
48
|
-
-- PASSO 1: REVOKE table-level (perde acesso a TODAS colunas)
|
|
49
|
-
revoke update on table public.posts from authenticated;
|
|
50
|
-
|
|
51
|
-
-- PASSO 2: GRANT column-level apenas em title + content
|
|
52
|
-
grant update (title, content) on table public.posts to authenticated;
|
|
53
|
-
|
|
54
|
-
-- AGORA: authenticated só pode UPDATE title + content
|
|
55
|
-
-- tentativa de UPDATE em user_id, created_at, etc. falha com "permission denied for column"
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## ⚠ Caveat #1 — Wildcard `*` restriction
|
|
59
|
-
|
|
60
|
-
**Restricted roles NÃO podem usar `SELECT *`.** Se uma role tem column-level privilege em **apenas algumas colunas** (não todas), `SELECT * FROM <table>` falha com:
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
ERROR: permission denied for column <restricted_col>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**Implicação prática:**
|
|
67
|
-
|
|
68
|
-
```sql
|
|
69
|
-
-- restrict authenticated role a apenas alguns SELECTs
|
|
70
|
-
revoke select on table public.posts from authenticated;
|
|
71
|
-
grant select (id, title, content) on table public.posts to authenticated;
|
|
72
|
-
|
|
73
|
-
-- depois disso:
|
|
74
|
-
-- ❌ select * from posts; -- FALHA (tenta acessar created_at, user_id, etc.)
|
|
75
|
-
-- ✅ select id, title, content from posts; -- OK
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
**Aplicação em SDK Supabase:**
|
|
79
|
-
|
|
80
|
-
```js
|
|
81
|
-
// errado — usa wildcard implícito quando você omite columns
|
|
82
|
-
const { data } = supabase.from('posts').select() // SELECT * by default
|
|
83
|
-
|
|
84
|
-
// certo — sempre liste colunas explicitamente em tabelas com column-level
|
|
85
|
-
const { data } = supabase.from('posts').select('id, title, content')
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**Defensive practice:** em tabelas com qualquer column-level privilege, **NUNCA** use `.select()` sem argumento. Sempre `.select('col1, col2, col3')`.
|
|
89
|
-
|
|
90
|
-
## ⚠ Caveat #2 — Impacto cross-operation
|
|
91
|
-
|
|
92
|
-
Quando você restringe uma coluna, **todas as operações** que tocam essa coluna falham:
|
|
93
|
-
|
|
94
|
-
- **SELECT** — `SELECT col_restricted` falha; `SELECT *` também falha (wildcard)
|
|
95
|
-
- **INSERT** — `INSERT (col_restricted) VALUES (...)` falha se role não tem `INSERT (col_restricted)`
|
|
96
|
-
- **UPDATE** — `UPDATE SET col_restricted = ...` falha
|
|
97
|
-
- **DELETE** — opera no nível de linha, NÃO afetado por column privileges (DELETE bypassa column check)
|
|
98
|
-
|
|
99
|
-
**Exemplo concreto:**
|
|
100
|
-
|
|
101
|
-
```sql
|
|
102
|
-
revoke update (price) on table public.products from authenticated;
|
|
103
|
-
|
|
104
|
-
-- depois disso:
|
|
105
|
-
-- ❌ update products set price = 100 where id = 1; -- FALHA
|
|
106
|
-
-- ❌ update products set title = 'x', price = 100; -- FALHA (price restringido)
|
|
107
|
-
-- ✅ update products set title = 'x'; -- OK (não toca price)
|
|
108
|
-
-- ✅ delete from products where price > 50; -- OK (DELETE ignora column priv)
|
|
109
|
-
-- ❌ select * from products; -- FALHA se SELECT (price) revoked tb
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**Implicação para INSERT:** mesmo em INSERT, role precisa ter privilege em **todas as colunas que vão receber valor** (incluindo defaults explícitos).
|
|
113
|
-
|
|
114
|
-
## Patterns canônicos
|
|
115
|
-
|
|
116
|
-
### Pattern 1 — Restringir UPDATE em colunas específicas
|
|
117
|
-
|
|
118
|
-
```sql
|
|
119
|
-
-- caso: post.title e post.content podem ser editados pelo owner
|
|
120
|
-
-- mas user_id e created_at NÃO podem ser mudados
|
|
121
|
-
|
|
122
|
-
-- 1. REVOKE table-level UPDATE
|
|
123
|
-
revoke update on table public.posts from authenticated;
|
|
124
|
-
|
|
125
|
-
-- 2. GRANT column-level UPDATE apenas onde é seguro
|
|
126
|
-
grant update (title, content, updated_at) on table public.posts to authenticated;
|
|
127
|
-
|
|
128
|
-
-- 3. RLS row-level garante que só o owner pode editar (combinação canônica)
|
|
129
|
-
create policy "users_update_own_posts"
|
|
130
|
-
on public.posts for update
|
|
131
|
-
to authenticated
|
|
132
|
-
using (
|
|
133
|
-
(select auth.uid()) is not null
|
|
134
|
-
and (select auth.uid()) = user_id
|
|
135
|
-
)
|
|
136
|
-
with check (
|
|
137
|
-
(select auth.uid()) is not null
|
|
138
|
-
and (select auth.uid()) = user_id
|
|
139
|
-
);
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Pattern 2 — Restringir SELECT em PII columns
|
|
143
|
-
|
|
144
|
-
```sql
|
|
145
|
-
-- caso: tabela users tem ssn (sensitive) — visível APENAS para security_admin role
|
|
146
|
-
|
|
147
|
-
-- 1. criar role específico (skill `supabase-rls-defense-in-depth` Camada 2)
|
|
148
|
-
create role security_admin with login password '<strong>';
|
|
149
|
-
|
|
150
|
-
-- 2. REVOKE table-level SELECT de roles padrão
|
|
151
|
-
revoke select on table public.users from anon, authenticated;
|
|
152
|
-
|
|
153
|
-
-- 3. GRANT column-level SELECT apenas em colunas não-sensíveis para authenticated
|
|
154
|
-
grant select (id, email, display_name, created_at) on table public.users to authenticated;
|
|
155
|
-
|
|
156
|
-
-- 4. GRANT table-level SELECT (acesso total) APENAS para security_admin
|
|
157
|
-
grant select on table public.users to security_admin;
|
|
158
|
-
|
|
159
|
-
-- 5. RLS row-level continua aplicada (ex: user vê apenas próprio registro)
|
|
160
|
-
create policy "users_select_own" on public.users for select to authenticated
|
|
161
|
-
using ((select auth.uid()) = id);
|
|
162
|
-
|
|
163
|
-
-- IMPORTANTE: cliente precisa usar select('id, email, display_name, created_at') — não select(*)
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Pattern 3 — Audit log com payload protegido
|
|
167
|
-
|
|
168
|
-
```sql
|
|
169
|
-
-- caso: audit_log tem payload jsonb com PII; só security_admin vê payload completo
|
|
170
|
-
|
|
171
|
-
revoke select on table public.audit_log from authenticated;
|
|
172
|
-
|
|
173
|
-
grant select (id, event_type, user_id, org_id, occurred_at) on table public.audit_log to authenticated;
|
|
174
|
-
|
|
175
|
-
grant select on table public.audit_log to security_admin; -- payload visível só aqui
|
|
176
|
-
|
|
177
|
-
-- bonus: combine com RLS row-level (user vê só audit_log da própria org)
|
|
178
|
-
create policy "audit_log_select_own_org" on public.audit_log for select to authenticated
|
|
179
|
-
using (
|
|
180
|
-
org_id::text = any(
|
|
181
|
-
select jsonb_array_elements_text((select auth.jwt()->'app_metadata'->'orgs'))
|
|
182
|
-
)
|
|
183
|
-
);
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Pattern 4 — Token raw em invites (apenas service_role)
|
|
187
|
-
|
|
188
|
-
```sql
|
|
189
|
-
-- caso: org_invites.token_raw é gerado durante create, hash armazenado, raw enviado por email
|
|
190
|
-
-- depois, nenhum role além de service_role deve poder ler o raw (cross-ref invite-flow-implementer)
|
|
191
|
-
|
|
192
|
-
revoke select on table public.org_invites from anon, authenticated;
|
|
193
|
-
|
|
194
|
-
-- nem authenticated nem anon podem ver token_raw
|
|
195
|
-
grant select (id, org_id, email, status, expires_at, created_at) on table public.org_invites to authenticated;
|
|
196
|
-
|
|
197
|
-
-- service_role vê tudo (incluindo token_raw) — usado durante envio de email
|
|
198
|
-
grant select on table public.org_invites to service_role;
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## Dedicated role table pattern (RECOMENDADO pela doc oficial)
|
|
202
|
-
|
|
203
|
-
Em vez de column-level privileges complexos, prefira a abordagem canônica:
|
|
204
|
-
|
|
205
|
-
```sql
|
|
206
|
-
-- 1. tabela de roles
|
|
207
|
-
create table public.user_roles (
|
|
208
|
-
user_id uuid primary key references auth.users (id),
|
|
209
|
-
is_admin boolean default false,
|
|
210
|
-
can_view_pii boolean default false,
|
|
211
|
-
can_edit_billing boolean default false
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
-- 2. RLS na tabela de roles (só service_role pode mutar)
|
|
215
|
-
alter table public.user_roles enable row level security;
|
|
216
|
-
create policy "users_view_own_role" on public.user_roles for select to authenticated
|
|
217
|
-
using ((select auth.uid()) = user_id);
|
|
218
|
-
|
|
219
|
-
-- 3. helper function
|
|
220
|
-
create or replace function public.can_view_pii()
|
|
221
|
-
returns boolean
|
|
222
|
-
language sql
|
|
223
|
-
stable
|
|
224
|
-
as $$
|
|
225
|
-
select coalesce(
|
|
226
|
-
(select can_view_pii from public.user_roles where user_id = (select auth.uid())),
|
|
227
|
-
false
|
|
228
|
-
);
|
|
229
|
-
$$;
|
|
230
|
-
|
|
231
|
-
-- 4. usar em RLS policies (sem column-level)
|
|
232
|
-
create policy "select_users_with_pii" on public.users for select to authenticated
|
|
233
|
-
using (public.can_view_pii());
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**Vantagens vs column-level:**
|
|
237
|
-
|
|
238
|
-
- **Dinâmico:** roles mudam via UPDATE simples (`update user_roles set can_view_pii = true where user_id = ...`); column-level exige REVOKE/GRANT
|
|
239
|
-
- **Auditável:** mudanças em user_roles ficam em audit_log; mudanças em GRANT são silent
|
|
240
|
-
- **Sem caveat de wildcard:** `select *` funciona; column-level força listar colunas
|
|
241
|
-
- **Composable:** combinar múltiplos predicados em policy é mais expressivo que multi-column GRANT
|
|
242
|
-
- **Self-service:** users podem ver próprio role; column privileges não tem auto-discovery
|
|
243
|
-
|
|
244
|
-
**Quando column-level continua melhor:**
|
|
245
|
-
|
|
246
|
-
- Defesa em profundidade adicional (camada extra além de RLS) — Camada 8 de defense-in-depth (skill [`supabase-rls-defense-in-depth`](../supabase-rls-defense-in-depth/SKILL.md))
|
|
247
|
-
- Compliance exige restrição **no banco** (não apenas na app) — ex: LGPD audit
|
|
248
|
-
- Third-party tooling acessa banco direto (Metabase, dbt) — column-level protege mesmo sem app
|
|
249
|
-
|
|
250
|
-
## Studio Dashboard (Supabase UI)
|
|
251
|
-
|
|
252
|
-
A UI de column-level privileges fica em **Feature Preview** no dashboard Supabase (intencionalmente escondida — recomendação implícita de não usar):
|
|
253
|
-
|
|
254
|
-
```
|
|
255
|
-
Dashboard → Database → Column Privileges
|
|
256
|
-
(Feature Preview)
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
**Caveat:** Studio UI permite mudanças mas **não versiona** — mudanças via UI não geram migration automática. Para projetos sérios, gerencie via migrations (`supabase migration new`) — ver pattern em skill [`supabase-migrations`](../supabase-migrations/SKILL.md) BLOCO 6 (v1.24).
|
|
260
|
-
|
|
261
|
-
## Manage column privileges in migrations
|
|
262
|
-
|
|
263
|
-
Pattern canônico para uma migration completa com column-level:
|
|
264
|
-
|
|
265
|
-
```sql
|
|
266
|
-
/*
|
|
267
|
-
Migration: create_posts_with_column_privileges
|
|
268
|
-
Created: 2026-05-11
|
|
269
|
-
Purpose: Create posts table with row-level + column-level security
|
|
270
|
-
Affects: public.posts (new), policies (new), column privileges (new)
|
|
271
|
-
*/
|
|
272
|
-
|
|
273
|
-
-- BLOCO 1: CREATE TABLE
|
|
274
|
-
create table public.posts (
|
|
275
|
-
id bigint primary key generated always as identity,
|
|
276
|
-
user_id uuid references auth.users (id),
|
|
277
|
-
title text,
|
|
278
|
-
content text,
|
|
279
|
-
created_at timestamptz default now(),
|
|
280
|
-
updated_at timestamptz default now()
|
|
281
|
-
);
|
|
282
|
-
|
|
283
|
-
-- BLOCO 2: GRANTs table-level (default)
|
|
284
|
-
grant select on public.posts to anon;
|
|
285
|
-
grant select, insert, update, delete on public.posts to authenticated;
|
|
286
|
-
grant select, insert, update, delete on public.posts to service_role;
|
|
287
|
-
|
|
288
|
-
-- BLOCO 3: ENABLE RLS
|
|
289
|
-
alter table public.posts enable row level security;
|
|
290
|
-
|
|
291
|
-
-- BLOCO 4: RLS policies row-level
|
|
292
|
-
create policy "users_update_own_posts" on public.posts for update
|
|
293
|
-
to authenticated
|
|
294
|
-
using ((select auth.uid()) = user_id);
|
|
295
|
-
|
|
296
|
-
-- BLOCO 5: Index
|
|
297
|
-
create index posts_user_id_idx on public.posts (user_id);
|
|
298
|
-
|
|
299
|
-
-- BLOCO 6 (v1.24): Column-Level Privileges (OPCIONAL — apenas se PII)
|
|
300
|
-
-- REVOKE table-level UPDATE de authenticated (perde acesso a TODAS colunas)
|
|
301
|
-
revoke update on table public.posts from authenticated;
|
|
302
|
-
|
|
303
|
-
-- GRANT column-level UPDATE apenas em title + content
|
|
304
|
-
grant update (title, content, updated_at) on table public.posts to authenticated;
|
|
305
|
-
|
|
306
|
-
-- service_role mantém acesso total (não precisa GRANT extra — já tem)
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
## Auditoria — detectar tabelas com PII sem column privileges
|
|
310
|
-
|
|
311
|
-
```sql
|
|
312
|
-
-- listar tabelas com colunas potencialmente sensíveis sem column-level GRANT/REVOKE
|
|
313
|
-
select
|
|
314
|
-
c.table_schema,
|
|
315
|
-
c.table_name,
|
|
316
|
-
c.column_name,
|
|
317
|
-
c.data_type
|
|
318
|
-
from information_schema.columns c
|
|
319
|
-
where c.table_schema = 'public'
|
|
320
|
-
and (
|
|
321
|
-
c.column_name ilike '%email%'
|
|
322
|
-
or c.column_name ilike '%phone%'
|
|
323
|
-
or c.column_name ilike '%ssn%'
|
|
324
|
-
or c.column_name ilike '%cpf%'
|
|
325
|
-
or c.column_name ilike '%token%'
|
|
326
|
-
or c.column_name ilike '%password%'
|
|
327
|
-
or c.column_name ilike '%credit_card%'
|
|
328
|
-
or c.column_name ilike '%bank_account%'
|
|
329
|
-
or c.column_name ilike '%salary%'
|
|
330
|
-
)
|
|
331
|
-
and not exists (
|
|
332
|
-
-- check se há column_privilege específico para esta coluna
|
|
333
|
-
select 1
|
|
334
|
-
from information_schema.column_privileges p
|
|
335
|
-
where p.table_schema = c.table_schema
|
|
336
|
-
and p.table_name = c.table_name
|
|
337
|
-
and p.column_name = c.column_name
|
|
338
|
-
)
|
|
339
|
-
order by c.table_schema, c.table_name, c.column_name;
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
Cross-ref auditoria sistemática em agent [`supabase-rls-hardener`](../../agents/supabase-rls-hardener.md) Detector 8 (v1.24).
|
|
343
|
-
|
|
344
|
-
## Anti-patterns
|
|
345
|
-
|
|
346
|
-
### Anti-pattern 1 — Column-level sem revoke table-level prévio
|
|
347
|
-
|
|
348
|
-
**Errado:**
|
|
349
|
-
```sql
|
|
350
|
-
-- column-level GRANT sem revoke table-level
|
|
351
|
-
grant update (title) on table public.posts to authenticated;
|
|
352
|
-
-- authenticated AINDA pode update todas colunas (table-level vence)
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
**Por quê:** Postgres aplica privilege mais permissivo — column-level GRANT sem REVOKE table-level prévio é no-op.
|
|
356
|
-
|
|
357
|
-
**Certo:**
|
|
358
|
-
```sql
|
|
359
|
-
revoke update on table public.posts from authenticated;
|
|
360
|
-
grant update (title) on table public.posts to authenticated;
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
### Anti-pattern 2 — Esperar que `SELECT *` funcione com column-level
|
|
364
|
-
|
|
365
|
-
**Errado:**
|
|
366
|
-
```sql
|
|
367
|
-
revoke select (sensitive_col) on table public.users from authenticated;
|
|
368
|
-
-- esperar que select * automaticamente skipe sensitive_col — NÃO FUNCIONA
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
```js
|
|
372
|
-
const { data } = supabase.from('users').select() // SELECT * — FALHA
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
**Por quê:** Postgres aplica permission check à query inteira. `SELECT *` é `SELECT col1, col2, ..., sensitive_col` expandido — falha se qualquer coluna sem permission.
|
|
376
|
-
|
|
377
|
-
**Certo:** sempre listar colunas explicitamente:
|
|
378
|
-
```js
|
|
379
|
-
const { data } = supabase.from('users').select('id, email, display_name')
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
### Anti-pattern 3 — Column-level em vez de dedicated role table
|
|
383
|
-
|
|
384
|
-
**Errado (para caso "admin vê PII"):**
|
|
385
|
-
```sql
|
|
386
|
-
revoke select (ssn, salary) on table public.employees from authenticated;
|
|
387
|
-
-- agora você precisa criar role separado, granular GRANT a cada admin, etc.
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
**Por quê:** muda admin = REVOKE/GRANT manual; sem audit trail; sem self-discovery.
|
|
391
|
-
|
|
392
|
-
**Certo:** dedicated role table + RLS function — ver section "Dedicated role table pattern (RECOMENDADO)" acima.
|
|
393
|
-
|
|
394
|
-
### Anti-pattern 4 — Column-level em INSERT esquecendo DEFAULTs
|
|
395
|
-
|
|
396
|
-
**Errado:**
|
|
397
|
-
```sql
|
|
398
|
-
revoke insert on table public.audit_log from authenticated;
|
|
399
|
-
grant insert (event_type, payload) on table public.audit_log to authenticated;
|
|
400
|
-
|
|
401
|
-
-- código tenta:
|
|
402
|
-
insert into audit_log (event_type, payload) values ('login', '{}');
|
|
403
|
-
-- FALHA porque user_id (PK default gen_random_uuid) também precisa de GRANT
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
**Certo:** lista TODAS colunas que recebem valor (incluindo defaults gerados):
|
|
407
|
-
```sql
|
|
408
|
-
grant insert (event_type, payload, user_id, occurred_at) on table public.audit_log to authenticated;
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
Ou prefira que cliente não faça INSERT direto — use RPC function `SECURITY DEFINER` que tem privilege total.
|
|
412
|
-
|
|
413
|
-
## Cross-suite integration (v1.24)
|
|
414
|
-
|
|
415
|
-
Esta skill é base para o agent novo `supabase-column-privileges-writer` (Phase 133) — recebe spec de table + colunas sensíveis via `Task()` e produz REVOKE/GRANT column-level SQL preservando intent upstream.
|
|
416
|
-
|
|
417
|
-
Princípio canônico v1.23 (herdado): agents não-Supabase pensam/planejam; agents Supabase materializam/hardenam; ninguém descarta upstream. Para column-level, o agent canonical é `supabase-column-privileges-writer`.
|
|
418
|
-
|
|
419
|
-
## Ver também
|
|
420
|
-
|
|
421
|
-
- [supabase-rls-policies](../supabase-rls-policies/SKILL.md) (v1.23) — RLS row-level (primeira camada de defesa)
|
|
422
|
-
- [supabase-rls-defense-in-depth](../supabase-rls-defense-in-depth/SKILL.md) (v1.23) — column-level é Camada 8 de defesa em profundidade (v1.24)
|
|
423
|
-
- [supabase-migrations](../supabase-migrations/SKILL.md) (v1.24) — BLOCO 6 opcional com column-level no template canônico
|
|
424
|
-
- [supabase-column-privileges-writer](../../agents/supabase-column-privileges-writer.md) (v1.24) — agent canonical materializador
|
|
425
|
-
- [supabase-rls-hardener](../../agents/supabase-rls-hardener.md) (v1.23) — Detector 8 valida column-level em tabelas com PII (v1.24)
|
|
426
|
-
- [glossário compartilhado](../_shared-supabase/glossary.md) — termos column-level privileges, table-level privileges, wildcard restriction, dedicated role table pattern
|
|
1
|
+
---
|
|
2
|
+
name: supabase-column-level-security
|
|
3
|
+
description: Use ao implementar Column-Level Security (CLS) em Supabase — complementa RLS com privilégios granulares por coluna via GRANT/REVOKE (col1, col2) ON TABLE. Feature AVANÇADA…
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Supabase — Column Level Security
|
|
7
|
+
|
|
8
|
+
## ⚠ Quando usar (e quando NÃO usar)
|
|
9
|
+
|
|
10
|
+
**Column-Level Security é feature AVANÇADA.** Para a maioria dos casos de controle de acesso, **NÃO** recomendamos column-level privileges. Prefira:
|
|
11
|
+
|
|
12
|
+
1. **RLS policies row-level** (skill [`supabase-rls-policies`](../supabase-rls-policies/SKILL.md)) — primeira linha de defesa
|
|
13
|
+
2. **Dedicated role table** — tabela `user_roles` com `is_admin`, `can_edit_billing`, etc.; RLS consulta esta tabela em policies; permite mudança dinâmica de roles sem reescrever GRANT/REVOKE
|
|
14
|
+
|
|
15
|
+
**Use column-level privileges APENAS quando:**
|
|
16
|
+
|
|
17
|
+
- **Compliance LGPD/GDPR** exige restrição granular por coluna (PII columns como SSN, CPF, salary)
|
|
18
|
+
- **Audit log sanitization** — coluna `payload` da audit_log deve ser legível só por security_admin
|
|
19
|
+
- **Billing data restrito** — `credit_card_token`, `bank_account` lisíveis apenas pelo billing_admin role
|
|
20
|
+
- **Token raw em tabelas** — `org_invites.token_raw` (apenas service_role) — depois TTL, hash apenas
|
|
21
|
+
|
|
22
|
+
**NÃO use para:**
|
|
23
|
+
|
|
24
|
+
- Hide/show colunas por user role normal (use view + RLS ao invés)
|
|
25
|
+
- Filtrar dados por linha (isso é RLS, não CLS)
|
|
26
|
+
- "Esconder" colunas no UI (cliente sempre vê o schema; CLS apenas restringe acesso runtime)
|
|
27
|
+
|
|
28
|
+
Trigger phrases:
|
|
29
|
+
|
|
30
|
+
- "column-level privileges", "column privileges Postgres"
|
|
31
|
+
- "GRANT (col) ON TABLE", "REVOKE (col) FROM role"
|
|
32
|
+
- "PII column restriction"
|
|
33
|
+
- "audit log payload column protected"
|
|
34
|
+
|
|
35
|
+
## Princípio canônico
|
|
36
|
+
|
|
37
|
+
Postgres tem **dois níveis** de privileges:
|
|
38
|
+
|
|
39
|
+
1. **Table-level (`GRANT/REVOKE ON TABLE`)** — default, aplica a todas colunas
|
|
40
|
+
2. **Column-level (`GRANT/REVOKE (col1, col2) ON TABLE`)** — granular por coluna; **subset** do table-level
|
|
41
|
+
|
|
42
|
+
**Hierarquia:** se você tem table-level `UPDATE` + column-level `UPDATE (title)` simultaneamente, o table-level **prevalece** (mais permissivo vence). Para restringir, você precisa **REVOKE table-level primeiro**, depois **GRANT column-level apenas nas colunas permitidas**.
|
|
43
|
+
|
|
44
|
+
```sql
|
|
45
|
+
-- ANTES: authenticated tem table-level UPDATE (default)
|
|
46
|
+
-- pode UPDATE todas colunas
|
|
47
|
+
|
|
48
|
+
-- PASSO 1: REVOKE table-level (perde acesso a TODAS colunas)
|
|
49
|
+
revoke update on table public.posts from authenticated;
|
|
50
|
+
|
|
51
|
+
-- PASSO 2: GRANT column-level apenas em title + content
|
|
52
|
+
grant update (title, content) on table public.posts to authenticated;
|
|
53
|
+
|
|
54
|
+
-- AGORA: authenticated só pode UPDATE title + content
|
|
55
|
+
-- tentativa de UPDATE em user_id, created_at, etc. falha com "permission denied for column"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## ⚠ Caveat #1 — Wildcard `*` restriction
|
|
59
|
+
|
|
60
|
+
**Restricted roles NÃO podem usar `SELECT *`.** Se uma role tem column-level privilege em **apenas algumas colunas** (não todas), `SELECT * FROM <table>` falha com:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
ERROR: permission denied for column <restricted_col>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Implicação prática:**
|
|
67
|
+
|
|
68
|
+
```sql
|
|
69
|
+
-- restrict authenticated role a apenas alguns SELECTs
|
|
70
|
+
revoke select on table public.posts from authenticated;
|
|
71
|
+
grant select (id, title, content) on table public.posts to authenticated;
|
|
72
|
+
|
|
73
|
+
-- depois disso:
|
|
74
|
+
-- ❌ select * from posts; -- FALHA (tenta acessar created_at, user_id, etc.)
|
|
75
|
+
-- ✅ select id, title, content from posts; -- OK
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Aplicação em SDK Supabase:**
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
// errado — usa wildcard implícito quando você omite columns
|
|
82
|
+
const { data } = supabase.from('posts').select() // SELECT * by default
|
|
83
|
+
|
|
84
|
+
// certo — sempre liste colunas explicitamente em tabelas com column-level
|
|
85
|
+
const { data } = supabase.from('posts').select('id, title, content')
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Defensive practice:** em tabelas com qualquer column-level privilege, **NUNCA** use `.select()` sem argumento. Sempre `.select('col1, col2, col3')`.
|
|
89
|
+
|
|
90
|
+
## ⚠ Caveat #2 — Impacto cross-operation
|
|
91
|
+
|
|
92
|
+
Quando você restringe uma coluna, **todas as operações** que tocam essa coluna falham:
|
|
93
|
+
|
|
94
|
+
- **SELECT** — `SELECT col_restricted` falha; `SELECT *` também falha (wildcard)
|
|
95
|
+
- **INSERT** — `INSERT (col_restricted) VALUES (...)` falha se role não tem `INSERT (col_restricted)`
|
|
96
|
+
- **UPDATE** — `UPDATE SET col_restricted = ...` falha
|
|
97
|
+
- **DELETE** — opera no nível de linha, NÃO afetado por column privileges (DELETE bypassa column check)
|
|
98
|
+
|
|
99
|
+
**Exemplo concreto:**
|
|
100
|
+
|
|
101
|
+
```sql
|
|
102
|
+
revoke update (price) on table public.products from authenticated;
|
|
103
|
+
|
|
104
|
+
-- depois disso:
|
|
105
|
+
-- ❌ update products set price = 100 where id = 1; -- FALHA
|
|
106
|
+
-- ❌ update products set title = 'x', price = 100; -- FALHA (price restringido)
|
|
107
|
+
-- ✅ update products set title = 'x'; -- OK (não toca price)
|
|
108
|
+
-- ✅ delete from products where price > 50; -- OK (DELETE ignora column priv)
|
|
109
|
+
-- ❌ select * from products; -- FALHA se SELECT (price) revoked tb
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Implicação para INSERT:** mesmo em INSERT, role precisa ter privilege em **todas as colunas que vão receber valor** (incluindo defaults explícitos).
|
|
113
|
+
|
|
114
|
+
## Patterns canônicos
|
|
115
|
+
|
|
116
|
+
### Pattern 1 — Restringir UPDATE em colunas específicas
|
|
117
|
+
|
|
118
|
+
```sql
|
|
119
|
+
-- caso: post.title e post.content podem ser editados pelo owner
|
|
120
|
+
-- mas user_id e created_at NÃO podem ser mudados
|
|
121
|
+
|
|
122
|
+
-- 1. REVOKE table-level UPDATE
|
|
123
|
+
revoke update on table public.posts from authenticated;
|
|
124
|
+
|
|
125
|
+
-- 2. GRANT column-level UPDATE apenas onde é seguro
|
|
126
|
+
grant update (title, content, updated_at) on table public.posts to authenticated;
|
|
127
|
+
|
|
128
|
+
-- 3. RLS row-level garante que só o owner pode editar (combinação canônica)
|
|
129
|
+
create policy "users_update_own_posts"
|
|
130
|
+
on public.posts for update
|
|
131
|
+
to authenticated
|
|
132
|
+
using (
|
|
133
|
+
(select auth.uid()) is not null
|
|
134
|
+
and (select auth.uid()) = user_id
|
|
135
|
+
)
|
|
136
|
+
with check (
|
|
137
|
+
(select auth.uid()) is not null
|
|
138
|
+
and (select auth.uid()) = user_id
|
|
139
|
+
);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Pattern 2 — Restringir SELECT em PII columns
|
|
143
|
+
|
|
144
|
+
```sql
|
|
145
|
+
-- caso: tabela users tem ssn (sensitive) — visível APENAS para security_admin role
|
|
146
|
+
|
|
147
|
+
-- 1. criar role específico (skill `supabase-rls-defense-in-depth` Camada 2)
|
|
148
|
+
create role security_admin with login password '<strong>';
|
|
149
|
+
|
|
150
|
+
-- 2. REVOKE table-level SELECT de roles padrão
|
|
151
|
+
revoke select on table public.users from anon, authenticated;
|
|
152
|
+
|
|
153
|
+
-- 3. GRANT column-level SELECT apenas em colunas não-sensíveis para authenticated
|
|
154
|
+
grant select (id, email, display_name, created_at) on table public.users to authenticated;
|
|
155
|
+
|
|
156
|
+
-- 4. GRANT table-level SELECT (acesso total) APENAS para security_admin
|
|
157
|
+
grant select on table public.users to security_admin;
|
|
158
|
+
|
|
159
|
+
-- 5. RLS row-level continua aplicada (ex: user vê apenas próprio registro)
|
|
160
|
+
create policy "users_select_own" on public.users for select to authenticated
|
|
161
|
+
using ((select auth.uid()) = id);
|
|
162
|
+
|
|
163
|
+
-- IMPORTANTE: cliente precisa usar select('id, email, display_name, created_at') — não select(*)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Pattern 3 — Audit log com payload protegido
|
|
167
|
+
|
|
168
|
+
```sql
|
|
169
|
+
-- caso: audit_log tem payload jsonb com PII; só security_admin vê payload completo
|
|
170
|
+
|
|
171
|
+
revoke select on table public.audit_log from authenticated;
|
|
172
|
+
|
|
173
|
+
grant select (id, event_type, user_id, org_id, occurred_at) on table public.audit_log to authenticated;
|
|
174
|
+
|
|
175
|
+
grant select on table public.audit_log to security_admin; -- payload visível só aqui
|
|
176
|
+
|
|
177
|
+
-- bonus: combine com RLS row-level (user vê só audit_log da própria org)
|
|
178
|
+
create policy "audit_log_select_own_org" on public.audit_log for select to authenticated
|
|
179
|
+
using (
|
|
180
|
+
org_id::text = any(
|
|
181
|
+
select jsonb_array_elements_text((select auth.jwt()->'app_metadata'->'orgs'))
|
|
182
|
+
)
|
|
183
|
+
);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Pattern 4 — Token raw em invites (apenas service_role)
|
|
187
|
+
|
|
188
|
+
```sql
|
|
189
|
+
-- caso: org_invites.token_raw é gerado durante create, hash armazenado, raw enviado por email
|
|
190
|
+
-- depois, nenhum role além de service_role deve poder ler o raw (cross-ref invite-flow-implementer)
|
|
191
|
+
|
|
192
|
+
revoke select on table public.org_invites from anon, authenticated;
|
|
193
|
+
|
|
194
|
+
-- nem authenticated nem anon podem ver token_raw
|
|
195
|
+
grant select (id, org_id, email, status, expires_at, created_at) on table public.org_invites to authenticated;
|
|
196
|
+
|
|
197
|
+
-- service_role vê tudo (incluindo token_raw) — usado durante envio de email
|
|
198
|
+
grant select on table public.org_invites to service_role;
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Dedicated role table pattern (RECOMENDADO pela doc oficial)
|
|
202
|
+
|
|
203
|
+
Em vez de column-level privileges complexos, prefira a abordagem canônica:
|
|
204
|
+
|
|
205
|
+
```sql
|
|
206
|
+
-- 1. tabela de roles
|
|
207
|
+
create table public.user_roles (
|
|
208
|
+
user_id uuid primary key references auth.users (id),
|
|
209
|
+
is_admin boolean default false,
|
|
210
|
+
can_view_pii boolean default false,
|
|
211
|
+
can_edit_billing boolean default false
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
-- 2. RLS na tabela de roles (só service_role pode mutar)
|
|
215
|
+
alter table public.user_roles enable row level security;
|
|
216
|
+
create policy "users_view_own_role" on public.user_roles for select to authenticated
|
|
217
|
+
using ((select auth.uid()) = user_id);
|
|
218
|
+
|
|
219
|
+
-- 3. helper function
|
|
220
|
+
create or replace function public.can_view_pii()
|
|
221
|
+
returns boolean
|
|
222
|
+
language sql
|
|
223
|
+
stable
|
|
224
|
+
as $$
|
|
225
|
+
select coalesce(
|
|
226
|
+
(select can_view_pii from public.user_roles where user_id = (select auth.uid())),
|
|
227
|
+
false
|
|
228
|
+
);
|
|
229
|
+
$$;
|
|
230
|
+
|
|
231
|
+
-- 4. usar em RLS policies (sem column-level)
|
|
232
|
+
create policy "select_users_with_pii" on public.users for select to authenticated
|
|
233
|
+
using (public.can_view_pii());
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Vantagens vs column-level:**
|
|
237
|
+
|
|
238
|
+
- **Dinâmico:** roles mudam via UPDATE simples (`update user_roles set can_view_pii = true where user_id = ...`); column-level exige REVOKE/GRANT
|
|
239
|
+
- **Auditável:** mudanças em user_roles ficam em audit_log; mudanças em GRANT são silent
|
|
240
|
+
- **Sem caveat de wildcard:** `select *` funciona; column-level força listar colunas
|
|
241
|
+
- **Composable:** combinar múltiplos predicados em policy é mais expressivo que multi-column GRANT
|
|
242
|
+
- **Self-service:** users podem ver próprio role; column privileges não tem auto-discovery
|
|
243
|
+
|
|
244
|
+
**Quando column-level continua melhor:**
|
|
245
|
+
|
|
246
|
+
- Defesa em profundidade adicional (camada extra além de RLS) — Camada 8 de defense-in-depth (skill [`supabase-rls-defense-in-depth`](../supabase-rls-defense-in-depth/SKILL.md))
|
|
247
|
+
- Compliance exige restrição **no banco** (não apenas na app) — ex: LGPD audit
|
|
248
|
+
- Third-party tooling acessa banco direto (Metabase, dbt) — column-level protege mesmo sem app
|
|
249
|
+
|
|
250
|
+
## Studio Dashboard (Supabase UI)
|
|
251
|
+
|
|
252
|
+
A UI de column-level privileges fica em **Feature Preview** no dashboard Supabase (intencionalmente escondida — recomendação implícita de não usar):
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
Dashboard → Database → Column Privileges
|
|
256
|
+
(Feature Preview)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Caveat:** Studio UI permite mudanças mas **não versiona** — mudanças via UI não geram migration automática. Para projetos sérios, gerencie via migrations (`supabase migration new`) — ver pattern em skill [`supabase-migrations`](../supabase-migrations/SKILL.md) BLOCO 6 (v1.24).
|
|
260
|
+
|
|
261
|
+
## Manage column privileges in migrations
|
|
262
|
+
|
|
263
|
+
Pattern canônico para uma migration completa com column-level:
|
|
264
|
+
|
|
265
|
+
```sql
|
|
266
|
+
/*
|
|
267
|
+
Migration: create_posts_with_column_privileges
|
|
268
|
+
Created: 2026-05-11
|
|
269
|
+
Purpose: Create posts table with row-level + column-level security
|
|
270
|
+
Affects: public.posts (new), policies (new), column privileges (new)
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
-- BLOCO 1: CREATE TABLE
|
|
274
|
+
create table public.posts (
|
|
275
|
+
id bigint primary key generated always as identity,
|
|
276
|
+
user_id uuid references auth.users (id),
|
|
277
|
+
title text,
|
|
278
|
+
content text,
|
|
279
|
+
created_at timestamptz default now(),
|
|
280
|
+
updated_at timestamptz default now()
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
-- BLOCO 2: GRANTs table-level (default)
|
|
284
|
+
grant select on public.posts to anon;
|
|
285
|
+
grant select, insert, update, delete on public.posts to authenticated;
|
|
286
|
+
grant select, insert, update, delete on public.posts to service_role;
|
|
287
|
+
|
|
288
|
+
-- BLOCO 3: ENABLE RLS
|
|
289
|
+
alter table public.posts enable row level security;
|
|
290
|
+
|
|
291
|
+
-- BLOCO 4: RLS policies row-level
|
|
292
|
+
create policy "users_update_own_posts" on public.posts for update
|
|
293
|
+
to authenticated
|
|
294
|
+
using ((select auth.uid()) = user_id);
|
|
295
|
+
|
|
296
|
+
-- BLOCO 5: Index
|
|
297
|
+
create index posts_user_id_idx on public.posts (user_id);
|
|
298
|
+
|
|
299
|
+
-- BLOCO 6 (v1.24): Column-Level Privileges (OPCIONAL — apenas se PII)
|
|
300
|
+
-- REVOKE table-level UPDATE de authenticated (perde acesso a TODAS colunas)
|
|
301
|
+
revoke update on table public.posts from authenticated;
|
|
302
|
+
|
|
303
|
+
-- GRANT column-level UPDATE apenas em title + content
|
|
304
|
+
grant update (title, content, updated_at) on table public.posts to authenticated;
|
|
305
|
+
|
|
306
|
+
-- service_role mantém acesso total (não precisa GRANT extra — já tem)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Auditoria — detectar tabelas com PII sem column privileges
|
|
310
|
+
|
|
311
|
+
```sql
|
|
312
|
+
-- listar tabelas com colunas potencialmente sensíveis sem column-level GRANT/REVOKE
|
|
313
|
+
select
|
|
314
|
+
c.table_schema,
|
|
315
|
+
c.table_name,
|
|
316
|
+
c.column_name,
|
|
317
|
+
c.data_type
|
|
318
|
+
from information_schema.columns c
|
|
319
|
+
where c.table_schema = 'public'
|
|
320
|
+
and (
|
|
321
|
+
c.column_name ilike '%email%'
|
|
322
|
+
or c.column_name ilike '%phone%'
|
|
323
|
+
or c.column_name ilike '%ssn%'
|
|
324
|
+
or c.column_name ilike '%cpf%'
|
|
325
|
+
or c.column_name ilike '%token%'
|
|
326
|
+
or c.column_name ilike '%password%'
|
|
327
|
+
or c.column_name ilike '%credit_card%'
|
|
328
|
+
or c.column_name ilike '%bank_account%'
|
|
329
|
+
or c.column_name ilike '%salary%'
|
|
330
|
+
)
|
|
331
|
+
and not exists (
|
|
332
|
+
-- check se há column_privilege específico para esta coluna
|
|
333
|
+
select 1
|
|
334
|
+
from information_schema.column_privileges p
|
|
335
|
+
where p.table_schema = c.table_schema
|
|
336
|
+
and p.table_name = c.table_name
|
|
337
|
+
and p.column_name = c.column_name
|
|
338
|
+
)
|
|
339
|
+
order by c.table_schema, c.table_name, c.column_name;
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Cross-ref auditoria sistemática em agent [`supabase-rls-hardener`](../../agents/supabase-rls-hardener.md) Detector 8 (v1.24).
|
|
343
|
+
|
|
344
|
+
## Anti-patterns
|
|
345
|
+
|
|
346
|
+
### Anti-pattern 1 — Column-level sem revoke table-level prévio
|
|
347
|
+
|
|
348
|
+
**Errado:**
|
|
349
|
+
```sql
|
|
350
|
+
-- column-level GRANT sem revoke table-level
|
|
351
|
+
grant update (title) on table public.posts to authenticated;
|
|
352
|
+
-- authenticated AINDA pode update todas colunas (table-level vence)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Por quê:** Postgres aplica privilege mais permissivo — column-level GRANT sem REVOKE table-level prévio é no-op.
|
|
356
|
+
|
|
357
|
+
**Certo:**
|
|
358
|
+
```sql
|
|
359
|
+
revoke update on table public.posts from authenticated;
|
|
360
|
+
grant update (title) on table public.posts to authenticated;
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Anti-pattern 2 — Esperar que `SELECT *` funcione com column-level
|
|
364
|
+
|
|
365
|
+
**Errado:**
|
|
366
|
+
```sql
|
|
367
|
+
revoke select (sensitive_col) on table public.users from authenticated;
|
|
368
|
+
-- esperar que select * automaticamente skipe sensitive_col — NÃO FUNCIONA
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
```js
|
|
372
|
+
const { data } = supabase.from('users').select() // SELECT * — FALHA
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Por quê:** Postgres aplica permission check à query inteira. `SELECT *` é `SELECT col1, col2, ..., sensitive_col` expandido — falha se qualquer coluna sem permission.
|
|
376
|
+
|
|
377
|
+
**Certo:** sempre listar colunas explicitamente:
|
|
378
|
+
```js
|
|
379
|
+
const { data } = supabase.from('users').select('id, email, display_name')
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Anti-pattern 3 — Column-level em vez de dedicated role table
|
|
383
|
+
|
|
384
|
+
**Errado (para caso "admin vê PII"):**
|
|
385
|
+
```sql
|
|
386
|
+
revoke select (ssn, salary) on table public.employees from authenticated;
|
|
387
|
+
-- agora você precisa criar role separado, granular GRANT a cada admin, etc.
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Por quê:** muda admin = REVOKE/GRANT manual; sem audit trail; sem self-discovery.
|
|
391
|
+
|
|
392
|
+
**Certo:** dedicated role table + RLS function — ver section "Dedicated role table pattern (RECOMENDADO)" acima.
|
|
393
|
+
|
|
394
|
+
### Anti-pattern 4 — Column-level em INSERT esquecendo DEFAULTs
|
|
395
|
+
|
|
396
|
+
**Errado:**
|
|
397
|
+
```sql
|
|
398
|
+
revoke insert on table public.audit_log from authenticated;
|
|
399
|
+
grant insert (event_type, payload) on table public.audit_log to authenticated;
|
|
400
|
+
|
|
401
|
+
-- código tenta:
|
|
402
|
+
insert into audit_log (event_type, payload) values ('login', '{}');
|
|
403
|
+
-- FALHA porque user_id (PK default gen_random_uuid) também precisa de GRANT
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**Certo:** lista TODAS colunas que recebem valor (incluindo defaults gerados):
|
|
407
|
+
```sql
|
|
408
|
+
grant insert (event_type, payload, user_id, occurred_at) on table public.audit_log to authenticated;
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Ou prefira que cliente não faça INSERT direto — use RPC function `SECURITY DEFINER` que tem privilege total.
|
|
412
|
+
|
|
413
|
+
## Cross-suite integration (v1.24)
|
|
414
|
+
|
|
415
|
+
Esta skill é base para o agent novo `supabase-column-privileges-writer` (Phase 133) — recebe spec de table + colunas sensíveis via `Task()` e produz REVOKE/GRANT column-level SQL preservando intent upstream.
|
|
416
|
+
|
|
417
|
+
Princípio canônico v1.23 (herdado): agents não-Supabase pensam/planejam; agents Supabase materializam/hardenam; ninguém descarta upstream. Para column-level, o agent canonical é `supabase-column-privileges-writer`.
|
|
418
|
+
|
|
419
|
+
## Ver também
|
|
420
|
+
|
|
421
|
+
- [supabase-rls-policies](../supabase-rls-policies/SKILL.md) (v1.23) — RLS row-level (primeira camada de defesa)
|
|
422
|
+
- [supabase-rls-defense-in-depth](../supabase-rls-defense-in-depth/SKILL.md) (v1.23) — column-level é Camada 8 de defesa em profundidade (v1.24)
|
|
423
|
+
- [supabase-migrations](../supabase-migrations/SKILL.md) (v1.24) — BLOCO 6 opcional com column-level no template canônico
|
|
424
|
+
- [supabase-column-privileges-writer](../../agents/supabase-column-privileges-writer.md) (v1.24) — agent canonical materializador
|
|
425
|
+
- [supabase-rls-hardener](../../agents/supabase-rls-hardener.md) (v1.23) — Detector 8 valida column-level em tabelas com PII (v1.24)
|
|
426
|
+
- [glossário compartilhado](../_shared-supabase/glossary.md) — termos column-level privileges, table-level privileges, wildcard restriction, dedicated role table pattern
|