mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
fix(worktree): espelha PORTAL_TRANSPARENCIA_API_KEY no env provisionado
A lista de envs espelhadas sai do inline do worktree.mjs para o helper puro MIRRORED_WORKTREE_ENV_KEYS/mirroredEnvCopiedLines (worktree-env.mjs, unit-testado) e passa a incluir a chave do Portal da Transparência: sem ela, build-city-report num worktree degradava as emendas oficiais para lacuna mesmo com a chave no checkout principal. .env.example documenta a chave e o espelhamento.
This commit is contained in:
parent
162dc8d017
commit
f29e8357e0
5 changed files with 70 additions and 9 deletions
|
|
@ -88,3 +88,10 @@ GOOGLE_CALENDAR_OAUTH_CLIENT_SECRET=
|
|||
# point it at a fake binary, and a host without ffmpeg can install it or set
|
||||
# this to a wrapper.
|
||||
FFMPEG_PATH=
|
||||
|
||||
# C163/C190 — Portal da Transparência API key used by the city/dossiê report
|
||||
# scripts to fetch official emendas (`JORGE SOLLA`). Optional: without it the
|
||||
# official emendas block degrades to an explicit gap (never zero silently).
|
||||
# `pnpm worktree next` mirrors this key into the worktree `.env.local` when it
|
||||
# is set here, so report builds run with the same source as the main checkout.
|
||||
PORTAL_TRANSPARENCIA_API_KEY=
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
**Worktree espelha `PORTAL_TRANSPARENCIA_API_KEY` no `.env.local` (2026-09-21):** o provisionamento por worktree copiava `PAYLOAD_SECRET`/`S3_*`/VAPID/Resend, mas não a chave do Portal da Transparência — então `node scripts/build-city-report.mjs` num worktree degradava as emendas oficiais para lacuna (`Chave da API do Portal da Transparência ausente.`) mesmo com a chave presente no checkout principal (visto no relatório de Miguel Calmon, C163). Correção no dono: a lista de envs espelhadas saiu do inline de `scripts/worktree.mjs` para `MIRRORED_WORKTREE_ENV_KEYS` + `mirroredEnvCopiedLines` em `scripts/lib/worktree-env.mjs` (função pura, unit-testada) e agora inclui `PORTAL_TRANSPARENCIA_API_KEY`; `.env.example` documenta a chave e o espelhamento. Sem schema, sem migration e sem mudança de URL pública — scripts + teste + doc.
|
||||
|
|
@ -77,6 +77,36 @@ export const s3EnvCopiedLines = (env) =>
|
|||
? [...S3_WORKTREE_REQUIRED_KEYS, 'S3_REGION'].map((key) => `${key}=${env[key]}`)
|
||||
: []
|
||||
|
||||
/**
|
||||
* Optional env keys mirrored from the main checkout into a worktree's
|
||||
* `.env.local` when present there (PAYLOAD_SECRET, DB and port come from the
|
||||
* caller). This list is the single owner of "what `pnpm worktree next`
|
||||
* copies": a key that exists in the main env but is missing here silently
|
||||
* degrades every worktree — `PORTAL_TRANSPARENCIA_API_KEY` is the report
|
||||
* scripts' case (C163/C190: without the mirror, official emendas became a
|
||||
* gap in the worktree even though the main env had the key).
|
||||
*/
|
||||
const MIRRORED_WORKTREE_ENV_KEYS = [
|
||||
'NEXT_PUBLIC_VAPID_PUBLIC_KEY',
|
||||
'VAPID_PUBLIC_KEY',
|
||||
'VAPID_PRIVATE_KEY',
|
||||
'VAPID_SUBJECT',
|
||||
'RESEND_API_KEY',
|
||||
'CAMPAIGN_EMAIL_FROM',
|
||||
'CAMPAIGN_EMAIL_FROM_NAME',
|
||||
'PORTAL_TRANSPARENCIA_API_KEY',
|
||||
]
|
||||
|
||||
/**
|
||||
* `KEY=value` lines for the mirrored keys present in `env`, in list order.
|
||||
* An absent/empty key copies nothing (same fail-open semantics as before).
|
||||
*
|
||||
* @param {Record<string, string | undefined>} env
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export const mirroredEnvCopiedLines = (env) =>
|
||||
MIRRORED_WORKTREE_ENV_KEYS.filter((key) => env[key]).map((key) => `${key}=${env[key]}`)
|
||||
|
||||
/**
|
||||
* Final environment for a branch. `takenSlots` = slots already claimed by
|
||||
* OTHER live worktrees; bumps +1 until free (bounded — live slot sets are
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ import {
|
|||
DEV_PORT_BASE,
|
||||
GENERATED_ENV_MARKER,
|
||||
isGeneratedDatabaseName,
|
||||
mirroredEnvCopiedLines,
|
||||
s3EnvCopiedLines,
|
||||
worktreeEnvFileContents,
|
||||
worktreeEnvironment,
|
||||
|
|
@ -503,8 +504,6 @@ const provision = async ({ dir, branch, issue, env, skipMigrate, mainRoot, purpo
|
|||
const devUrl = `postgresql://teqo:teqo@localhost:5432/${devDatabase}`
|
||||
const testUrl = `postgresql://teqo:teqo@localhost:5432/${testDatabase}`
|
||||
|
||||
const copy = (key) => (mainEnv[key] ? [`${key}=${mainEnv[key]}`] : [])
|
||||
|
||||
const issueLabel = issue ? ` · issue #${issue.number}` : ''
|
||||
const generatedBy = `gerado por pnpm worktree ${purpose}`
|
||||
|
||||
|
|
@ -517,13 +516,9 @@ const provision = async ({ dir, branch, issue, env, skipMigrate, mainRoot, purpo
|
|||
copiedLines: [
|
||||
// Media storage (OPS52): all-or-nothing (see s3EnvCopiedLines).
|
||||
...s3EnvCopiedLines(mainEnv),
|
||||
...copy('NEXT_PUBLIC_VAPID_PUBLIC_KEY'),
|
||||
...copy('VAPID_PUBLIC_KEY'),
|
||||
...copy('VAPID_PRIVATE_KEY'),
|
||||
...copy('VAPID_SUBJECT'),
|
||||
...copy('RESEND_API_KEY'),
|
||||
...copy('CAMPAIGN_EMAIL_FROM'),
|
||||
...copy('CAMPAIGN_EMAIL_FROM_NAME'),
|
||||
// Optional secrets mirrored from the main env (single owner:
|
||||
// MIRRORED_WORKTREE_ENV_KEYS in scripts/lib/worktree-env.mjs).
|
||||
...mirroredEnvCopiedLines(mainEnv),
|
||||
],
|
||||
})
|
||||
writeFileSync(join(dir, '.env.local'), devLines.join('\n'))
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
GENERATED_ENV_MARKER,
|
||||
hashSlotOf,
|
||||
isGeneratedDatabaseName,
|
||||
mirroredEnvCopiedLines,
|
||||
numericSlotOfCode,
|
||||
s3EnvCopiedLines,
|
||||
testDatabaseForSlot,
|
||||
|
|
@ -886,6 +887,33 @@ describe('s3EnvCopiedLines (OPS52 media storage, all-or-nothing)', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('mirroredEnvCopiedLines (optional envs mirrored into the worktree)', () => {
|
||||
it('copies PORTAL_TRANSPARENCIA_API_KEY from the main env (C163/C190 reports)', () => {
|
||||
expect(mirroredEnvCopiedLines({ PORTAL_TRANSPARENCIA_API_KEY: 'eb32-key' })).toEqual([
|
||||
'PORTAL_TRANSPARENCIA_API_KEY=eb32-key',
|
||||
])
|
||||
})
|
||||
|
||||
it('copies every mirrored key present, in a stable order, skipping absent ones', () => {
|
||||
expect(
|
||||
mirroredEnvCopiedLines({
|
||||
RESEND_API_KEY: 're_1',
|
||||
VAPID_PRIVATE_KEY: 'priv',
|
||||
PORTAL_TRANSPARENCIA_API_KEY: 'eb32-key',
|
||||
}),
|
||||
).toEqual([
|
||||
'VAPID_PRIVATE_KEY=priv',
|
||||
'RESEND_API_KEY=re_1',
|
||||
'PORTAL_TRANSPARENCIA_API_KEY=eb32-key',
|
||||
])
|
||||
})
|
||||
|
||||
it('copies nothing when no mirrored key is set', () => {
|
||||
expect(mirroredEnvCopiedLines({ DATABASE_URL: 'x' })).toEqual([])
|
||||
expect(mirroredEnvCopiedLines({ PORTAL_TRANSPARENCIA_API_KEY: '' })).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('worktreeEnvFileContents (dev/test env parity)', () => {
|
||||
const env = worktreeEnvironment({ branch: 'C15-fullcalendar', code: 'C15' })
|
||||
const lines = worktreeEnvFileContents({
|
||||
|
|
|
|||
Loading…
Reference in a new issue