From 81513d5b14de263d2aa8db2013c7772808a7e6d4 Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Thu, 27 Aug 2026 08:40:25 -0300 Subject: [PATCH] =?UTF-8?q?fix(deploy):=20reverte=20package.json=20para=20?= =?UTF-8?q?desbloquear=20o=20deploy=20=E2=80=94=20cache=20deps=20do=20Buil?= =?UTF-8?q?dKit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O deploy de fea6c645 falhou 2x: a mudança do script generate:importmap em package.json invalidou a cache da camada deps do Dockerfile no homeserver, e o pnpm install re-rodou do zero — o postinstall do sharp@0.32.6 (transitivo) estourou o timeout baixando o libvips de objects.githubusercontent.com ('sharp: Installation error: Request timed out'; o git fetch de github.com funciona — o release vai por outro hostname da CDN). Produção intocada (falha pré compose swap). Reverte package.json ao byte do estado cacheado (a9f0c61e) — o install nem roda. Remove o wrapper generate-importmap.mjs (desligado vira dead code); proteção do importMap fica com o guard CI+deploy + pin unit + contrato. Hardening do deps documentado no post-mortem (retry do install / libvips via apk / proxy), changelog do follow-up incluído. --- ...8-27-admin-branco-importmap-s3-followup.md | 1 + .../2026-08-26-admin-branco-importmap-s3.md | 27 +++++++------- package.json | 2 +- scripts/generate-importmap.mjs | 35 ------------------- 4 files changed, 16 insertions(+), 49 deletions(-) create mode 100644 docs/changelog/2026-08-27-admin-branco-importmap-s3-followup.md delete mode 100644 scripts/generate-importmap.mjs diff --git a/docs/changelog/2026-08-27-admin-branco-importmap-s3-followup.md b/docs/changelog/2026-08-27-admin-branco-importmap-s3-followup.md new file mode 100644 index 00000000..ce4b519a --- /dev/null +++ b/docs/changelog/2026-08-27-admin-branco-importmap-s3-followup.md @@ -0,0 +1 @@ +**Admin em branco — follow-up: deploy bloqueado pelo reinstall do deps, package.json revertido (2026-08-27):** o fix do importMap (#926, main em `fea6c645`) não conseguia PUBLICAR: o deploy manual falhou 2× no build do migrator — a mudança de `package.json` (script `generate:importmap` → wrapper) invalidou a cache BuildKit da camada `deps` do Dockerfile, o `pnpm install --frozen-lockfile` re-rodou do zero e o `postinstall` do `sharp@0.32.6` (transitivo) estourou o timeout baixando o libvips de `objects.githubusercontent.com` no homeserver (`sharp: Installation error: Request timed out`; o `git fetch` de github.com funciona — o release vai por hostname diferente da CDN). Produção ficou intocada (falha antes do compose swap). Correção: `package.json` revertido ao byte do estado cacheado (`a9f0c61e`) — a cache do `deps` volta a valer e o install nem roda; wrapper `scripts/generate-importmap.mjs` **removido** (ficaria desligado — dead code); proteção mantida pelo guard `check-importmap-s3.mjs` (ci-pr.yml + verify do deploy) + pin unit + contrato. Dívida documentada no post-mortem: hardening da camada `deps` (retry do install / libvips via apk / proxy do download) — sem ele, qualquer mudança futura em package.json/pnpm-lock/pnpm-workspace volta a bustar a cache e travar o deploy igual. Ação: re-dispatch manual do `deploy.yml` (o guard do HEAD exige main atual; o `verify` já passou 19m verde no run anterior). diff --git a/docs/postmortems/2026-08-26-admin-branco-importmap-s3.md b/docs/postmortems/2026-08-26-admin-branco-importmap-s3.md index ac8b693a..2cbc981d 100644 --- a/docs/postmortems/2026-08-26-admin-branco-importmap-s3.md +++ b/docs/postmortems/2026-08-26-admin-branco-importmap-s3.md @@ -58,21 +58,22 @@ Regeneração do importMap com envs S3\_\* dummy — o diff foi de exatamente +2 ## Prevenção -| Estratégia | Custo | Estado | -| ------------------------------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------ | -| Pin unit `importMapS3UploadHandler.unit.spec.ts` (falha se a entrada sumir) | barata | implementada agora (mesmo PR) | -| Guard `scripts/check-importmap-s3.mjs` no ci-pr.yml (content guards) e no job verify do deploy.yml | barata | implementada agora (mesmo PR) | -| Wrapper `scripts/generate-importmap.mjs` no `pnpm generate:importmap` (injeta S3\_\* dummy quando ausentes) | barata | implementada agora (mesmo PR) | -| Contrato compartilhado `scripts/lib/importMapContract.mjs` (chave + prefixo do handler, chaves das envs S3) | barata | implementada agora (mesmo PR) | -| AGENTS.md: instrução das envs S3\_\* no generate:importmap + referência aos guards | barata | implementada agora (mesmo PR) | -| Gerar o importMap no BUILD (prebuild com S3\_\* via BuildKit secrets) em vez de commitá-lo | cara | documentada — não implementada neste fluxo | -| Tornar o plugin s3Storage incondicional no config (adaptador local em dev) | cara | documentada — não implementada neste fluxo | -| Smoke real de deploy: abrir /admin em headless e assertar o mount da raiz Payload (não só HTTP 200) | cara | documentada — não implementada neste fluxo | -| Fail-fast/erro estruturado quando getFromImportMap retorna undefined (hoje é console.error silencioso no log do servidor) | cara | documentada — não implementada neste fluxo | +| Estratégia | Custo | Estado | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Pin unit `importMapS3UploadHandler.unit.spec.ts` (falha se a entrada sumir) | barata | implementada agora (mesmo PR) | +| Guard `scripts/check-importmap-s3.mjs` no ci-pr.yml (content guards) e no job verify do deploy.yml | barata | implementada agora (mesmo PR) | +| Wrapper `scripts/generate-importmap.mjs` no `pnpm generate:importmap` (injeta S3\_\* dummy quando ausentes) | barata | removida no follow-up (2026-08-27) — a mudança de package.json invalida a cache BuildKit da camada `deps` no homeserver e força reinstall cujo `postinstall` do `sharp@0.32.6` falha (timeout do libvips em objects.githubusercontent.com; 2 deploys falhos). Re-ligar junto com o hardening do Dockerfile | +| Contrato compartilhado `scripts/lib/importMapContract.mjs` (chave + prefixo do handler, chaves das envs S3) | barata | implementada agora (mesmo PR) | +| AGENTS.md: instrução das envs S3\_\* no generate:importmap + referência aos guards | barata | implementada agora (mesmo PR) | +| Gerar o importMap no BUILD (prebuild com S3\_\* via BuildKit secrets) em vez de commitá-lo | cara | documentada — não implementada neste fluxo | +| Tornar o plugin s3Storage incondicional no config (adaptador local em dev) | cara | documentada — não implementada neste fluxo | +| Smoke real de deploy: abrir /admin em headless e assertar o mount da raiz Payload (não só HTTP 200) | cara | documentada — não implementada neste fluxo | +| Fail-fast/erro estruturado quando getFromImportMap retorna undefined (hoje é console.error silencioso no log do servidor) | cara | documentada — não implementada neste fluxo | +| Hardening da camada `deps` do Dockerfile (retry do `pnpm install` / libvips via apk / proxy do download do sharp) — qualquer mudança em package.json/pnpm-lock/pnpm-workspace busta a cache e o egress do homeserver para objects.githubusercontent.com não conclui downloads | cara | documentada — não implementada neste fluxo | -**Estratégia implementada:** pin unit que falha se o handler sumir do importMap; guard de CI+deploy que regenera com S3\_\* dummy e falha em divergência (drift + restore do arquivo); wrapper do `generate:importmap` que injeta as envs dummy — a regeneração local nunca mais orfa o handler; contrato compartilhado da chave/prefixo e das envs; doc no AGENTS.md. +**Estratégia implementada:** pin unit que falha se o handler sumir do importMap; guard de CI+deploy que regenera com S3\_\* dummy e falha em divergência (drift + restore do arquivo); contrato compartilhado da chave/prefixo e das envs; doc no AGENTS.md. O wrapper do `generate:importmap` foi removido no follow-up (a mudança de package.json que o ligava quebrou o deploy — ver tabela); a proteção fica com o guard + pin. -**Estratégia documentada (cara):** gerar o importMap no build (elimina a classe: artefato gerado não drift; toca o pipeline do homeserver); tornar o s3Storage incondicional (estabiliza o importMap; muda storage local e caminho de media); smoke de deploy que abre /admin em headless e asserta o mount da raiz Payload; fail-fast estruturado quando getFromImportMap retorna undefined. +**Estratégia documentada (cara):** gerar o importMap no build (elimina a classe: artefato gerado não drift; toca o pipeline do homeserver); tornar o s3Storage incondicional (estabiliza o importMap; muda storage local e caminho de media); smoke de deploy que abre /admin em headless e asserta o mount da raiz Payload; fail-fast estruturado quando getFromImportMap retorna undefined; hardening da camada `deps` do Dockerfile contra o reinstall completo no homeserver. ## Lições diff --git a/package.json b/package.json index 6da40862..ff71b37c 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "changelog:build": "node scripts/build-changelog.mjs", "changelog:read": "node scripts/build-changelog.mjs --stdout", "changelog:check": "node scripts/build-changelog.mjs --check", - "generate:importmap": "node scripts/generate-importmap.mjs", + "generate:importmap": "cross-env NODE_OPTIONS=\"--no-deprecation --conditions=react-server\" payload generate:importmap", "generate:types": "cross-env NODE_OPTIONS=\"--no-deprecation --conditions=react-server\" payload generate:types", "migrate": "cross-env NODE_OPTIONS=\"--no-deprecation --conditions=react-server\" payload migrate", "migrate:create": "cross-env NODE_OPTIONS=\"--no-deprecation --conditions=react-server\" payload migrate:create", diff --git a/scripts/generate-importmap.mjs b/scripts/generate-importmap.mjs deleted file mode 100644 index 95622039..00000000 --- a/scripts/generate-importmap.mjs +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node -/** - * Wrapper for `payload generate:importmap` that always injects dummy S3_* - * envs (when unset) so the generated importMap carries the - * S3ClientUploadHandler entry — regenerating without the S3_* envs silently - * orphans it and the admin goes blank in production (class - * OPS69/OPS72/OPS73). Dummy values are fine: the generator only iterates the - * config, it never connects to the bucket. - */ -import { spawnSync } from 'node:child_process' - -import { S3_STORAGE_ENV_KEYS } from './lib/importMapContract.mjs' - -const DUMMY = { - S3_BUCKET: 'dev-dummy-bucket', - S3_ENDPOINT: 'http://127.0.0.1:3900', - S3_ACCESS_KEY_ID: 'dev-dummy-access-key', - S3_SECRET_ACCESS_KEY: 'dev-dummy-secret-key', -} - -const env = { - ...process.env, - // Same NODE_OPTIONS as before — the payload CLI loads server-only modules. - NODE_OPTIONS: '--no-deprecation --conditions=react-server', - ...Object.fromEntries( - S3_STORAGE_ENV_KEYS.map((key) => [key, process.env[key]?.trim() || DUMMY[key]]), - ), -} - -const result = spawnSync('payload', ['generate:importmap'], { - stdio: 'inherit', - env, -}) - -process.exit(result.status ?? 1)