From 64ea0dbab963d7ae1950fcc1c8bff32ae40625ee Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Tue, 18 Aug 2026 08:25:46 -0300 Subject: [PATCH] =?UTF-8?q?ops(OPS54):=20allowlist=20onlyBuiltDependencies?= =?UTF-8?q?=20migra=20para=20pnpm-workspace.yaml=20=E2=80=94=20fim=20do=20?= =?UTF-8?q?warning=20do=20pnpm=2010=20sobre=20o=20campo=20pnpm=20ignorado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 4 +- docs/CHANGELOG-AGENTS.md | 2 + docs/changelog/2026-08-18-ops54.md | 1 + ...pnpm-warning-onlybuiltdependencies-impl.md | 70 +++++++++++++++++++ package.json | 7 -- pnpm-workspace.yaml | 4 ++ 6 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 docs/changelog/2026-08-18-ops54.md create mode 100644 docs/plans/ops54-pnpm-warning-onlybuiltdependencies-impl.md create mode 100644 pnpm-workspace.yaml diff --git a/Dockerfile b/Dockerfile index a0da5256..43175c74 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,8 @@ RUN apk add --no-cache libc6-compat && corepack enable FROM base AS deps WORKDIR /app -# Install the pinned package manager and dependency graph. -COPY package.json pnpm-lock.yaml ./ +# pnpm-workspace.yaml carries onlyBuiltDependencies — pnpm 10 no longer reads the "pnpm" field. +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ RUN pnpm install --frozen-lockfile # One-shot image used to apply committed Payload migrations before a release. diff --git a/docs/CHANGELOG-AGENTS.md b/docs/CHANGELOG-AGENTS.md index 96de6280..a6698494 100644 --- a/docs/CHANGELOG-AGENTS.md +++ b/docs/CHANGELOG-AGENTS.md @@ -16,6 +16,8 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente **Recently resolved (2026-08-18):** **OPS52-media** — os objetos de media de produção (as ~40 capas dos posts, que existiam como rows com URL relativa `/api/media/file/` mas sem arquivo em lugar nenhum) são recuperáveis do WordPress de origem com `pnpm media:recover` (`scripts/recover-media.mjs`, novo): lê as rows de `media` + `post.coverImage` (mapeamento exato row→slug; fallback pelo filename determinístico `.`), resolve a capa com a MESMA lógica do seed (featured media do REST `_embed`, senão 1ª imagem inline do corpo — só 7/43 posts têm featured), baixa e faz `PutObject` no bucket das envs `S3_*` com key = `filename` da row, **sem nunca escrever no DB** (rows e URLs intocadas; o staticHandler do Payload passa a servir). Extraído para `scripts/lib/wpArticles.mjs` o fetch ao vivo do WordPress (seed-posts agora importa de lá — sem twin; unit-testado). Fail-closed: exige as 4 `S3_*` completas (`resolveS3StorageEnv` reusado; recuperação nunca vai pro storage local; `--verify` dispensa S3 — só HEAD de URLs públicas), `ALLOW_REMOTE_DB=true` explícito para DB remoto + echo do alvo (DB/bucket/endpoint/origin), timeouts curtos no SDK (`@smithy/node-http-handler`, 5s/15s) e nos fetches (30s/60s) — endpoint inalcançável falha em segundos em vez de pendurar (a rota pública de media de prod pendurava >25s; evidência de possível falta de rota container→Garage, diagnosticada no runbook do impl plan), e covers constrangidas a http(s) no host do WordPress com só `image/*` armazenado (sem SSRF/objeto não-imagem no proxy). Modos: reconcile (padrão, upload idempotente por overwrite), `--dry-run` (plano + `headObject`; exit 1 se qualquer checagem falhar), `--verify` (HEAD da URL pública por filename — o aceite da Issue, sem credencial). Runbook de execução no homeserver: `docs/plans/ops52-media-recuperar-arquivos-impl.md`. +**Recently resolved (2026-08-18):** **OPS54** — fim do warning do pnpm sobre o campo `pnpm` ignorado em `package.json`. A allowlist `onlyBuiltDependencies` (`sharp`, `esbuild`, `unrs-resolver`) migrou para o home canônico do pnpm 10: novo `pnpm-workspace.yaml` na raiz (sem `packages` — repo single-package, default `['.']`), e o bloco `"pnpm"` saiu do `package.json` (pnpm 10 não o lê mais; sem a remoção o warning persiste). `Dockerfile` estágio `deps` agora copia `pnpm-workspace.yaml` junto (`COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./`) — sem isso a allowlist não chegaria ao install da imagem e local×Docker divergiriam nos build scripts. Validado com a versão pinada (10.11.0) e no estágio deps real (`docker build --target deps`): nenhum `[WARN]` do campo `pnpm` em install/CI/Docker, `pnpm config get onlyBuiltDependencies` → os 3 pacotes, `--frozen-lockfile` limpo (lockfile e grafo intocados). Guardrails respeitados: `.npmrc` (`legacy-peer-deps`, `include`) e `packageManager` intocados; nada além do que o warning citava foi migrado (o aviso informativo de `msw`/`onnxruntime-node` é comportamento padrão do pnpm 10 — fora de escopo por anti-goal). Sem migration, sem UI, sem testes de domínio (config de ferramenta; gates completos verdes). Repo: `docs/plans/ops54-pnpm-warning-onlybuiltdependencies-impl.md`. + **Recently resolved (2026-08-17):** **OPS51** — o banco de produção saiu do Neon para o Postgres do homeserver (`teqo_1313`, container `teqo-1313`), sem mudança de config: o `~/stack/teqo-1313.env` já apontava para o banco preparado (criado 16/08 com role própria + cadeia completa de 56 migrations + zero conteúdo — verificado), então restaurar = a produção "apareceu" no container. **Divergência deliberada da intenção (questão A/B validada como B):** rejeitado criar `teqo_prod` novo — o argumento "o banco do 1313 tem vida própria" não se sustenta (o site 1313 É a produção deste repo) e o OPS53 já trata `teqo_1313` como produção. Execução 100% no homeserver (PII nunca tocou a workstation): URL do Neon puxada do Vercel (`vercel env pull`, projeto `jorgesolla`, `DATABASE_URL_UNPOOLED` → `NEON_DATABASE_URL` em `~/stack/.env` chmod 600), `pg_dump -Fc` (Neon PG 17.10) → `/srv/hdd/backups/teqo-neon-pre-migracao/teqo-neon-full-20260817-204800.dump` (5,8 MB, sha256 `f12196f2…`), `pg_restore --no-owner --no-privileges` como a role `teqo_1313` (drop schema + grant, padrão do `db-pull`), verificado: contagens por tabela idênticas ao Neon (1919 contatos, 39 posts, 1487 assinaturas, 1484 subscrições, 35 campaign_users, 392 lideranças, 2 pledges, 435 municípios, 6 atividades; supporter segue 0 — blocker LGPD ainda de pé), sequences no topo (`last_value == max(id)`), objetos com dono `teqo_1313`, `payload migrate` no-op (56 = 56, serviço de maintenance `teqo-1313-migrate`), 3 credenciais WebAuthn + 34 sessions + 5 chaves Consent restauradas (RP ID não mudou — biometria segue valendo). Smoke sem deploy: `/`, artigo com conteúdo restaurado, `/campanha/login`, `/admin`, `POST /api/revalidate` (`posts` + `global_privacy-policy`), WebAuthn `login-options`, barreira 307 sem sessão — verdes; smoke de browser (login, biometria, convites) validado manualmente. **Rollback documentado:** Neon nunca foi escrito (só lido); voltar = re-apontar `DATABASE_URL` do `teqo-1313.env` para o Neon + `compose up -d`. **Débito registrado (→ OPS52):** as 40 rows de `media` têm URLs relativas (`/api/media/file/…`) sem arquivos em lugar nenhum — capas dão 500 no homeserver e **404 no próprio Vercel/produção atual** (estado pré-existente; migração manteve paridade). Repo: plano da intenção concluído, `AGENTS.md` e help de `db:pull`/`check-push-chain` sem a referência ao Neon; infra-solla `STATE.md` atualizado à parte. **Recently resolved (2026-08-17):** **OPS53** — o deploy do site 1313 virou etapa do CI: mergir em `main` com a suite verde == site atualizado em `jorgesolla1313.com.br`, sem passo manual. O job `deploy` em `.forgejo/workflows/ci.yml` roda no host do runner (workstation, `runs-on: host`) e streama `scripts/deploy-homeserver.sh` para o homeserver via SSH (`ssh homeserver "bash -s -- "`); o script remoto (bash puro, homeserver sem dependências novas) faz: guard de HEAD (`git ls-remote` de `main` == SHA do job, senão skip "stale"), `flock` de serialização, workspace `~/teqo-deploy` (clone do Forgejo local), `docker login localhost:5000` (REGISTRY_USER/PASSWORD de `~/stack/.env`), build dos stages `runner`+`migrator` no homeserver (`--network stack_default` para a geração estática alcançar o `postgres:5432` do compose; secrets de `~/stack/teqo-1313.env` via BuildKit, sem camadas/logs), push no registry local, swap dos tags de imagem no compose (com backup `docker-compose.yml.pre-`), **migrate pelo serviço de maintenance `teqo-1313-migrate` antes do rollout**, `docker compose up -d`, espera do healthcheck e smoke (`/`, `/campanha/login`, `/admin`, barreira 307, WebAuthn `login-options` com body JSON, `POST /api/revalidate` com o secret real — rehearsal validado contra o site vivo). Falha pós-swap → rollback automático best-effort (restore do backup + `up -d` da imagem anterior) + job vermelho. **Divergência deliberada da intenção (fato novo):** a intenção assumia o runner no homeserver; verificado (`infra-solla/STATE.md` + ao vivo) que o runner é a `workstation-runner` na workstation e o stack de produção vive no homeserver — a abordagem A foi corrigida para "job `runs-on: host` na workstation + todo o deploy no homeserver via SSH", o que manteve **zero secrets novos no Forgejo** e zero mudança de infra no compose. Nenhum secret no repo; envs seguem chmod-600 no homeserver. Runbook (rollback manual, falhas conhecidas, decisão de segurança do host label): `docs/ops/teqo-1313-deploy.md` (novo). Guarda estrutural nova: `tests/unit/deployScript.unit.spec.ts` (bash -n + invariantes do pipeline: HEAD guard, BuildKit secrets, ordem migrate→rollout, smoke). AGENTS.md/AGENT-OPS.md atualizados. Primeiro deploy real = o merge deste próprio item (tracer bullet); infra-solla `STATE.md` anotado à parte. diff --git a/docs/changelog/2026-08-18-ops54.md b/docs/changelog/2026-08-18-ops54.md new file mode 100644 index 00000000..9f447fb6 --- /dev/null +++ b/docs/changelog/2026-08-18-ops54.md @@ -0,0 +1 @@ +**Recently resolved (2026-08-18):** **OPS54** — fim do warning do pnpm sobre o campo `pnpm` ignorado em `package.json`. A allowlist `onlyBuiltDependencies` (`sharp`, `esbuild`, `unrs-resolver`) migrou para o home canônico do pnpm 10: novo `pnpm-workspace.yaml` na raiz (sem `packages` — repo single-package, default `['.']`), e o bloco `"pnpm"` saiu do `package.json` (pnpm 10 não o lê mais; sem a remoção o warning persiste). `Dockerfile` estágio `deps` agora copia `pnpm-workspace.yaml` junto (`COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./`) — sem isso a allowlist não chegaria ao install da imagem e local×Docker divergiriam nos build scripts. Validado com a versão pinada (10.11.0) e no estágio deps real (`docker build --target deps`): nenhum `[WARN]` do campo `pnpm` em install/CI/Docker, `pnpm config get onlyBuiltDependencies` → os 3 pacotes, `--frozen-lockfile` limpo (lockfile e grafo intocados). Guardrails respeitados: `.npmrc` (`legacy-peer-deps`, `include`) e `packageManager` intocados; nada além do que o warning citava foi migrado (o aviso informativo de `msw`/`onnxruntime-node` é comportamento padrão do pnpm 10 — fora de escopo por anti-goal). Sem migration, sem UI, sem testes de domínio (config de ferramenta; gates completos verdes). Repo: `docs/plans/ops54-pnpm-warning-onlybuiltdependencies-impl.md`. diff --git a/docs/plans/ops54-pnpm-warning-onlybuiltdependencies-impl.md b/docs/plans/ops54-pnpm-warning-onlybuiltdependencies-impl.md new file mode 100644 index 00000000..d7e6aa48 --- /dev/null +++ b/docs/plans/ops54-pnpm-warning-onlybuiltdependencies-impl.md @@ -0,0 +1,70 @@ +# Impl: Acabar com o warning do pnpm sobre `pnpm.onlyBuiltDependencies` ignorado + +Status: aprovado +Atualizado em: 2026-08-18 +Issue: #12 +Intenção: docs/plans/ops54-pnpm-warning-onlybuiltdependencies.md +Appetite restante: herdado (~2–4 h; executável em bem menos — mudança de 3 arquivos) + +## Leitura da intenção + +- **Outcome:** nenhum comando pnpm (terminal, CI, Dockerfile) imprime o `[WARN]` do campo `pnpm`; a allowlist `onlyBuiltDependencies` (`sharp`, `esbuild`, `unrs-resolver`) volta a ser honrada no lugar canônico que o pnpm 10 aponta. +- **O que NÃO negociar:** `.npmrc` intocado (`legacy-peer-deps`, `include`); `packageManager` intocado; grafo de dependências inalterado (`pnpm install --frozen-lockfile` continua passando); nada além do que o warning cita é migrado. +- **O que reavaliar:** a hipótese da intenção já é a abordagem correta (pnpm-workspace.yaml). Ponto novo verificado empiricamente com a versão pinada (10.11.0): `pnpm-workspace.yaml` **sem** o campo `packages` funciona (single-package repo vira workspace de raiz, default `['.']`); o lockfile existente só tem um importer raiz — consistente. + +## Abordagem recomendada + +```mermaid +flowchart LR + A[package.json\nremove campo pnpm] --> C[pnpm-workspace.yaml\nonlyBuiltDependencies] + B[Dockerfile deps\n+ COPY pnpm-workspace.yaml] --> D[pnpm install --frozen-lockfile\nsem warning, allowlist honrada] + C --> D +``` + +**Opções consideradas:** A (pnpm-workspace.yaml — recomendado) | B (.npmrc) | C (manter campo + ignorar) +**Recomendação:** A — é o novo home canônico de settings do pnpm 10 e o destino que o próprio warning aponta; validado empiricamente com a versão pinada (10.11.0): sem warning, `pnpm config get onlyBuiltDependencies` → `sharp,esbuild,unrs-resolver`, `--frozen-lockfile` limpo. +**Rejeitadas:** + +- **B (.npmrc):** ainda suportado, mas caminho legado para este tipo de setting; o guardrail da intenção proíbe tocar `.npmrc` (e não há warning pedindo isso). +- **C (ignorar):** falha o aceite (warning persiste + allowlist continua ignorada). +- **(implicita) manter o campo `pnpm`:** o warning só some com a remoção do campo — a config no novo lugar não silencia o aviso. + +### Componentes / mudanças + +- **`pnpm-workspace.yaml`** (novo, raiz): `onlyBuiltDependencies: [sharp, esbuild, unrs-resolver]`. Sem campo `packages` (default `['.']` em pnpm 10.7+; repo single-package — validado). Sem comentários. +- **`package.json`**: remover o bloco `"pnpm": { "onlyBuiltDependencies": [...] }` (linhas 186–192). Nada mais no arquivo muda. +- **`Dockerfile`** (estágio `deps`, linha atual `COPY package.json pnpm-lock.yaml ./`): passar a copiar também `pnpm-workspace.yaml` — o `pnpm install --frozen-lockfile` da imagem precisa da config para honrar a allowlist (sem ela, local e Docker divergiriam: local rodaria os builds de `sharp`/`esbuild`/`unrs-resolver`, Docker não). Estágios `builder`/`migrator` usam `COPY . .` — o `.dockerignore` não exclui o YAML, já cobertos. +- **Changelog:** `docs/changelog/2026-08-18-ops54.md` + `pnpm changelog:build` (OPS44). +- **Migration:** sem migration (config de ferramenta). +- **Access / Consent / UI:** N/A. + +### Dados → forma (se aplicável) + +N/A — sem métricas/UI. + +## Fases verificáveis + +1. **Config + Dockerfile** — criar `pnpm-workspace.yaml`, remover campo `pnpm`, ajustar COPY do `deps`. +2. **Verificação local** — `pnpm install --frozen-lockfile` (sem warning, sem diff no lockfile — `git status` limpo depois); `pnpm config get onlyBuiltDependencies` → 3 pacotes; rodada de gates: `typecheck`, `lint`, `format:check`, `knip`, `check:cycles`, `test:unit`. +3. **Docker** — `docker build --target deps .` (não precisa de secrets) provando o estágio deps com a config nova. +4. **Gates** — `pnpm gate:fast`; push via `pnpm push`; CI Forgejo verde (o CI roda `pnpm install --frozen-lockfile` em todos os jobs — é a prova final do warning sumindo). + +## Rabbit holes / Não escopo (engenharia) + +- Mover `legacy-peer-deps` / `include` do `.npmrc` para o YAML — fora de escopo (nenhum warning pede). +- `dangerouslyAllowAllBuilds` ou re-approve de outros pacotes — fora de escopo. +- Atualizar pnpm / `packageManager` — fora de escopo. +- Comentários no YAML — não adicionar (convenção do repo); o plano + changelog documentam o porquê. + +## Riscos e mitigação + +- **`pnpm-workspace.yaml` sem `packages` muda semântica de workspace?** Baixo: pnpm 10.7+ defaulta `packages: ['.']`; lockfile atual tem um único importer raiz; validado no sandbox com a versão pinada (install + frozen-lockfile limpos). Se `pnpm install` local apontar drift, o passo 2 pega na hora. +- **Docker build sem a config no `deps`** silenciosamente bloquearia os builds dos 3 pacotes na imagem (regressão de comportamento local×Docker): mitigado pelo COPY explícito + verificação com `docker build --target deps`. +- **OPS53 compartilha o Dockerfile:** já resolvido — OPS53 está merged em `main` (6a3f61f9); sem concorrência em andamento. +- **CI com cache pnpm (pnpm/action-setup):** o cache é por lockfile — inalterado — então `cache: pnpm` segue batendo. Sem risco. + +## Aceite de engenharia + +- [x] Aceite de produto da intenção ainda coberto (warning some; allowlist honrada; `.npmrc`/`packageManager`/grafo intactos) +- [x] Invariantes AGENTS/engineering-standards (sem código runtime tocado; sem migration; sem DB) +- [x] Testes de domínio previstos: N/A (sem access/write paths); verificação empírica local + estágio Docker deps + CI como prova diff --git a/package.json b/package.json index 2e965454..6bd679b9 100644 --- a/package.json +++ b/package.json @@ -186,13 +186,6 @@ "node": "24.x", "pnpm": "^9 || ^10" }, - "pnpm": { - "onlyBuiltDependencies": [ - "sharp", - "esbuild", - "unrs-resolver" - ] - }, "packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977", "private": true } diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..a07f6284 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +onlyBuiltDependencies: + - sharp + - esbuild + - unrs-resolver -- 2.45.2