@luanpdd/kit-mcp 1.26.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/kit/agents/release-pipeline-auditor.md +11 -0
- package/kit/agents/supabase-architect.md +14 -0
- package/kit/agents/supabase-branching-architect.md +562 -0
- package/kit/agents/supabase-cicd-pipeline-implementer.md +777 -0
- package/kit/agents/supabase-migration-writer.md +12 -0
- package/kit/file-manifest.json +13 -6
- package/kit/skills/_shared-supabase/glossary.md +10 -0
- package/kit/skills/supabase-branching-workflow/SKILL.md +544 -0
- package/kit/skills/supabase-ci-cd-github-actions/SKILL.md +880 -0
- package/kit/skills/supabase-config-toml-remotes/SKILL.md +807 -0
- package/kit/skills/supabase-migration-repair/SKILL.md +823 -0
- package/kit/skills/supabase-pgtap-testing/SKILL.md +1053 -0
- package/package.json +1 -1
|
@@ -0,0 +1,807 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: supabase-config-toml-remotes
|
|
3
|
+
description: Use ao configurar Supabase para branching — `[remotes.<name>]` block + branch-specific overrides + secrets per-branch (NÃO herdam) + dotenvx pattern (.env.keys + .env.preview encrypted) + 6 grupos de encrypted fields canônicos (Studio/Database/Auth Core/Email/Captcha/Hooks/SMS/External + Edge Runtime). v1.27 incorpora 100% da doc oficial.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Supabase — Config TOML & Remotes
|
|
7
|
+
|
|
8
|
+
## Quando usar
|
|
9
|
+
|
|
10
|
+
Branching Supabase exige configuração per-branch via `supabase/config.toml` — blocos `[remotes.<name>]` declaram **overrides versionados em git** que o Deploy DAG step 4 (configure) aplica em cada branch.
|
|
11
|
+
|
|
12
|
+
Esta skill é par-conjugado com `supabase-branching-workflow` (Phase 149) — branching workflow descreve **quando** branches são criados; esta skill descreve **como** configurar.
|
|
13
|
+
|
|
14
|
+
Trigger phrases:
|
|
15
|
+
|
|
16
|
+
- "remotes block Supabase", "[remotes] config.toml"
|
|
17
|
+
- "branch-specific config Supabase", "config.toml staging override"
|
|
18
|
+
- "secrets per-branch Supabase", "supabase secrets set"
|
|
19
|
+
- "dotenvx Supabase", ".env.keys .env.preview"
|
|
20
|
+
- "encrypted: Supabase config", "env() vs encrypted: syntax"
|
|
21
|
+
- "Supabase encrypted fields", "auth.hook secrets encrypted"
|
|
22
|
+
- "designated secret fields"
|
|
23
|
+
- "branch project_id Supabase"
|
|
24
|
+
|
|
25
|
+
**Use APENAS para:**
|
|
26
|
+
|
|
27
|
+
- Configurar persistent branches (staging, QA, production) via `[remotes.<branch>]` block
|
|
28
|
+
- Materializar overrides per-ambiente (db.pool_size, api.max_rows, auth.external.*, edge_runtime.secrets)
|
|
29
|
+
- Gerenciar secrets per-branch via `supabase secrets set --env-file`
|
|
30
|
+
- Versionar secrets encrypted em git via dotenvx pattern (.env.keys + .env.preview/.env.production)
|
|
31
|
+
|
|
32
|
+
**NÃO use para:**
|
|
33
|
+
|
|
34
|
+
- Substituir secret vault corporativo (Vault, AWS Secrets Manager) — dotenvx é git-tracked encrypted; vault corporativo tem audit trail + rotation policies
|
|
35
|
+
- Gerenciar secrets de runtime de Edge Functions sem `supabase secrets set` — `env()` em config.toml é build-time do CLI, não runtime do projeto
|
|
36
|
+
- Versionar a chave de decryption (`.env.keys`) — NUNCA committar; é equivalente a vazar password master
|
|
37
|
+
- Apontar `[remotes.<name>]` para branch deletado — operações falham silenciosamente
|
|
38
|
+
|
|
39
|
+
## Princípio canônico
|
|
40
|
+
|
|
41
|
+
Três princípios canônicos:
|
|
42
|
+
|
|
43
|
+
1. **`config.toml` é source of truth versionado.** `[remotes.<branch>]` block declara overrides explícitos commitados em git — Deploy DAG step 4 (configure) re-aplica em cada deploy. Sem deriva entre o que está em git e o que está no branch.
|
|
44
|
+
|
|
45
|
+
2. **dotenvx para secrets git-tracked.** `.env.keys` (decryption key, **SEMPRE gitignored**) + `.env.preview`/`.env.production` (encrypted values, committed em git). Permite versionar secrets sem expor — git history rastreia mudanças de secrets sem PII em plaintext.
|
|
46
|
+
|
|
47
|
+
3. **Secrets NÃO herdam entre branches.** Cada branch tem credenciais únicas; criar persistent branch `staging` NÃO copia secrets do `main`. Reset manual via `supabase secrets set --env-file` para CADA branch — incluindo o branch `main` original.
|
|
48
|
+
|
|
49
|
+
### Distinção canônica `env()` vs `encrypted:`
|
|
50
|
+
|
|
51
|
+
| | `env(VAR_NAME)` | `encrypted:<value>` |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| Resolução | Runtime CLI (build-time) | Decryption via `.env.keys` |
|
|
54
|
+
| Onde funciona | **Qualquer** field em config.toml | **APENAS** designated secret fields (Pattern 5) |
|
|
55
|
+
| Workflow | Setar env var no shell antes do CLI | Encriptar via `dotenvx set`, committed em git |
|
|
56
|
+
| Caveat | Resolve para env var **local** do CLI, NÃO para secrets do projeto Supabase (runtime das Edge Functions) | Em field **não-designated** é silent no-op (literal string usada como valor) |
|
|
57
|
+
| Caso de uso | Secrets em env vars do CI (GitHub Actions) | Secrets versionados encrypted em git via dotenvx |
|
|
58
|
+
|
|
59
|
+
## Pattern 1: `[remotes]` block — referenciar branch existente (CFG-01)
|
|
60
|
+
|
|
61
|
+
`[remotes.<name>]` em `config.toml` declara que **este bloco se aplica APENAS ao branch nomeado** identificado pelo `project_id`.
|
|
62
|
+
|
|
63
|
+
### Pré-requisito
|
|
64
|
+
|
|
65
|
+
Branch já criado (persistent via CLI ou preview via PR webhook):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# criar persistent branch via CLI
|
|
69
|
+
supabase --experimental branches create staging --persistent
|
|
70
|
+
|
|
71
|
+
# (preview branches são criados automaticamente via GitHub PR — cross-ref skill supabase-branching-workflow Pattern 3)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Workflow canônico
|
|
75
|
+
|
|
76
|
+
**Step 1: Obter `project_id` do branch:**
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
supabase --experimental branches list
|
|
80
|
+
|
|
81
|
+
# output esperado:
|
|
82
|
+
# BRANCH NAME BRANCH PROJECT ID STATUS
|
|
83
|
+
# main main-project-ref active
|
|
84
|
+
# staging staging-dedicated-ref active
|
|
85
|
+
# pr-42-feature pr42-feature-ref active
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Step 2: Adicionar `[remotes.<branch>]` block no `supabase/config.toml`:**
|
|
89
|
+
|
|
90
|
+
```toml
|
|
91
|
+
[remotes.staging]
|
|
92
|
+
project_id = "staging-dedicated-ref"
|
|
93
|
+
|
|
94
|
+
[remotes.staging.db.seed]
|
|
95
|
+
enabled = true
|
|
96
|
+
sql_paths = ["./seeds/staging.sql"]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Step 3: Commitar `config.toml` em git → Deploy DAG step 4 (configure) aplica overrides no branch.**
|
|
100
|
+
|
|
101
|
+
### Exemplo TOML — múltiplos branches
|
|
102
|
+
|
|
103
|
+
```toml
|
|
104
|
+
# bloco base — aplica a TODOS os branches (incluindo main)
|
|
105
|
+
[db]
|
|
106
|
+
port = 54322
|
|
107
|
+
pool_size = 15
|
|
108
|
+
|
|
109
|
+
[api]
|
|
110
|
+
port = 54321
|
|
111
|
+
max_rows = 1000
|
|
112
|
+
|
|
113
|
+
# branch staging — overrides específicos
|
|
114
|
+
[remotes.staging]
|
|
115
|
+
project_id = "staging-dedicated-ref"
|
|
116
|
+
|
|
117
|
+
[remotes.staging.db.seed]
|
|
118
|
+
enabled = true
|
|
119
|
+
sql_paths = ["./seeds/staging.sql"]
|
|
120
|
+
|
|
121
|
+
# branch production — sem seeds em produção
|
|
122
|
+
[remotes.production]
|
|
123
|
+
project_id = "production-dedicated-ref"
|
|
124
|
+
|
|
125
|
+
[remotes.production.db.seed]
|
|
126
|
+
enabled = false
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Caveat — branch deletado
|
|
130
|
+
|
|
131
|
+
`project_id` deve ser de branch **existente**. Se branch foi deletado:
|
|
132
|
+
|
|
133
|
+
- Bloco `[remotes.<branch>]` continua válido sintaticamente
|
|
134
|
+
- CLI rejeita commands com erro `branch not found`
|
|
135
|
+
- DAG step 4 (configure) silenciosamente skip o branch deletado
|
|
136
|
+
|
|
137
|
+
**Mitigação:** revisão trimestral — `supabase --experimental branches list` + remover blocos `[remotes.<deleted>]` correspondentes.
|
|
138
|
+
|
|
139
|
+
### Caveat — `project_id` único por bloco
|
|
140
|
+
|
|
141
|
+
Cada `[remotes.<name>]` deve apontar para **branch dedicado** criado especificamente. NÃO reutilizar `project_id` do `main` para `staging` (cross-ref Anti-pattern 5).
|
|
142
|
+
|
|
143
|
+
## Pattern 2: Branch-specific configuration overrides (CFG-02)
|
|
144
|
+
|
|
145
|
+
Princípio: config base (sem `[remotes...]` prefix) aplica a TODOS os branches; `[remotes.<name>.<section>]` aplica override APENAS no branch nomeado.
|
|
146
|
+
|
|
147
|
+
### Categorias de fields override-able (canônicas)
|
|
148
|
+
|
|
149
|
+
**db (database tuning):**
|
|
150
|
+
|
|
151
|
+
```toml
|
|
152
|
+
[db]
|
|
153
|
+
port = 54322
|
|
154
|
+
pool_size = 15 # default
|
|
155
|
+
|
|
156
|
+
# staging override
|
|
157
|
+
[remotes.staging.db]
|
|
158
|
+
port = 54322 # mesma porta — só pool_size muda
|
|
159
|
+
pool_size = 25
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**api (PostgREST):**
|
|
163
|
+
|
|
164
|
+
```toml
|
|
165
|
+
[api]
|
|
166
|
+
port = 54321
|
|
167
|
+
max_rows = 1000
|
|
168
|
+
schemas = ["public"]
|
|
169
|
+
|
|
170
|
+
# staging quer ver schema extensions para debug
|
|
171
|
+
[remotes.staging.api]
|
|
172
|
+
max_rows = 5000 # debug — limite maior
|
|
173
|
+
schemas = ["public", "extensions"]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**db.seed:**
|
|
177
|
+
|
|
178
|
+
```toml
|
|
179
|
+
# default — sem seed
|
|
180
|
+
[db.seed]
|
|
181
|
+
enabled = false
|
|
182
|
+
sql_paths = []
|
|
183
|
+
|
|
184
|
+
# staging — seed sintético para QA
|
|
185
|
+
[remotes.staging.db.seed]
|
|
186
|
+
enabled = true
|
|
187
|
+
sql_paths = ["./seeds/staging.sql"]
|
|
188
|
+
|
|
189
|
+
# preview — seed minimal para smoke tests
|
|
190
|
+
[remotes.preview.db.seed]
|
|
191
|
+
enabled = true
|
|
192
|
+
sql_paths = ["./seeds/preview-smoke.sql"]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**auth.external.* (OAuth providers):**
|
|
196
|
+
|
|
197
|
+
```toml
|
|
198
|
+
# production GitHub OAuth
|
|
199
|
+
[auth.external.github]
|
|
200
|
+
enabled = true
|
|
201
|
+
client_id = "Iv1.production-app-id"
|
|
202
|
+
secret = "encrypted:LSi...prod-github-secret-encrypted...=="
|
|
203
|
+
|
|
204
|
+
# staging GitHub OAuth — app diferente
|
|
205
|
+
[remotes.staging.auth.external.github]
|
|
206
|
+
enabled = true
|
|
207
|
+
client_id = "Iv1.staging-app-id"
|
|
208
|
+
secret = "encrypted:LSi...staging-github-secret-encrypted...=="
|
|
209
|
+
redirect_uri = "https://staging.example.com/auth/callback"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**edge_runtime.secrets:**
|
|
213
|
+
|
|
214
|
+
```toml
|
|
215
|
+
[edge_runtime.secrets]
|
|
216
|
+
SENDGRID_API_KEY = "encrypted:LSi...prod-sendgrid-encrypted...=="
|
|
217
|
+
|
|
218
|
+
# staging — SendGrid sandbox
|
|
219
|
+
[remotes.staging.edge_runtime.secrets]
|
|
220
|
+
SENDGRID_API_KEY = "encrypted:LSi...staging-sendgrid-encrypted...=="
|
|
221
|
+
SENDGRID_SANDBOX_MODE = "env(STAGING_SENDGRID_SANDBOX_MODE)"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Tabela canônica de fields override-able
|
|
225
|
+
|
|
226
|
+
| Section | Fields | Caso de uso típico |
|
|
227
|
+
|---------|--------|---------------------|
|
|
228
|
+
| `db` | `port`, `pool_size` | Tuning pool size per ambiente (staging menor) |
|
|
229
|
+
| `api` | `port`, `max_rows`, `schemas` | Diferenciar response limits + schemas expostos |
|
|
230
|
+
| `db.seed` | `enabled`, `sql_paths` | Seeds diferentes por branch |
|
|
231
|
+
| `auth.external.<provider>` | `enabled`, `client_id`, `secret`, `redirect_uri` | OAuth keys per ambiente |
|
|
232
|
+
| `auth.email.smtp` | `host`, `port`, `user`, `pass` | SMTP staging vs produção |
|
|
233
|
+
| `auth.sms.<provider>` | `account_sid`, `auth_token`, etc. | SMS provider keys per ambiente |
|
|
234
|
+
| `edge_runtime.secrets.<KEY>` | custom env vars | API keys per branch (SendGrid, Stripe, OpenAI) |
|
|
235
|
+
| `studio.openai_api_key` | string | Key diferente para staging studio (lower limits) |
|
|
236
|
+
|
|
237
|
+
### Caveat — merge behavior
|
|
238
|
+
|
|
239
|
+
`[remotes.staging.db]` com `pool_size = 25` NÃO sobrescreve `[db]` global completamente — apenas o field específico (`pool_size`). Outros fields do `[db]` global (port, etc.) continuam aplicados.
|
|
240
|
+
|
|
241
|
+
```toml
|
|
242
|
+
# config base
|
|
243
|
+
[db]
|
|
244
|
+
port = 54322
|
|
245
|
+
pool_size = 15
|
|
246
|
+
shadow_port = 54320
|
|
247
|
+
|
|
248
|
+
# staging override — apenas pool_size muda
|
|
249
|
+
[remotes.staging.db]
|
|
250
|
+
pool_size = 25
|
|
251
|
+
# resultado em staging: port=54322, pool_size=25, shadow_port=54320 (mantidos da base)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Caveat — re-deploy required
|
|
255
|
+
|
|
256
|
+
Alterações em `config.toml` precisam ser pushed para o branch — Deploy DAG step 4 (configure) só roda em novo deploy (push novo commit no PR ou re-run via Dashboard).
|
|
257
|
+
|
|
258
|
+
## Pattern 3: Secrets management per-branch (CFG-03)
|
|
259
|
+
|
|
260
|
+
### Caveat canônico — secrets NÃO herdam
|
|
261
|
+
|
|
262
|
+
> **Secrets NÃO herdam entre branches.** Criar persistent branch `staging` NÃO copia secrets do `main`. Cada branch precisa ter secrets setados separadamente.
|
|
263
|
+
|
|
264
|
+
Implicação prática:
|
|
265
|
+
|
|
266
|
+
- `Deno.env.get("SENDGRID_API_KEY")` em Edge Function no branch staging retorna `undefined` até `supabase secrets set` ser executado para o staging
|
|
267
|
+
- Esse comportamento é silent — sem warning no DAG, sem alert do CLI
|
|
268
|
+
|
|
269
|
+
### CLI canônico
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Set secrets a partir de .env file (recomendação canônica)
|
|
273
|
+
supabase secrets set --env-file ./supabase/.env
|
|
274
|
+
|
|
275
|
+
# Set secret individual
|
|
276
|
+
supabase secrets set SMTP_HOST=smtp.example.com
|
|
277
|
+
|
|
278
|
+
# Listar secrets do branch atual
|
|
279
|
+
supabase secrets list
|
|
280
|
+
|
|
281
|
+
# Remover secret
|
|
282
|
+
supabase secrets unset SMTP_HOST
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Workflow per-branch canônico
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# 1. criar staging branch
|
|
289
|
+
supabase --experimental branches create staging --persistent
|
|
290
|
+
|
|
291
|
+
# 2. obter project_id do staging
|
|
292
|
+
supabase --experimental branches list | grep staging
|
|
293
|
+
# output: staging staging-dedicated-ref active
|
|
294
|
+
|
|
295
|
+
# 3. link CLI para o branch staging
|
|
296
|
+
supabase link --project-ref staging-dedicated-ref
|
|
297
|
+
|
|
298
|
+
# 4. setar secrets DO STAGING (arquivo dedicado)
|
|
299
|
+
supabase secrets set --env-file ./supabase/.env.staging
|
|
300
|
+
|
|
301
|
+
# 5. validar — listar secrets do staging
|
|
302
|
+
supabase secrets list
|
|
303
|
+
|
|
304
|
+
# 6. voltar para main quando terminar
|
|
305
|
+
supabase link --project-ref main-project-ref
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Exemplo `.env.staging`
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# .env.staging — secrets específicos do branch staging
|
|
312
|
+
# Gitignored se não usa dotenvx (Pattern 4); encrypted se usa.
|
|
313
|
+
SMTP_HOST=smtp.staging.example.com
|
|
314
|
+
SMTP_USER=staging-user
|
|
315
|
+
SMTP_PASS=staging-pass
|
|
316
|
+
SENDGRID_API_KEY=SG.staging-api-key
|
|
317
|
+
OPENAI_API_KEY=sk-staging-openai-key
|
|
318
|
+
STRIPE_SECRET_KEY=sk_test_staging_stripe
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Caveat — secrets vs config.toml `env()`
|
|
322
|
+
|
|
323
|
+
Distinção CRÍTICA — fonte de confusão comum:
|
|
324
|
+
|
|
325
|
+
| | `supabase secrets set` | `env()` em config.toml |
|
|
326
|
+
|---|---|---|
|
|
327
|
+
| Resolvido | Runtime das **Edge Functions** | Build-time do **CLI local** |
|
|
328
|
+
| Acesso | `Deno.env.get("KEY")` no código Deno | Substituição literal no `config.toml` pré-deploy |
|
|
329
|
+
| Storage | Supabase backend (per-branch) | Env var do shell que rodou o CLI |
|
|
330
|
+
| Lifecycle | Persistido no branch | Volátil (só durante invocação do CLI) |
|
|
331
|
+
|
|
332
|
+
Exemplo concreto:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
# Setar secret no branch (runtime Edge Function)
|
|
336
|
+
supabase secrets set SENDGRID_API_KEY=sk-real-key
|
|
337
|
+
# → Deno.env.get("SENDGRID_API_KEY") em Edge Function retorna "sk-real-key"
|
|
338
|
+
|
|
339
|
+
# Setar env var local (build-time config.toml)
|
|
340
|
+
export SENDGRID_API_KEY=sk-different-key
|
|
341
|
+
supabase db push
|
|
342
|
+
# → config.toml com env(SENDGRID_API_KEY) resolve para "sk-different-key" (do shell)
|
|
343
|
+
# → Edge Function ainda retorna "sk-real-key" (do supabase secrets set anterior)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Recomendação canônica
|
|
347
|
+
|
|
348
|
+
Usar **dotenvx pattern** (Pattern 4) para versionar secrets encrypted em git em vez de gerenciar `.env.staging` separadamente em cada máquina.
|
|
349
|
+
|
|
350
|
+
## Pattern 4: dotenvx pattern + `encrypted:` vs `env()` syntax (CFG-04)
|
|
351
|
+
|
|
352
|
+
### Princípio dotenvx
|
|
353
|
+
|
|
354
|
+
dotenvx ([dotenvx.com](https://dotenvx.com/)) é uma evolução de `dotenv` que permite **encryption symmetric** de valores no arquivo `.env`:
|
|
355
|
+
|
|
356
|
+
- Encrypted values podem ser committed em git (`.env.preview`, `.env.production`)
|
|
357
|
+
- Decryption key (`.env.keys`) **NUNCA é committed** — gitignored sempre
|
|
358
|
+
- Permite versionar secrets sem expor — git history rastreia mudanças de secrets sem PII em plaintext
|
|
359
|
+
|
|
360
|
+
### Tabela canônica de file types (dotenvx convenção)
|
|
361
|
+
|
|
362
|
+
| File | Env | gitignore | Encrypted | Caso de uso |
|
|
363
|
+
|------|-----|-----------|-----------|-------------|
|
|
364
|
+
| `.env.keys` | All | **YES** (NUNCA committar) | No (key plaintext) | Decryption master key |
|
|
365
|
+
| `.env.local` | Local dev | YES | No (plaintext OK local) | Overrides de dev individual |
|
|
366
|
+
| `.env.production` | Production | No (committed) | YES | Secrets de produção encrypted |
|
|
367
|
+
| `.env.preview` | Branches preview | No (committed) | YES | Secrets de preview branches encrypted |
|
|
368
|
+
| `.env` | Any (fallback) | Maybe | YES | Default file (custom) |
|
|
369
|
+
|
|
370
|
+
**Atenção canônica:** `.env.keys` em `.gitignore` é obrigação canônica — sem isso, o pattern dotenvx é equivalente a commitar secrets plaintext.
|
|
371
|
+
|
|
372
|
+
### Workflow canônico dotenvx
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
# 1. instalar dotenvx (devDependency)
|
|
376
|
+
npm install -D @dotenvx/dotenvx
|
|
377
|
+
|
|
378
|
+
# 2. adicionar .env.keys ao .gitignore (BLOQUEANTE — fazer ANTES de qualquer set)
|
|
379
|
+
echo ".env.keys" >> .gitignore
|
|
380
|
+
git add .gitignore
|
|
381
|
+
git commit -m "chore: gitignore dotenvx decryption key"
|
|
382
|
+
|
|
383
|
+
# 3. encrypted set — gera .env.keys automaticamente na primeira vez
|
|
384
|
+
npx @dotenvx/dotenvx set SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET "ghs_real_secret" -f supabase/.env.preview
|
|
385
|
+
# Output:
|
|
386
|
+
# set SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET (encrypted) (.env.preview)
|
|
387
|
+
# wrote new public-private encryption keys to .env.keys
|
|
388
|
+
|
|
389
|
+
# 4. commitar .env.preview (encrypted) + verificar .env.keys NÃO foi committed
|
|
390
|
+
git status
|
|
391
|
+
# modified: supabase/.env.preview
|
|
392
|
+
# (.env.keys NÃO deve aparecer)
|
|
393
|
+
git add supabase/.env.preview
|
|
394
|
+
git commit -m "feat: add encrypted GitHub OAuth secret for preview"
|
|
395
|
+
|
|
396
|
+
# 5. usar com supabase CLI (carregar via --env-file)
|
|
397
|
+
npx supabase secrets set --env-file supabase/.env.keys
|
|
398
|
+
# ou em workflow CI (decripta + roda CLI):
|
|
399
|
+
npx @dotenvx/dotenvx run -- supabase secrets set --env-file supabase/.env.preview
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Sintaxes em `config.toml`
|
|
403
|
+
|
|
404
|
+
**Option A: `encrypted:<value>` directly em designated secret field:**
|
|
405
|
+
|
|
406
|
+
```toml
|
|
407
|
+
[auth.external.github]
|
|
408
|
+
enabled = true
|
|
409
|
+
client_id = "Iv1.app-id-public"
|
|
410
|
+
# secret é designated secret field (Pattern 5 Grupo 8) — encrypted: é decriptado via .env.keys
|
|
411
|
+
secret = "encrypted:LSiME...github-secret-encrypted-payload...=="
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Option B: `env(VAR_NAME)` para resolver via env var (qualquer field):**
|
|
415
|
+
|
|
416
|
+
```toml
|
|
417
|
+
[auth.external.github]
|
|
418
|
+
enabled = true
|
|
419
|
+
client_id = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_CLIENT_ID)"
|
|
420
|
+
secret = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET)"
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Warning canônico — `encrypted:` é restrito
|
|
424
|
+
|
|
425
|
+
> **`encrypted:` syntax SÓ funciona em designated secret fields** (Pattern 5 — 6 grupos canônicos). Em outros campos não decripta silenciosamente — o valor literal `"encrypted:LSiME..."` é usado como string, expondo o payload encrypted como se fosse plaintext.
|
|
426
|
+
|
|
427
|
+
Exemplo concreto do falso silencioso:
|
|
428
|
+
|
|
429
|
+
```toml
|
|
430
|
+
# ERRADO — auth.email.smtp.host NÃO é designated secret field
|
|
431
|
+
[auth.email.smtp]
|
|
432
|
+
host = "encrypted:LSi...wrong...==" # ← silent no-op
|
|
433
|
+
# resultado: SMTP tenta conectar em host literal "encrypted:LSi...wrong...==" → DNS fail
|
|
434
|
+
|
|
435
|
+
# CERTO — auth.email.smtp.pass É designated (Pattern 5 Grupo 4)
|
|
436
|
+
[auth.email.smtp]
|
|
437
|
+
host = "smtp.example.com" # plain
|
|
438
|
+
pass = "encrypted:LSi...correct-pass...==" # ← decriptado
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Quando usar qual
|
|
442
|
+
|
|
443
|
+
- **`encrypted:`** — quando quer versionar o secret **encrypted em git** (workflow dotenvx); aplicar APENAS em fields designados (Pattern 5)
|
|
444
|
+
- **`env()`** — quando secrets vivem em env vars do CI/local; works em **qualquer field**; flexibilidade ao custo de não versionar em git (rotação via update env var no CI)
|
|
445
|
+
|
|
446
|
+
Recomendação canônica para teams maduros: `encrypted:` em produção (auditável via git history) + `env()` em dev local (volátil).
|
|
447
|
+
|
|
448
|
+
## Pattern 5: 6 grupos de encrypted fields canônicos (CFG-05)
|
|
449
|
+
|
|
450
|
+
Princípio: apenas estes fields aceitam `encrypted:<value>` syntax — qualquer outro field é **silent no-op** (cross-ref Pattern 4 Warning).
|
|
451
|
+
|
|
452
|
+
### Lista canônica COMPLETA dos 6 grupos lógicos
|
|
453
|
+
|
|
454
|
+
A documentação Supabase agrupa estes como **6 grupos lógicos** (Studio, Database, Auth Core/Email/Captcha/Hooks/SMS/External, Edge Runtime) — apresentamos expandido para máxima clareza por subcategoria.
|
|
455
|
+
|
|
456
|
+
### Grupo 1: Studio
|
|
457
|
+
|
|
458
|
+
| Field | Caso de uso |
|
|
459
|
+
|-------|-------------|
|
|
460
|
+
| `studio.openai_api_key` | Studio AI features (SQL suggestions, schema generation) |
|
|
461
|
+
|
|
462
|
+
### Grupo 2: Database
|
|
463
|
+
|
|
464
|
+
| Field | Caso de uso |
|
|
465
|
+
|-------|-------------|
|
|
466
|
+
| `db.root_key` | Root key para encryption-at-rest (Vault) |
|
|
467
|
+
| `db.vault.*` (todas subkeys) | Supabase Vault — encryption keys gerenciadas |
|
|
468
|
+
|
|
469
|
+
### Grupo 3: Auth Core
|
|
470
|
+
|
|
471
|
+
| Field | Caso de uso |
|
|
472
|
+
|-------|-------------|
|
|
473
|
+
| `auth.publishable_key` | API publishable key (substitui anon key v2) |
|
|
474
|
+
| `auth.secret_key` | API secret key (substitui service_role key v2) |
|
|
475
|
+
| `auth.jwt_secret` | JWT signing secret (HS256) |
|
|
476
|
+
|
|
477
|
+
### Grupo 4: Auth Email
|
|
478
|
+
|
|
479
|
+
| Field | Caso de uso |
|
|
480
|
+
|-------|-------------|
|
|
481
|
+
| `auth.email.smtp.pass` | Password do SMTP server (SendGrid, AWS SES, Mailgun, etc.) |
|
|
482
|
+
|
|
483
|
+
### Grupo 5: Auth Captcha
|
|
484
|
+
|
|
485
|
+
| Field | Caso de uso |
|
|
486
|
+
|-------|-------------|
|
|
487
|
+
| `auth.captcha.secret` | hCaptcha ou Turnstile secret key |
|
|
488
|
+
|
|
489
|
+
### Grupo 6: Auth Hooks
|
|
490
|
+
|
|
491
|
+
Todos os 6 Auth Hooks (cross-ref skill `supabase-custom-claims-rbac` v1.25):
|
|
492
|
+
|
|
493
|
+
| Field | Caso de uso |
|
|
494
|
+
|-------|-------------|
|
|
495
|
+
| `auth.hook.mfa_verification_attempt.secrets` | Custom MFA verification hook |
|
|
496
|
+
| `auth.hook.password_verification_attempt.secrets` | Custom password verification hook |
|
|
497
|
+
| `auth.hook.custom_access_token.secrets` | Custom Access Token Auth Hook (RBAC v1.25) |
|
|
498
|
+
| `auth.hook.send_sms.secrets` | Custom SMS sender hook |
|
|
499
|
+
| `auth.hook.send_email.secrets` | Custom email sender hook |
|
|
500
|
+
| `auth.hook.before_user_created.secrets` | Hook para validar/rejeitar signup |
|
|
501
|
+
|
|
502
|
+
### Grupo 7: Auth SMS providers
|
|
503
|
+
|
|
504
|
+
5 providers SMS canônicos:
|
|
505
|
+
|
|
506
|
+
| Field | Caso de uso |
|
|
507
|
+
|-------|-------------|
|
|
508
|
+
| `auth.sms.twilio.auth_token` | Twilio SMS provider |
|
|
509
|
+
| `auth.sms.twilio_verify.auth_token` | Twilio Verify (MFA) |
|
|
510
|
+
| `auth.sms.messagebird.access_key` | MessageBird provider |
|
|
511
|
+
| `auth.sms.textlocal.api_key` | Textlocal (UK provider) |
|
|
512
|
+
| `auth.sms.vonage.api_secret` | Vonage (ex-Nexmo) |
|
|
513
|
+
|
|
514
|
+
### Grupo 8: Auth External providers
|
|
515
|
+
|
|
516
|
+
| Field | Caso de uso |
|
|
517
|
+
|-------|-------------|
|
|
518
|
+
| `auth.external.<provider>.secret` | Qualquer OAuth provider — github, google, facebook, apple, twitter, discord, gitlab, bitbucket, azure, linkedin, notion, slack, spotify, twitch, kakao, keycloak, workos, zoom, figma, fly |
|
|
519
|
+
|
|
520
|
+
### Grupo 9: Edge Runtime
|
|
521
|
+
|
|
522
|
+
| Field | Caso de uso |
|
|
523
|
+
|-------|-------------|
|
|
524
|
+
| `edge_runtime.secrets.*` (todas subkeys) | Env vars custom para Edge Functions (SENDGRID, STRIPE, OPENAI, etc.) |
|
|
525
|
+
|
|
526
|
+
### Exemplo TOML completo cobrindo múltiplos grupos
|
|
527
|
+
|
|
528
|
+
```toml
|
|
529
|
+
# Grupo 1: Studio
|
|
530
|
+
[studio]
|
|
531
|
+
openai_api_key = "encrypted:LSi...studio-key-encrypted...=="
|
|
532
|
+
|
|
533
|
+
# Grupo 2: Database (Vault)
|
|
534
|
+
[db.vault]
|
|
535
|
+
secret_master_key = "encrypted:LSi...vault-master-encrypted...=="
|
|
536
|
+
|
|
537
|
+
# Grupo 3: Auth Core
|
|
538
|
+
[auth]
|
|
539
|
+
jwt_secret = "encrypted:LSi...jwt-secret-encrypted...=="
|
|
540
|
+
secret_key = "encrypted:LSi...secret-key-encrypted...=="
|
|
541
|
+
|
|
542
|
+
# Grupo 4: Auth Email
|
|
543
|
+
[auth.email.smtp]
|
|
544
|
+
host = "smtp.sendgrid.net"
|
|
545
|
+
port = 587
|
|
546
|
+
user = "apikey"
|
|
547
|
+
pass = "encrypted:LSi...smtp-pass-encrypted...=="
|
|
548
|
+
|
|
549
|
+
# Grupo 5: Auth Captcha
|
|
550
|
+
[auth.captcha]
|
|
551
|
+
enabled = true
|
|
552
|
+
provider = "hcaptcha"
|
|
553
|
+
secret = "encrypted:LSi...captcha-secret-encrypted...=="
|
|
554
|
+
|
|
555
|
+
# Grupo 6: Auth Hooks
|
|
556
|
+
[auth.hook.custom_access_token]
|
|
557
|
+
enabled = true
|
|
558
|
+
uri = "pg-functions://postgres/auth/custom_access_token_hook"
|
|
559
|
+
secrets = "encrypted:LSi...hook-secret-encrypted...=="
|
|
560
|
+
|
|
561
|
+
[auth.hook.send_email]
|
|
562
|
+
enabled = true
|
|
563
|
+
uri = "https://example.com/auth/send-email-hook"
|
|
564
|
+
secrets = "encrypted:LSi...email-hook-secret-encrypted...=="
|
|
565
|
+
|
|
566
|
+
# Grupo 7: Auth SMS (Twilio)
|
|
567
|
+
[auth.sms.twilio]
|
|
568
|
+
enabled = true
|
|
569
|
+
account_sid = "ACxxxxxxxxxxxx"
|
|
570
|
+
message_service_sid = "MGxxxxxxxxxxxx"
|
|
571
|
+
auth_token = "encrypted:LSi...twilio-token-encrypted...=="
|
|
572
|
+
|
|
573
|
+
# Grupo 8: Auth External (GitHub OAuth)
|
|
574
|
+
[auth.external.github]
|
|
575
|
+
enabled = true
|
|
576
|
+
client_id = "Iv1.xxxxxxx"
|
|
577
|
+
secret = "encrypted:LSi...github-secret-encrypted...=="
|
|
578
|
+
|
|
579
|
+
# Grupo 9: Edge Runtime
|
|
580
|
+
[edge_runtime.secrets]
|
|
581
|
+
OPENAI_API_KEY = "encrypted:LSi...openai-edge-encrypted...=="
|
|
582
|
+
SENDGRID_API_KEY = "encrypted:LSi...sendgrid-edge-encrypted...=="
|
|
583
|
+
STRIPE_SECRET_KEY = "encrypted:LSi...stripe-edge-encrypted...=="
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Caveat — lista pode evoluir com versões do CLI
|
|
587
|
+
|
|
588
|
+
A lista de designated secret fields pode evoluir com novas versões do Supabase CLI (novos providers OAuth, novos Auth Hooks, etc.). Para refresh periódico:
|
|
589
|
+
|
|
590
|
+
```bash
|
|
591
|
+
# verificar versão do CLI
|
|
592
|
+
supabase --version
|
|
593
|
+
|
|
594
|
+
# consultar doc oficial:
|
|
595
|
+
# https://supabase.com/docs/guides/local-development/cli/config
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Recomendação canônica:** review trimestral da lista vs doc oficial — Supabase publica updates regularmente.
|
|
599
|
+
|
|
600
|
+
## Anti-patterns
|
|
601
|
+
|
|
602
|
+
### Anti-pattern 1: Usar `encrypted:` em field não-designated
|
|
603
|
+
|
|
604
|
+
**Errado:**
|
|
605
|
+
|
|
606
|
+
```toml
|
|
607
|
+
[auth.email.smtp]
|
|
608
|
+
host = "encrypted:LSi...wrong-host...==" # smtp.host NÃO é designated
|
|
609
|
+
port = 587
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
**Por quê:** valor literal é usado como string — SMTP tenta conectar em host literal `"encrypted:LSi...=="`, DNS lookup falha silenciosamente, emails não são enviados, sem erro claro no log.
|
|
613
|
+
|
|
614
|
+
**Certo:** consultar Pattern 5 — usar `encrypted:` APENAS nos grupos canônicos. Para `auth.email.smtp.host` use plaintext (não é secret) ou `env(SMTP_HOST)`:
|
|
615
|
+
|
|
616
|
+
```toml
|
|
617
|
+
[auth.email.smtp]
|
|
618
|
+
host = "smtp.sendgrid.net" # plaintext OK (não é secret)
|
|
619
|
+
port = 587
|
|
620
|
+
user = "apikey"
|
|
621
|
+
pass = "encrypted:LSi...correct-pass...==" # designated secret field
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Anti-pattern 2: Assumir secrets herdam entre branches
|
|
625
|
+
|
|
626
|
+
**Errado:** criar `staging` branch e assumir que `SENDGRID_API_KEY` do `main` está disponível.
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
supabase --experimental branches create staging --persistent
|
|
630
|
+
# (assume erradamente que secrets do main foram copiados)
|
|
631
|
+
|
|
632
|
+
# Edge Function no staging — falha
|
|
633
|
+
const apiKey = Deno.env.get("SENDGRID_API_KEY"); // undefined
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**Por quê:** secrets são **per-branch** — staging tem env vars vazias até `supabase secrets set` rodar separadamente; Edge Functions retornam `undefined`; código quebra sem erro claro no DAG.
|
|
637
|
+
|
|
638
|
+
**Certo:** rodar `supabase secrets set --env-file` para **CADA branch** (main + staging + preview + production):
|
|
639
|
+
|
|
640
|
+
```bash
|
|
641
|
+
# para cada branch
|
|
642
|
+
for branch in main staging production; do
|
|
643
|
+
supabase link --project-ref "${branch}-project-ref"
|
|
644
|
+
supabase secrets set --env-file "./supabase/.env.${branch}"
|
|
645
|
+
done
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Documentar workflow no onboarding do projeto.
|
|
649
|
+
|
|
650
|
+
### Anti-pattern 3: Commitar `.env.keys` no git
|
|
651
|
+
|
|
652
|
+
**Errado:** `.env.keys` aparece em `git status` e dev faz `git add` distraído:
|
|
653
|
+
|
|
654
|
+
```bash
|
|
655
|
+
git status
|
|
656
|
+
# Changes not staged for commit:
|
|
657
|
+
# modified: supabase/.env.preview
|
|
658
|
+
# modified: .env.keys ← BLOQUEANTE
|
|
659
|
+
git add .
|
|
660
|
+
git commit -m "feat: add preview secrets" # vazou a chave master
|
|
661
|
+
git push
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
**Por quê:** `.env.keys` é a chave de **decryption master** — com ela, qualquer um decripta `.env.preview`/`.env.production` e tem acesso a TODOS os secrets encrypted; equivalente a vazar password master + todos os tokens OAuth + todas as API keys de uma vez.
|
|
665
|
+
|
|
666
|
+
**Certo:**
|
|
667
|
+
|
|
668
|
+
```bash
|
|
669
|
+
# adicionar SEMPRE ao .gitignore — ANTES de qualquer set
|
|
670
|
+
echo ".env.keys" >> .gitignore
|
|
671
|
+
git add .gitignore
|
|
672
|
+
git commit -m "chore: gitignore dotenvx decryption key"
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Se foi committed por engano:
|
|
676
|
+
|
|
677
|
+
1. `git filter-repo` (ou BFG) para limpar history
|
|
678
|
+
2. **Rotacionar TODOS os secrets encrypted imediatamente** — sem confiar que ninguém viu antes
|
|
679
|
+
3. Re-encrypt valores em `.env.preview`/`.env.production` com nova `.env.keys`
|
|
680
|
+
4. Force-push branches afetados
|
|
681
|
+
5. Notificar team + auditar acessos
|
|
682
|
+
|
|
683
|
+
### Anti-pattern 4: Confundir `env()` vs `encrypted:` syntax
|
|
684
|
+
|
|
685
|
+
**Errado:** tentar combinar os dois prefixos:
|
|
686
|
+
|
|
687
|
+
```toml
|
|
688
|
+
[auth.external.github]
|
|
689
|
+
secret = "encrypted:env(GITHUB_SECRET)" # syntax inválida — mistura prefixos
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
**Por quê:** Supabase CLI parser não combina os dois — valor literal `"encrypted:env(GITHUB_SECRET)"` é usado como string, OAuth callback falha com `invalid client_secret`.
|
|
693
|
+
|
|
694
|
+
**Certo:** escolher UM:
|
|
695
|
+
|
|
696
|
+
```toml
|
|
697
|
+
# Option A: env() resolve via env var
|
|
698
|
+
[auth.external.github]
|
|
699
|
+
secret = "env(GITHUB_SECRET)"
|
|
700
|
+
|
|
701
|
+
# Option B: encrypted: via dotenvx decryption
|
|
702
|
+
[auth.external.github]
|
|
703
|
+
secret = "encrypted:LSi...payload-encrypted...=="
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
Nunca combinar.
|
|
707
|
+
|
|
708
|
+
### Anti-pattern 5: Reusar `project_id` entre `[remotes]` blocks
|
|
709
|
+
|
|
710
|
+
**Errado:**
|
|
711
|
+
|
|
712
|
+
```toml
|
|
713
|
+
[remotes.staging]
|
|
714
|
+
project_id = "main-project-ref" # ← mesmo ref do main
|
|
715
|
+
|
|
716
|
+
[remotes.production]
|
|
717
|
+
project_id = "main-project-ref" # ← mesmo ref do main
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
**Por quê:** `[remotes.<name>]` deve apontar para branch **DEDICADO** criado via `supabase --experimental branches create`; usar mesmo `project_id` para múltiplos `[remotes]` causa configs sobrescritas no DAG step 4 (configure) — última definição vence, comportamento imprevisível.
|
|
721
|
+
|
|
722
|
+
**Certo:** criar branch por ambiente + obter `project_id` único:
|
|
723
|
+
|
|
724
|
+
```bash
|
|
725
|
+
supabase --experimental branches create staging --persistent
|
|
726
|
+
supabase --experimental branches create production --persistent
|
|
727
|
+
supabase --experimental branches list
|
|
728
|
+
# BRANCH NAME BRANCH PROJECT ID
|
|
729
|
+
# main main-project-ref
|
|
730
|
+
# staging staging-dedicated-ref
|
|
731
|
+
# production production-dedicated-ref
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
```toml
|
|
735
|
+
[remotes.staging]
|
|
736
|
+
project_id = "staging-dedicated-ref"
|
|
737
|
+
|
|
738
|
+
[remotes.production]
|
|
739
|
+
project_id = "production-dedicated-ref"
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### Anti-pattern 6: Esperar `env()` em config.toml resolver para secrets do projeto
|
|
743
|
+
|
|
744
|
+
**Errado:** setar secret via `supabase secrets set` e esperar que `config.toml` com `env()` resolva:
|
|
745
|
+
|
|
746
|
+
```bash
|
|
747
|
+
# setar secret no projeto (runtime Edge Functions)
|
|
748
|
+
supabase secrets set SENDGRID_API_KEY=sk-real-key
|
|
749
|
+
|
|
750
|
+
# config.toml
|
|
751
|
+
[edge_runtime.secrets]
|
|
752
|
+
# expecta erradamente que o secret do projeto seja resolvido
|
|
753
|
+
SENDGRID_API_KEY = "env(SENDGRID_API_KEY)"
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
**Por quê:** `env()` em config.toml resolve para env var **do CLI local** (build-time), **NÃO para secrets do projeto Supabase** (runtime das Edge Functions). Se o shell que roda o CLI não tem `SENDGRID_API_KEY` exportado, resolve para string vazia → config quebrada.
|
|
757
|
+
|
|
758
|
+
**Certo:**
|
|
759
|
+
|
|
760
|
+
- **Para secrets de Edge Functions runtime:** `supabase secrets set` + `Deno.env.get("SENDGRID_API_KEY")` no código Deno
|
|
761
|
+
- **Para config.toml build-time:** setar env var no shell antes de rodar CLI:
|
|
762
|
+
|
|
763
|
+
```bash
|
|
764
|
+
export SENDGRID_API_KEY=sk-build-time-key
|
|
765
|
+
supabase db push
|
|
766
|
+
# config.toml com env(SENDGRID_API_KEY) resolve para "sk-build-time-key"
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
Em workflow CI (GitHub Actions): expor secret no env do step:
|
|
770
|
+
|
|
771
|
+
```yaml
|
|
772
|
+
- name: Push to Supabase
|
|
773
|
+
env:
|
|
774
|
+
SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
|
|
775
|
+
run: supabase db push
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
## Cross-suite integration (v1.27)
|
|
779
|
+
|
|
780
|
+
Esta skill é par-conjugado com `supabase-branching-workflow` (Phase 149) — branching workflow descreve **quando** branches são criados; config-toml-remotes descreve **como** configurar.
|
|
781
|
+
|
|
782
|
+
Cross-refs canônicas com outras skills v1.27 (Phases 150-153):
|
|
783
|
+
|
|
784
|
+
- **supabase-branching-workflow** (Phase 149) — Deploy DAG step 4 (configure) lê `[remotes.<branch>]` block desta skill
|
|
785
|
+
- **supabase-ci-cd-github-actions** (Phase 151, futura) — 8 workflows GitHub Actions que exportam env vars + rodam `supabase db push` com `--env-file` (cross-ref Pattern 3 + Pattern 4)
|
|
786
|
+
- **supabase-pgtap-testing** (Phase 152, futura) — testes pgTAP que rodam em remote branches via `--db-url` derivada de `[remotes.<branch>]`
|
|
787
|
+
- **supabase-migration-repair** (Phase 153, futura) — `migration repair` per `[remotes.<branch>]` quando drift detectado
|
|
788
|
+
|
|
789
|
+
Base para agent novo v1.27:
|
|
790
|
+
|
|
791
|
+
- **supabase-cicd-pipeline-implementer** (Phase 154, futura) — recebe spec via `Task()` e materializa `[remotes.<branch>]` blocks na config + GitHub Actions workflows com dotenvx integration
|
|
792
|
+
|
|
793
|
+
Pattern de handoff cooperativo herdado v1.23-v1.26: **architect** projeta strategy → **cicd-pipeline-implementer** materializa → **release-pipeline-auditor** (v1.10) audita hermeticidade. Nenhum agente descarta upstream — handoff cooperativo SQL (princípio canônico v1.23).
|
|
794
|
+
|
|
795
|
+
## Ver também
|
|
796
|
+
|
|
797
|
+
- [supabase-branching-workflow](../supabase-branching-workflow/SKILL.md) (v1.27, Phase 149) — pré-requisito conceitual; Deploy DAG step 4 (configure) aplica `[remotes]`
|
|
798
|
+
- [supabase-ci-cd-github-actions](../supabase-ci-cd-github-actions/SKILL.md) (v1.27, Phase 151) — workflows GitHub Actions com `--env-file` + `supabase secrets set`
|
|
799
|
+
- [supabase-pgtap-testing](../supabase-pgtap-testing/SKILL.md) (v1.27, Phase 152) — testes que rodam em remote branches via `--db-url`
|
|
800
|
+
- [supabase-migration-repair](../supabase-migration-repair/SKILL.md) (v1.27, Phase 153) — `migration repair` per `[remotes.<branch>]`
|
|
801
|
+
- [supabase-migrations](../supabase-migrations/SKILL.md) (v1.23) — migrations aplicadas no branch via `supabase db push --linked`
|
|
802
|
+
- [supabase-edge-functions](../supabase-edge-functions/SKILL.md) — `Deno.env.get()` lê secrets setados via `supabase secrets set --env-file`
|
|
803
|
+
- [supabase-auth-ssr](../supabase-auth-ssr/SKILL.md) — `auth.external.*.secret` encrypted fields usados no auth flow
|
|
804
|
+
- [supabase-custom-claims-rbac](../supabase-custom-claims-rbac/SKILL.md) (v1.25) — `auth.hook.custom_access_token.secrets` é Auth Hook (Grupo 6)
|
|
805
|
+
- [supabase-postgres-roles](../supabase-postgres-roles/SKILL.md) (v1.26) — cross-ref para system access via secrets DB (`db.root_key`, `db.vault`)
|
|
806
|
+
- [glossário compartilhado](../_shared-supabase/glossary.md) — termos `[remotes]`, encrypted:, env(), dotenvx, .env.keys, .env.preview, designated secret fields, branch project_id
|
|
807
|
+
- Doc oficial: [Branching Configuration](https://supabase.com/docs/guides/deployment/branching#configuration), [Config Reference](https://supabase.com/docs/guides/local-development/cli/config), [dotenvx](https://dotenvx.com/), [Auth Hooks](https://supabase.com/docs/guides/auth/auth-hooks)
|