mirror of
https://github.com/melgarafael/DeskcommCRM.git
synced 2026-10-02 01:28:34 +08:00
fix(kit): a guarda de ARM só considera instalação real
O #1775 separou instalação NOVA (recusa em não-x86_64) de instalação existente (aviso, e o script segue até o build local), mas o critério de "existente" lia o estado do DIRETÓRIO: compose E um `.env`. Um `install.sh --yes` numa VPS ARM NOVA cujo `.env` chegou pronto — copiado de outra máquina, gerado por automação, ou deixado por uma rodada que parou no meio — passava como instalação existente e ia construir as imagens na própria VPS, 15 a 25 minutos depois de a guarda ter recusado tudo o que devia. O que passa a provar a instalação é o que ela DEIXOU: o marcador .deskcomm-instalado, que o install.sh grava quando o app está saudável; um contêiner do projeto Docker desta instalação, parado ou não, que é o caso de quem instalou numa versão anterior; e o contêiner do Supabase single-server. O filtro de contêiner é por projeto — o de outro programa na mesma VPS não vale, e uma VPS com WordPress é a regra, não a exceção. O volume do Postgres, sugerido na issue, NÃO entra: ele só existe no modo single-server e some com o `down -v` que o próprio kit ensina como receita de "recomeçar", então quem o encontrasse seria uma instalação derrubada. A guarda só pergunta isso quando a arquitetura não é suportada — em amd64 o veredito já é amd64, e perguntar chamaria o docker no topo do install.sh sem necessidade. As duas receitas de "recomeçar" (o painel de recuperação e a do banner final) apagam o marcador junto com o `.env`, e o `.gitignore` o declara como estado da VPS. A fixture do teste do #1775 passa a gravar o marcador: ela representa uma instalação que já passou pelo instalador, e sem o marcador o `docker ps` do dublê (que devolve vazio) faria aquela prova medir uma instalação NOVA. Teste novo com 46 asserções em 7 seções: o caso da issue (.env + nada instalado → recusa), os três sinais de instalação real, o que NÃO é prova (contêiner de outro projeto, docker indisponível, ausência de .env), x86_64 sem tocar no docker, a fórmula do nome do projeto medida contra nome_do_projeto_compose, o marcador, e a remoção do nome antigo. Refs: #1778 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0496190f3a
commit
2424a24c8b
@@ -0,0 +1,23 @@
|
||||
---
|
||||
impacto: nada_mudou
|
||||
secao: corrigido
|
||||
titulo: Instalar pela primeira vez numa VPS ARM volta a ser recusado, mesmo com o .env já preenchido
|
||||
---
|
||||
|
||||
Se você está começando a instalar o DeskcommCRM numa VPS ARM (Oracle Ampere,
|
||||
aarch64) e o `install.sh` recusava dizendo que só existe VPS x86_64, a causa
|
||||
estava no `.env`: uma pasta com o arquivo de configuração preenchido — copiado de
|
||||
outra máquina, gerado por automação, ou deixado por uma instalação que parou no
|
||||
meio — era confundida com uma instalação que já estava no ar. O instalador então
|
||||
aceitava seguir e passava 15 a 25 minutos construindo as imagens na própria VPS,
|
||||
quando o certo era recusar logo no começo.
|
||||
|
||||
Agora a instalação é reconhecida pelo que ela deixou de verdade: os contêineres
|
||||
do DeskcommCRM (ou do seu Supabase) no Docker, ou o arquivo que o próprio
|
||||
instalador grava quando termina. Quem já tinha o CRM rodando numa VPS ARM
|
||||
continua atualizando normalmente, aviso e build local inclusos.
|
||||
|
||||
Se você usa o comando de "recomeçar" (`docker compose down -v && rm -f .env`),
|
||||
ele passou a apagar esse arquivo junto — ele faz parte do estado da instalação.
|
||||
|
||||
Contribuição de @webtecnica (#1778).
|
||||
@@ -154,6 +154,11 @@ backups/
|
||||
# Marcas de execução do kit (agent.sh / update.sh)
|
||||
.update.lock
|
||||
.deskcomm-site-url-avisado
|
||||
# Marcador que o install.sh grava quando a instalação termina com o app no ar,
|
||||
# e que a guarda de arquitetura (#1042/#1266) lê para distinguir instalação NOVA
|
||||
# de instalação existente numa VPS ARM (#1778). É estado da máquina de quem
|
||||
# instalou, nunca entra no repositório — igual ao `.env` que mora ao lado dele.
|
||||
.deskcomm-instalado
|
||||
|
||||
# Dump de banco de QA. A doutrina já estava escrita duas linhas acima e só o
|
||||
# PADRÃO faltava: `backups/` não casa com `.qa-backups/`, e um dump de 1,1 MB de
|
||||
|
||||
+103
-14
@@ -32,7 +32,7 @@ arquitetura_suportada_pelo_kit() {
|
||||
esac
|
||||
}
|
||||
|
||||
# ── JÁ EXISTE UMA INSTALAÇÃO AQUI? (#1266) ───────────────────────────────────
|
||||
# ── JÁ EXISTE UMA INSTALAÇÃO REAL AQUI? (#1266, corrigido pelo #1778) ───────
|
||||
#
|
||||
# A guarda do #1042 vivia no TOPO dos dois scripts, e por isso matava antes de
|
||||
# chegar ao `construir_aqui_e_subir` (#1060/#1143) — a recuperação por build
|
||||
@@ -42,24 +42,105 @@ arquitetura_suportada_pelo_kit() {
|
||||
# que deixava quem já tinha uma instalação ARM funcionando PERMANENTEMENTE sem
|
||||
# poder rodar `update.sh` de novo, e sem bandeira nenhuma.
|
||||
#
|
||||
# O sinal é o mesmo que o `enter_project` usa para achar o projeto: o compose E
|
||||
# um `.env`. Num kit recém-clonado não existe nenhum dos dois (o install.sh
|
||||
# escreve o `.env` bem depois de sourcear este arquivo), então uma instalação
|
||||
# NOVA continua sendo recusada — que é o que a guarda do #1042 acertou. Numa
|
||||
# instalação que JÁ EXISTE os dois estão lá, e é nesse caso que a recusa vira
|
||||
# aviso: o caminho de recuperação do #1060/#1143 existe e continua depois
|
||||
# daqui, sem nada a travar.
|
||||
# O sinal NÃO pode ser o estado do DIRETÓRIO. "compose + `.env`" chega junto
|
||||
# numa instalação NOVA: o `.env` pode ter sido copiado de outra máquina, gerado
|
||||
# por automação, ou deixado por uma rodada anterior do `--yes` que parou no
|
||||
# meio. Com esse critério, um `install.sh --yes` numa VPS ARM NOVA com o `.env`
|
||||
# já preenchido passava pela guarda como se fosse instalação existente e ia
|
||||
# construir as imagens na própria VPS (15–25 min) — exatamente o que a guarda
|
||||
# do #1042 existe para impedir. E o `.env` sozinho nunca provou nada: o
|
||||
# `git clone` de uma instalação nova pode trazer um `.env` de exemplo.
|
||||
#
|
||||
# O `.env` sozinho não serve: o `git clone` de uma instalação nova pode trazer
|
||||
# um `.env` de exemplo, e recusar (ou seguir) por causa dele seria adivinhar.
|
||||
instalacao_do_kit_ja_existe() {
|
||||
local d
|
||||
# O sinal do DIRETÓRIO entra como CONDIÇÃO, nunca como prova: sem compose nem
|
||||
# `.env` não há nem nome de projeto para procurar, e o marcador — que só o
|
||||
# install.sh escreve, e sempre ao lado do `.env` — é o mesmo par sem prova.
|
||||
#
|
||||
# O que prova é o que a instalação DEIXOU no Docker, e a guarda pergunta ao
|
||||
# Docker diretamente. `nome_do_projeto_compose` mora mais abaixo, no bloco de
|
||||
# proxy/nome de projeto; por isso o cálculo do nome fica em uma função só, e o
|
||||
# resto a chama por nome em tempo de execução (o shell resolve a chamada
|
||||
# quando ela acontece, não quando o arquivo é lido) — o que deixa esta função
|
||||
# aqui em cima, onde a guarda precisa dela, sem depender da ordem do arquivo.
|
||||
#
|
||||
# O volume do Postgres NÃO entra: ele só existe no modo single-server e some
|
||||
# junto com o `down -v` que o próprio kit ensina como receita de "recomeçar" —
|
||||
# quem o encontrasse seria uma instalação derrubada, não uma instalação real.
|
||||
MARCA_INSTALACAO_NOME=".deskcomm-instalado"
|
||||
|
||||
# O nome do projeto Docker DESTA instalação, na ordem que importa. O
|
||||
# COMPOSE_PROJECT_NAME do `.env` manda quando existe (é o nome que os
|
||||
# contêineres carregam no label); o derivado do diretório é o que o Compose
|
||||
# usaria sem ele, e as duas entradas são testadas. Errar o nome faria a guarda
|
||||
# não achar o contêiner de quem JÁ TEM instalação — e a recusa voltaria a matar
|
||||
# a recuperação do #1775, que é exatamente o que o sinal de contêiner
|
||||
# existe para não fazer.
|
||||
#
|
||||
# O derivado do diretório é REPETIDO aqui, e não chamado de
|
||||
# `nome_do_projeto_compose`: essa função mora ~500 linhas abaixo deste ponto, e
|
||||
# a guarda roda no TOPO do arquivo, quando ela ainda não existe (chamar por nome
|
||||
# aqui daria "command not found" e a recusa do #1042 viraria um erro de
|
||||
# sintaxe). A fórmula é a de lá — minúsculo, só [a-z0-9_-], com os `_`/`-` do
|
||||
# INÍCIO aparados — e `tests/shell/` mede as duas cópias iguais.
|
||||
nomes_do_projeto_da_instalacao() { # nomes_do_projeto_da_instalacao <diretório>
|
||||
local dir="$1" declarado derivado
|
||||
declarado="$(sed -n 's/^[[:space:]]*COMPOSE_PROJECT_NAME=//p' "$dir/.env" 2>/dev/null \
|
||||
| head -1 | tr -d '\r' | tr -d '"'"'" | tr -d '[:space:]')"
|
||||
derivado="$(basename "$dir" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')"
|
||||
derivado="${derivado#"${derivado%%[!_-]*}"}"
|
||||
# Um valor fora do que o Compose aceita como nome é melhor ignorado do que
|
||||
# procurado: o `--filter` não valida, e o nome errado devolve vazio — que é a
|
||||
# mesma resposta de "não achei", e é a que manda recusar.
|
||||
case "$declarado" in
|
||||
''|*[!a-z0-9_-]*) ;;
|
||||
*) printf '%s\n%s\n' "$declarado" "$derivado" ; return 0 ;;
|
||||
esac
|
||||
printf '%s\n' "$derivado"
|
||||
}
|
||||
|
||||
# Há contêiner (rodando OU parado) do projeto compose informado? O `-a` conta o
|
||||
# que está parado: quem instalou e parou o CRM tem instalação do mesmo jeito, e
|
||||
# parar o stack é uma pausa, não um desinstalar. `docker` fora do PATH (ou sem
|
||||
# permissão no socket) devolve 1, que é a resposta que manda RECUSAR — nunca
|
||||
# adivinhar instalação a partir de um `docker` que não respondeu.
|
||||
conteiner_do_projeto_existe() { # conteiner_do_projeto_existe <projeto compose>
|
||||
[ -n "${1:-}" ] || return 1
|
||||
command -v docker >/dev/null 2>&1 || return 1
|
||||
[ -n "$(docker ps -a -q --filter "label=com.docker.compose.project=$1" 2>/dev/null)" ]
|
||||
}
|
||||
|
||||
instalacao_real_do_kit_aqui() {
|
||||
local d nome
|
||||
for d in "$PWD" "$PWD/deskcommcrm"; do
|
||||
[ -f "$d/$COMPOSE" ] && [ -f "$d/.env" ] && return 0
|
||||
[ -f "$d/$COMPOSE" ] && [ -f "$d/.env" ] || continue
|
||||
[ -f "$d/$MARCA_INSTALACAO_NOME" ] && return 0
|
||||
while IFS= read -r nome; do
|
||||
[ -n "$nome" ] || continue
|
||||
conteiner_do_projeto_existe "$nome" && return 0
|
||||
conteiner_do_projeto_existe "$nome-supabase" && return 0
|
||||
done <<EOF
|
||||
$(nomes_do_projeto_da_instalacao "$d")
|
||||
EOF
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# O install.sh grava este marcador com a stack no ar, para que a guarda de
|
||||
# arquitetura reconheça a instalação pelo QUE ELA DEIXOU, e não pelo que veio
|
||||
# pronto no diretório. `chmod 600` pelo mesmo rigor do `.env`: o arquivo não é
|
||||
# segredo, mas também não é para vazar.
|
||||
marcar_instalacao_feita() { # marcar_instalacao_feita [versão]
|
||||
# `local` um por linha, e o segundo já com o valor montado: no mesmo `local`,
|
||||
# o nome da esquerda ainda não existe quando a direita é avaliada, e com
|
||||
# `set -u` o `local dir=… marca="$dir/…"` morre em "unbound variable" — o
|
||||
# arquivo nunca era gravado e a instalação que deu certo mesmo assim é que
|
||||
# escondia o defeito.
|
||||
local dir="${PROJECT_DIR:-$PWD}"
|
||||
local marca="$dir/$MARCA_INSTALACAO_NOME"
|
||||
{ printf 'instalado_em=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo desconhecido)"
|
||||
printf 'versao=%s\n' "${1:-}"; } > "$marca" 2>/dev/null || return 1
|
||||
chmod 600 "$marca" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Ecoa: amd64 | recuperar | nova
|
||||
#
|
||||
# A decisão é PURA no que recebe: `uname` e a leitura do disco ficam fora, para
|
||||
@@ -75,7 +156,15 @@ veredito_da_arquitetura() { # veredito_da_arquitetura <arquitetura> [0=nova | 1
|
||||
verificar_arquitetura_do_kit() {
|
||||
local arch existe=0
|
||||
arch="$(uname -m 2>/dev/null || t "desconhecida")"
|
||||
instalacao_do_kit_ja_existe && existe=1
|
||||
# O sinal de "instalação real" SÓ é perguntado quando a arquitetura não é
|
||||
# suportada. Em amd64 o veredito já é `amd64` e a guarda atravessa, então
|
||||
# perguntar seria trabalho inútil — e, com o critério do #1778, trabalho que
|
||||
# chama o `docker` no TOPO do install.sh, antes de qualquer passo do
|
||||
# instalador. A seção 4 do teste de #1778 mede isso: em x86_64 a guarda não
|
||||
# fala com o Docker.
|
||||
if ! arquitetura_suportada_pelo_kit "$arch"; then
|
||||
instalacao_real_do_kit_aqui && existe=1
|
||||
fi
|
||||
|
||||
case "$(veredito_da_arquitetura "$arch" "$existe")" in
|
||||
amd64) return 0 ;;
|
||||
|
||||
@@ -119,6 +119,8 @@ sin eso un contenedor de compose común no puede entrar en ella."
|
||||
["apaga a configuração digitada"]="borra la configuración ingresada"
|
||||
["derruba o que subiu"]="derriba lo que se levantó"
|
||||
["começa de novo"]="empieza de nuevo"
|
||||
["apaga o marcador desta instalação"]="borra el marcador de esta instalación"
|
||||
["⚠ Não consegui gravar o marcador desta instalação (arquivo .deskcomm-instalado). O CRM está no ar; numa VPS ARM a atualização pode pedir a VPS x86_64 até o marcador existir."]="⚠ No pude escribir el marcador de esta instalación (archivo .deskcomm-instalado). El CRM está en línea; en una VPS ARM la actualización puede pedir la VPS x86_64 hasta que el marcador exista."
|
||||
["Se o schema chegou a ser aplicado e você quer o banco limpo de novo,"]="Si el esquema llegó a aplicarse y quieres la base de datos limpia de nuevo,"
|
||||
["abra o Supabase > SQL Editor e rode (ATENÇÃO: apaga todos os dados):"]="abre Supabase > SQL Editor y ejecuta (ATENCIÓN: borra todos los datos):"
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ show_recovery() {
|
||||
printf '\n%s\n\n' "$(t "Como voltar atrás e recomeçar do zero:")"
|
||||
printf ' %s\n' "cd ${dir}"
|
||||
printf ' %s\n' "rm -f .env # $(t "apaga a configuração digitada")"
|
||||
printf ' %s\n' "rm -f ${MARCA_INSTALACAO_NOME:-.deskcomm-instalado} # $(t "apaga o marcador desta instalação")"
|
||||
printf ' %s\n' "docker compose $(dc_files) down -v # $(t "derruba o que subiu")"
|
||||
printf ' %s\n' "bash ${KIT_DIR:-hostgator-setup-kit}/install.sh # $(t "começa de novo")"
|
||||
printf '\n%s\n' "$(t "Se o schema chegou a ser aplicado e você quer o banco limpo de novo,")"
|
||||
@@ -2272,6 +2273,26 @@ marcar_segredo_do_cron_como_novo
|
||||
setup_event_log_drain_cron
|
||||
setup_update_agent_cron
|
||||
|
||||
# ── O marcador que diz que esta instalação EXISTE (#1778) ───────────────────
|
||||
# A guarda de arquitetura (#1042, contornada pelo #1266) precisa distinguir
|
||||
# "instalação nova" de "instalação que já está no ar", e ela não pode usar
|
||||
# "tem compose e tem `.env`" como prova: o `.env` chega pronto numa instalação
|
||||
# NOVA (copiado, gerado por automação, ou deixado por um `--yes` que parou no
|
||||
# meio), e com esse critério uma VPS ARM nova começava a instalação construindo
|
||||
# as imagens na própria VPS — o que a guarda existe para impedir.
|
||||
#
|
||||
# O marcador vai aqui, e não antes, porque só a partir daqui é verdade que a
|
||||
# instalação EXISTE: os contêineres subiram e o app respondeu. Gravar antes
|
||||
# deixaria o arquivo afirmando uma instalação que pode não ter acontecido — e
|
||||
# a próxima rodada da guarda confiaria numa instalação que não está no ar.
|
||||
# `|| true` porque a ausência do marcador não pode derrubar uma instalação
|
||||
# cujos contêineres já estão no ar: no pior caso a guarda cai no sinal do
|
||||
# contêiner, que é o mesmo que ela usava para quem instalou numa versão
|
||||
# anterior.
|
||||
if [ "${APP_SAUDAVEL:-0}" = 1 ]; then
|
||||
marcar_instalacao_feita "$VERSAO_ALVO" || c_ylw "$(t "⚠ Não consegui gravar o marcador desta instalação (arquivo .deskcomm-instalado). O CRM está no ar; numa VPS ARM a atualização pode pedir a VPS x86_64 até o marcador existir.")"
|
||||
fi
|
||||
|
||||
# ── Final ───────────────────────────────────────────────────────────────────
|
||||
# O app não confirmou que está de pé: dizer "Instalação concluída!" aqui seria
|
||||
# mentir na única tela que a pessoa vai ler inteira. Ela recebe o estado real e
|
||||
@@ -2367,7 +2388,7 @@ $(telemetria_no_banner)
|
||||
$(t "backup:") bash hostgator-setup-kit/backup.sh
|
||||
$(t "trocar config:") bash hostgator-setup-kit/install.sh
|
||||
$(t "(mostra tudo o que você respondeu e deixa corrigir por número)")
|
||||
$(t "recomeçar:") docker compose $(dc_files) down -v && rm -f .env
|
||||
$(t "recomeçar:") docker compose $(dc_files) down -v && rm -f .env ${MARCA_INSTALACAO_NOME:-.deskcomm-instalado}
|
||||
$(t "(derruba tudo; depois rode o install.sh de novo)")
|
||||
|
||||
DONE
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
"cercas": "vitest run --project cercas",
|
||||
"test:db": "bash scripts/test-db.sh",
|
||||
"test:db:update": "bash scripts/test-update-com-dados.sh",
|
||||
"test:shell": "bash tests/shell/update-guard.test.sh && bash hostgator-setup-kit/test-validators.sh && bash tests/shell/baseline-reaplica-apos-disputa.test.sh && bash tests/shell/dono-do-projeto.test.sh && bash tests/shell/scheduler-entrypoint.test.sh && bash tests/shell/cron-sem-crontab-previo.test.sh && bash tests/shell/senha-do-cron-vazada.test.sh && bash tests/shell/owner-id-por-email.test.sh && bash tests/shell/deskcomm-contribuir.test.sh && bash tests/shell/colisao-de-migration.test.sh && bash tests/shell/test-db-recusa-sem-vitest.test.sh && bash tests/shell/guard-hooks-atualizados.test.sh && bash tests/shell/hooks-nao-acusam-a-main.test.sh && bash tests/shell/env-e2e-porta-do-stack.test.sh && bash tests/shell/instalar-guias.test.sh && bash tests/shell/arquitetura-kit.test.sh && bash tests/shell/guarda-arm-nao-mata-a-recuperacao.test.sh && bash tests/shell/extensao-nao-instala.test.sh && bash tests/shell/atualizacao-para-quem-fala-com-o-banco.test.sh && bash tests/shell/desinstalar-docker.test.sh && bash tests/shell/stack-local.test.sh && bash tests/shell/e2e-build-recusa-sem-next.test.sh && bash tests/shell/smoke-llm-recusa-sem-tsx.test.sh && bash tests/shell/waha-backup-volume.test.sh && bash tests/shell/single-server-installer.test.sh && bash tests/shell/single-server-operacao.test.sh && bash tests/shell/ubuntu-production-installer.test.sh && bash tests/shell/atualizacao-de-fora-nao-pula-o-backup.test.sh && bash tests/shell/release-publicada-nao-maior-tag.test.sh",
|
||||
"test:shell": "bash tests/shell/update-guard.test.sh && bash hostgator-setup-kit/test-validators.sh && bash tests/shell/baseline-reaplica-apos-disputa.test.sh && bash tests/shell/dono-do-projeto.test.sh && bash tests/shell/scheduler-entrypoint.test.sh && bash tests/shell/cron-sem-crontab-previo.test.sh && bash tests/shell/senha-do-cron-vazada.test.sh && bash tests/shell/owner-id-por-email.test.sh && bash tests/shell/deskcomm-contribuir.test.sh && bash tests/shell/colisao-de-migration.test.sh && bash tests/shell/test-db-recusa-sem-vitest.test.sh && bash tests/shell/guard-hooks-atualizados.test.sh && bash tests/shell/hooks-nao-acusam-a-main.test.sh && bash tests/shell/env-e2e-porta-do-stack.test.sh && bash tests/shell/instalar-guias.test.sh && bash tests/shell/arquitetura-kit.test.sh && bash tests/shell/guarda-arm-nao-mata-a-recuperacao.test.sh && bash tests/shell/guarda-arm-so-considera-instalacao-real.test.sh && bash tests/shell/extensao-nao-instala.test.sh && bash tests/shell/atualizacao-para-quem-fala-com-o-banco.test.sh && bash tests/shell/desinstalar-docker.test.sh && bash tests/shell/stack-local.test.sh && bash tests/shell/e2e-build-recusa-sem-next.test.sh && bash tests/shell/smoke-llm-recusa-sem-tsx.test.sh && bash tests/shell/waha-backup-volume.test.sh && bash tests/shell/single-server-installer.test.sh && bash tests/shell/single-server-operacao.test.sh && bash tests/shell/ubuntu-production-installer.test.sh && bash tests/shell/atualizacao-de-fora-nao-pula-o-backup.test.sh && bash tests/shell/release-publicada-nao-maior-tag.test.sh",
|
||||
"test:invariants": "bash scripts/test-db.sh",
|
||||
"lint:channels": "tsx scripts/lint-channels.ts",
|
||||
"lint:role-rank": "tsx scripts/lint-role-rank.ts",
|
||||
|
||||
@@ -159,6 +159,14 @@ INTERNAL_SECRET=segredo
|
||||
NUVEMSHOP_OAUTH_ENCRYPTION_KEY=chave
|
||||
ENV
|
||||
chmod 600 "$proj/.env"
|
||||
# O marcador que o install.sh grava com a stack no ar (#1778). Esta fixture
|
||||
# representa uma instalação que JÁ PASSOU pelo instalador, então ela tem o
|
||||
# marcador — e, mesmo sem ele, teria o contêiner do projeto, que é o outro
|
||||
# sinal de instalação real. Sem esta linha o `docker ps -a -q` do dublê (que
|
||||
# devolve vazio) faria esta prova medir uma instalação NOVA, que não é o caso
|
||||
# que ela existe para provar.
|
||||
printf 'instalado_em=2026-09-27T00:00:00Z\nversao=0.9.0\n' > "$proj/.deskcomm-instalado"
|
||||
chmod 600 "$proj/.deskcomm-instalado"
|
||||
fi
|
||||
# O overlay do #1143 precisa EXISTIR no projeto: o `construir_aqui_e_subir`
|
||||
# passa `-f $COMPOSE_BUILD` para o compose, e um `-f` de arquivo inexistente
|
||||
@@ -312,7 +320,7 @@ R5="$WORK/caso5"; mkdir -p "$R5"; montar_instalacao "$R5" 0
|
||||
(
|
||||
cd "$R5/deskcommcrm" || exit 1
|
||||
git checkout --quiet v0.9.0
|
||||
sed -i.bak 's/instalacao_do_kit_ja_existe && existe=1/: guarda velha/' hostgator-setup-kit/_common.sh
|
||||
sed -i.bak 's/instalacao_real_do_kit_aqui && existe=1/: guarda velha/' hostgator-setup-kit/_common.sh
|
||||
rm -f hostgator-setup-kit/_common.sh.bak
|
||||
git commit --quiet -am "kit com a guarda velha"
|
||||
git tag v0.8.0
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
#!/usr/bin/env bash
|
||||
# ── #1778 — a guarda de ARM só considera instalação REAL ─────────────────────
|
||||
#
|
||||
# O DEFEITO, e por que o teste do #1775 não podia pegá-lo:
|
||||
#
|
||||
# O #1775 separou instalação NOVA (recusa em não-x86_64) de instalação
|
||||
# EXISTENTE (aviso, e o script segue até o build local). O critério de
|
||||
# "existente" lia o estado do DIRETÓRIO — compose E um `.env` — e um
|
||||
# `install.sh --yes` numa VPS ARM NOVA com o `.env` já preenchido (copiado de
|
||||
# outra máquina, gerado por automação, ou deixado por uma rodada anterior que
|
||||
# parou no meio) passava como existente e ia construir as imagens na própria
|
||||
# VPS. O caminho alcançado é o mesmo build local que o install.sh já tem
|
||||
# (por volta da linha 2209), então não é risco de segurança: é a instalação
|
||||
# NOVA em ARM deixar de ser recusada, que é o que a guarda do #1042 existe
|
||||
# para impedir.
|
||||
#
|
||||
# O teste do #1775 não podia ver isso porque a fixture dele (`montar_instalacao`)
|
||||
# representa uma instalação que JÁ PASSOU pelo install.sh: para aquela prova,
|
||||
# "tem compose e tem `.env`" e "é instalação real" são a MESMA coisa. Foi por
|
||||
# isso que este arquivo nasce: separar os dois, e dar ao par `.env`-sem-mais um
|
||||
# nome que a guarda trata como instalação NOVA.
|
||||
#
|
||||
# O QUE ESTE ARQUIVO PROVA, e o que NÃO prova:
|
||||
#
|
||||
# Prova que a guarda decide pelo que a instalação DEIXOU (marcador, contêiner
|
||||
# do projeto, contêiner do Supabase single-server) e não pelo que chegou
|
||||
# pronto na pasta: com `.env` e nada instalado, aarch64 é recusada com a
|
||||
# recusa do #1042. Prova que os três sinais de instalação real continuam
|
||||
# passando, que o filtro de contêiner é por PROJETO (o de outra instalação na
|
||||
# mesma VPS não vale), que `docker` indisponível não vira instalação inventada,
|
||||
# e que em x86_64 o `docker` nem é chamado — a guarda não perguntou nada.
|
||||
#
|
||||
# NÃO prova nada numa VPS ARM de verdade: `uname` e `docker` são dublês, o
|
||||
# diretório é descartável (mktemp) e nenhum contêiner sobe. O que se prova é
|
||||
# a DECISÃO da guarda, que é onde o critério mora.
|
||||
#
|
||||
# bash tests/shell/guarda-arm-so-considera-instalacao-real.test.sh
|
||||
set -uo pipefail
|
||||
# Isolamento do git: um GIT_DIR herdado (suíte rodada de dentro de um hook ou
|
||||
# de um `rebase --exec`) manda por cima de todo `cd`/`git init` dos diretórios
|
||||
# descartáveis abaixo. Nenhum teste aqui mede o autor do git.
|
||||
unset $(git rev-parse --local-env-vars 2>/dev/null) 2>/dev/null
|
||||
export GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t.t GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t.t
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd -P)"
|
||||
COMMON="$REPO_ROOT/hostgator-setup-kit/_common.sh"
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
# Guarda de raio de ação: com TMPDIR apontando para diretório inexistente o
|
||||
# `mktemp` acima falha e WORK fica VAZIA — aí "$WORK/bin/docker" vira /bin/docker
|
||||
# e o dublê abaixo sobrescreve o binário da máquina de quem roda a suíte.
|
||||
if [ -z "$WORK" ] || [ ! -d "$WORK" ] || [ "$WORK" = / ]; then
|
||||
echo "abortado: mktemp -d não devolveu um sandbox (WORK='$WORK') — TMPDIR inválido?" >&2
|
||||
exit 1
|
||||
fi
|
||||
trap '[ "${DK_KEEP:-0}" = 1 ] || rm -rf "$WORK"' EXIT
|
||||
|
||||
REAL_UNAME="$(command -v uname)"
|
||||
FAILS=0
|
||||
TOTAL=0
|
||||
check() { # check <descrição> <comando de verificação...>
|
||||
TOTAL=$((TOTAL + 1))
|
||||
if "${@:2}"; then printf ' ✓ %s\n' "$1"; else printf ' ✗ %s\n' "$1"; FAILS=$((FAILS + 1)); fi
|
||||
}
|
||||
nao_contem() { ! grep -q -- "$1" "$2"; } # nao_contem <texto> <arquivo>
|
||||
|
||||
# ── Dublês ───────────────────────────────────────────────────────────────────
|
||||
mkdir -p "$WORK/bin"
|
||||
# `uname -m` é a arquitetura que o caso escolhe; o resto de `uname` vai para o
|
||||
# binário de verdade.
|
||||
cat > "$WORK/bin/uname" <<STUB
|
||||
#!/usr/bin/env bash
|
||||
[ "\$*" = "-m" ] && { printf '%s\n' "\${FAKE_ARCH:-aarch64}"; exit 0; }
|
||||
exec "$REAL_UNAME" "\$@"
|
||||
STUB
|
||||
# `docker` responde ao ÚNICO comando que a guarda faz: `ps -a -q --filter
|
||||
# label=com.docker.compose.project=<nome>`. O dublê devolve um id quando o nome
|
||||
# pedido estiver na lista de PROJETOS COM CONTÊINER, e vazio quando não estiver
|
||||
# — inclusive quando o nome pedido for o do projeto de outra instalação, que é
|
||||
# o caso 7. Toda chamada vai para o log, para o teste provar que em x86_64 a
|
||||
# guarda NÃO PERGUNTOU nada (caso 8).
|
||||
cat > "$WORK/bin/docker" <<'STUB'
|
||||
#!/usr/bin/env bash
|
||||
printf '%s\n' "$*" >> "$DOCKER_LOG"
|
||||
n="$*"
|
||||
projeto="${n##*com.docker.compose.project=}"
|
||||
projeto="${projeto%% *}"
|
||||
for p in ${PROJETOS_COM_CONTAINER:-}; do
|
||||
[ "$p" = "$projeto" ] && { printf 'c0ffee1234\n'; exit 0; }
|
||||
done
|
||||
exit 0
|
||||
STUB
|
||||
# A asserção do caso 8 precisa provar que a guarda NÃO falou com o Docker, e
|
||||
# não apenas que o log ficou vazio: o stub registra uma linha por chamada, então
|
||||
# "nenhuma linha" e "nenhuma consulta ao projeto" são a mesma coisa aqui. O
|
||||
# `label=com.docker.compose.project` é o que distingue a consulta da guarda de
|
||||
# qualquer outra linha que um stub pudesse escrever.
|
||||
docker_falou_com_o_docker() { grep -q 'com.docker.compose.project' "$DOCKER_LOG" 2>/dev/null; }
|
||||
# `check` roda o comando com "${@:2}", e um `!` solto ali vira nome de comando
|
||||
# em vez de negação — daí a inversão morar numa função própria.
|
||||
docker_nao_falou() { ! docker_falou_com_o_docker; }
|
||||
chmod +x "$WORK/bin/uname" "$WORK/bin/docker"
|
||||
export DOCKER_LOG="$WORK/docker.log"
|
||||
export PATH="$WORK/bin:$PATH"
|
||||
|
||||
# ── Fixture ──────────────────────────────────────────────────────────────────
|
||||
# Uma pasta que parece uma instalação: compose + `.env`. O que muda entre os
|
||||
# casos é o resto — o marcador, os contêineres, e se o `.env` existe. O nome do
|
||||
# projeto que o Compose derivaria da pasta é `deskcommcrm` (basename), e é por
|
||||
# ele que o dublê do `docker` responde.
|
||||
montar_pasta() { # montar_pasta <diretório> [1=com .env]
|
||||
local d="$1" sem_env="${2:-0}"
|
||||
mkdir -p "$d"
|
||||
printf 'services:\n app:\n image: x\n' > "$d/docker-compose.prod.yml"
|
||||
[ "$sem_env" = 1 ] && return 0
|
||||
cat > "$d/.env" <<ENV
|
||||
APP_IMAGE=ghcr.io/melgarafael/deskcommcrm:0.9.0
|
||||
SUPABASE_DB_URL=postgresql://x/y
|
||||
NEXT_PUBLIC_APP_URL=https://crm.exemplo.com.br
|
||||
INTERNAL_SECRET=segredo
|
||||
ENV
|
||||
chmod 600 "$d/.env"
|
||||
}
|
||||
|
||||
# roda_guarda <diretório de trabalho> <arch> <projetos com contêiner...> → rc
|
||||
# Carrega o `_common.sh` com o NOME de quem sourceou, porque é o nome que a
|
||||
# guarda confere (`BASH_SOURCE[1]`): sem ele a guarda nem roda. A decisão é lida
|
||||
# de `instalacao_real_do_kit_aqui`, que é onde o critério mora, e a RECUSA é
|
||||
# provada pelo rc e pelo texto do #1042 — a mesma prova do
|
||||
# `tests/shell/arquitetura-kit.test.sh`, com a instalação NOVA carregada de `.env`.
|
||||
guarda() { # guarda <diretório> <arch> [projetos com contêiner...]
|
||||
local d="$1" arch="$2"; shift 2
|
||||
# O log é ZERADO entre as duas passadas do helper: a primeira mede o
|
||||
# `instalacao_real_do_kit_aqui` (que chama o docker) e a segunda mede a
|
||||
# `verificar_arquitetura_do_kit` (que, em amd64, não pode chamar). Sem o
|
||||
# `: >` no meio, a consulta da primeira passada ainda estaria no log quando a
|
||||
# asserção do caso 8 lesse, e o caso diria que a guarda falou com o Docker em
|
||||
# x86_64 — o que é o defeito, e não o que acontece.
|
||||
: > "$DOCKER_LOG"
|
||||
( cd "$d" && \
|
||||
env FAKE_ARCH="$arch" PROJETOS_COM_CONTAINER="$*" \
|
||||
bash -c '. "$0"
|
||||
if instalacao_real_do_kit_aqui; then echo REAL; else echo NOVA; fi' "$COMMON" \
|
||||
) > "$WORK/veredito.txt" 2>"$WORK/guarda.err"
|
||||
# O rc é o da VERIFICAÇÃO DA GUARDA completa (que sai 1 na recusa), e não o do
|
||||
# `bash -c` acima: a guarda é quem responde se a instalação existe.
|
||||
: > "$DOCKER_LOG"
|
||||
( cd "$d" && env FAKE_ARCH="$arch" PROJETOS_COM_CONTAINER="$*" \
|
||||
bash -c 'set -- "$0"; . "$1"
|
||||
verificar_arquitetura_do_kit' "$COMMON" install.sh \
|
||||
) > "$WORK/guarda.out" 2>&1
|
||||
RC=$?
|
||||
VEREDITO="$(cat "$WORK/veredito.txt")"
|
||||
SAIDA="$(cat "$WORK/guarda.out")"
|
||||
}
|
||||
# O nome que o Compose derivaria da pasta. Lido do próprio `docker` dublê em vez
|
||||
# de repetido aqui: se um dia a fórmula mudar, o teste continua medindo a
|
||||
#_installação_ e não uma constante desatualizada.
|
||||
nome_derivado() { basename "$1" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-'; }
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
echo '── 1. A DEFÉITO DA #1778: .env preenchido + NADA instalado é instalação'
|
||||
echo ' NOVA, e aarch64 é recusada com a recusa do #1042'
|
||||
# A receita do relato: `install.sh --yes` numa VPS ARM NOVA cujo `.env` veio
|
||||
# pronto (copiado de outra máquina, gerado por automação, ou deixado por uma
|
||||
# rodada que parou no meio). Compose e `.env` estão lá — que era o que bastava.
|
||||
# O resultado tem de ser a RECUSA, com o texto do #1042, e sem a palavra do
|
||||
# aviso de instalação existente.
|
||||
R1="$WORK/caso1"; mkdir -p "$R1"; montar_pasta "$R1/deskcommcrm" 0
|
||||
guarda "$R1" aarch64
|
||||
check ".env + compose e NADA instalado → a instalação NÃO é real" \
|
||||
test "$VEREDITO" = NOVA
|
||||
check "e aarch64 é recusada (rc=$RC, e != 0)" test "$RC" -ne 0
|
||||
check "a recusa é a do #1042 (orienta a VPS suportada)" \
|
||||
grep -q 'Use uma VPS x86_64/amd64' "$WORK/guarda.out"
|
||||
check "a recusa diz qual arquitetura foi encontrada" \
|
||||
grep -q 'aarch64' "$WORK/guarda.out"
|
||||
check "e NÃO diz que a instalação já existe (o aviso do #1775)" \
|
||||
nao_contem 'JÁ EXISTE' "$WORK/guarda.out"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo '── 2. OS TRÊS SINAIS DE INSTALAÇÃO REAL CONTINUAM PASSANDO (#1775 intacto)'
|
||||
# O contrapeso obrigatório: o que o #1775 consertou não pode ser desfeito. Sem
|
||||
# esta seção, um conserto que recusasse TUDO em ARM também ficaria verde.
|
||||
R2="$WORK/caso2"; mkdir -p "$R2"; montar_pasta "$R2/deskcommcrm" 0
|
||||
marcar_instalacao() { # marcar_instalacao <diretório> [versão]
|
||||
printf 'instalado_em=2026-09-27T00:00:00Z\nversao=%s\n' "${2:-0.9.0}" \
|
||||
> "$1/.deskcomm-instalado"
|
||||
chmod 600 "$1/.deskcomm-instalado"
|
||||
}
|
||||
# 2a. O marcador, que o install.sh grava com a stack no ar. É o sinal mais
|
||||
# forte: a instalação em si escreveu que terminou.
|
||||
marcar_instalacao "$R2/deskcommcrm"
|
||||
guarda "$R2" aarch64
|
||||
check "o marcador .deskcomm-instalado → a instalação é real" test "$VEREDITO" = REAL
|
||||
check "e aarch64 passa pela guarda (rc=$RC, e == 0)" test "$RC" -eq 0
|
||||
check "com o aviso de que a instalação já existe, e não com a recusa" \
|
||||
grep -q 'JÁ EXISTE' "$WORK/guarda.out"
|
||||
check "e a recusa do #1042 NÃO aparece" \
|
||||
nao_contem 'Use uma VPS x86_64/amd64' "$WORK/guarda.out"
|
||||
|
||||
# 2b. O contêiner do projeto, que é o caso de quem instalou numa versão
|
||||
# anterior e por isso não tem marcador. Precisa ser o contêiner do projeto
|
||||
# DESTA instalação — daí o nome derivado da pasta, e não um nome qualquer.
|
||||
R2B="$WORK/caso2b"; mkdir -p "$R2B"; montar_pasta "$R2B/deskcommcrm" 0
|
||||
guarda "$R2B" aarch64 "$(nome_derivado "$R2B/deskcommcrm")"
|
||||
check "contêiner do projeto DESTA instalação → é real" test "$VEREDITO" = REAL
|
||||
check "e aarch64 passa pela guarda (rc=$RC, e == 0)" test "$RC" -eq 0
|
||||
check "com o aviso de instalação existente" grep -q 'JÁ EXISTE' "$WORK/guarda.out"
|
||||
|
||||
# 2c. O contêiner do Supabase single-server, que o modo single-server cria com
|
||||
# o sufixo `-supabase` no nome do projeto. Sem este sinal, quem instalou em
|
||||
# single-server passaria a ser recusado numa VPS ARM — uma regressão nova.
|
||||
R2C="$WORK/caso2c"; mkdir -p "$R2C"; montar_pasta "$R2C/deskcommcrm" 0
|
||||
guarda "$R2C" aarch64 "$(nome_derivado "$R2C/deskcommcrm")-supabase"
|
||||
check "contêiner do Supabase single-server → é real" test "$VEREDITO" = REAL
|
||||
check "e aarch64 passa pela guarda (rc=$RC, e == 0)" test "$RC" -eq 0
|
||||
|
||||
# 2d. O COMPOSE_PROJECT_NAME do `.env` manda sobre o nome derivado da pasta, e
|
||||
# o guard tem de procurar pelo que os contêineres carregam de verdade. Uma
|
||||
# segunda instalação na mesma VPS (a receita do próprio kit para quem quer duas)
|
||||
# nomeia o projeto no `.env` justamente para não disputar o parque com a outra.
|
||||
R2D="$WORK/caso2d"; mkdir -p "$R2D"; montar_pasta "$R2D/deskcommcrm" 0
|
||||
printf 'COMPOSE_PROJECT_NAME=deskcommcrm-2\n' >> "$R2D/deskcommcrm/.env"
|
||||
guarda "$R2D" aarch64 "deskcommcrm-2"
|
||||
check "COMPOSE_PROJECT_NAME do .env manda sobre o nome da pasta → é real" \
|
||||
test "$VEREDITO" = REAL
|
||||
check "e aarch64 passa pela guarda (rc=$RC, e == 0)" test "$RC" -eq 0
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo '── 3. O QUE NÃO É PROVA DE INSTALAÇÃO: os contêineres errados e o Docker'
|
||||
echo ' que não respondeu'
|
||||
# Aqui está a outra metade do defeito. Um `docker ps` que responde com o
|
||||
# contêiner de OUTRO programa não prova que ESTE projeto foi instalado — e a
|
||||
# VPS de quem já tem um WordPress é a regra, não a exceção. Sem o filtro por
|
||||
# projeto, qualquer VPS com Docker vira "instalação existente" e a recusa do
|
||||
# #1042 deixa de existir em cima de um `docker ps` qualquer.
|
||||
R3="$WORK/caso3"; mkdir -p "$R3"; montar_pasta "$R3/deskcommcrm" 0
|
||||
guarda "$R3" aarch64 "wordpress_app_pljr imobplus-server-app-1 traefik"
|
||||
check "contêiner de OUTRO programa na mesma VPS → a instalação NÃO é real" \
|
||||
test "$VEREDITO" = NOVA
|
||||
check "e aarch64 é recusada (rc=$RC, e != 0)" test "$RC" -ne 0
|
||||
check "a recusa é a do #1042" grep -q 'Use uma VPS x86_64/amd64' "$WORK/guarda.out"
|
||||
|
||||
# Um `docker` que não responde (fora do PATH, daemon parado, sem permissão no
|
||||
# socket) devolve vazio, e vazio é "não achei" — a resposta que manda RECUSAR.
|
||||
# O contrário seria adivinhar instalação a partir de um Docker que não falou.
|
||||
R3B="$WORK/caso3b"; mkdir -p "$R3B"; montar_pasta "$R3B/deskcommcrm" 0
|
||||
guarda "$R3B" aarch64
|
||||
: > "$DOCKER_LOG"
|
||||
( cd "$R3B" && env -i PATH="/usr/bin:/bin" HOME="${HOME:-/root}" FAKE_ARCH=aarch64 \
|
||||
bash -c '. "$0"
|
||||
if instalacao_real_do_kit_aqui; then echo REAL; else echo NOVA; fi' "$COMMON" \
|
||||
) > "$WORK/sem-docker.txt" 2>&1
|
||||
check "sem docker no PATH, a instalação NÃO é inventada" \
|
||||
grep -q '^NOVA$' "$WORK/sem-docker.txt"
|
||||
|
||||
# Sem `.env` não há nem nome de projeto para procurar — e a pasta nem é uma
|
||||
# instalação. O guard nem deve chamar o docker aqui.
|
||||
R3C="$WORK/caso3c"; mkdir -p "$R3C"; montar_pasta "$R3C/deskcommcrm" 1
|
||||
guarda "$R3C" aarch64 "$(nome_derivado "$R3C/deskcommcrm")"
|
||||
check "sem .env (e com contêiner do projeto lá) → a instalação NÃO é real" \
|
||||
test "$VEREDITO" = NOVA
|
||||
check "e aarch64 é recusada (rc=$RC, e != 0)" test "$RC" -ne 0
|
||||
check "e o docker nem é chamado sem .env" docker_nao_falou
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo '── 4. x86_64: A GUARDA CONTINUA NÃO PERGUNTANDO NADA'
|
||||
# Em amd64 o veredito é `amd64` antes de olhar o disco, e a guarda não deve
|
||||
# tocar no Docker para descobrir isso. O `test:shell` roda num Mac Apple
|
||||
# Silicon, então este caso é o que impede a suíte de depender do processador de
|
||||
# quem a roda.
|
||||
R4="$WORK/caso4"; mkdir -p "$R4"; montar_pasta "$R4/deskcommcrm" 0
|
||||
guarda "$R4" x86_64
|
||||
check "em x86_64 a guarda atravessa (rc=$RC, e == 0)" test "$RC" -eq 0
|
||||
check "em x86_64 a guarda NÃO chama o docker (nem disco, nem contêiner)" \
|
||||
docker_nao_falou
|
||||
check "em x86_64 não sai nem recusa nem aviso sobre arquitetura" \
|
||||
nao_contem 'arquitetura' "$WORK/guarda.out"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo '── 5. A FÓRMULA DO NOME: a cópia do guard bate com nome_do_projeto_compose'
|
||||
# O guard repete a fórmula do nome do projeto em vez de chamar a função, porque
|
||||
# roda no TOPO do `_common.sh`, antes dela existir. Essa repetição é uma dívida:
|
||||
# se as duas divergirem, a guarda para de achar o contêiner de quem JÁ TEM
|
||||
# instalação e volta a recusar a recuperação do #1775. Este caso mede as duas
|
||||
# lado a lado, com as pastas que o próprio kit já usa de exemplo.
|
||||
(
|
||||
. "$COMMON" 2>/dev/null
|
||||
for pasta in deskcommcrm _deskcomm -deskcomm _-_crm _123 CRM-production meu_crm-2; do
|
||||
dir="$WORK/nome/$pasta"; mkdir -p "$dir"
|
||||
printf 'x\n' > "$dir/docker-compose.prod.yml"; : > "$dir/.env"
|
||||
printf '%s %s %s\n' "$pasta" "$(nome_do_projeto_compose "$dir")" \
|
||||
"$(nomes_do_projeto_da_instalacao "$dir" | tr '\n' ',')"
|
||||
done
|
||||
) > "$WORK/nomes.txt" 2>&1
|
||||
while read -r pasta esperado derivados; do
|
||||
check "«$pasta»: o guard deriva «$esperado» como nome_do_projeto_compose" \
|
||||
test "$derivados" = "$esperado,"
|
||||
done < "$WORK/nomes.txt"
|
||||
|
||||
# Um COMPOSE_PROJECT_NAME fora do que o Compose aceita é ignorado, e o derivado
|
||||
# da pasta segue na lista: um nome inválido não pode fazer a guarda procurar
|
||||
# por algo que o Docker nunca chamará.
|
||||
R5="$WORK/caso5"; mkdir -p "$R5"; montar_pasta "$R5/deskcommcrm" 0
|
||||
printf 'COMPOSE_PROJECT_NAME=CRM Inválido/Não\n' >> "$R5/deskcommcrm/.env"
|
||||
N5="$(
|
||||
. "$COMMON" 2>/dev/null
|
||||
nomes_do_projeto_da_instalacao "$R5/deskcommcrm" | tr '\n' ','
|
||||
)"
|
||||
check "um COMPOSE_PROJECT_NAME inválido é ignorado (resta o nome derivado: $N5)" \
|
||||
test "$N5" = "$(nome_derivado "$R5/deskcommcrm"),"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo '── 6. O MARCADOR: o install.sh grava, e a guarda lê o que ele diz'
|
||||
# O marcador é o sinal que o install.sh passa a escrever. As duas metades
|
||||
# importam: que ele SAI com a stack no ar (e não antes, nem quando o app não
|
||||
# respondeu), e que a guarda reconhece o arquivo.
|
||||
# A escrita é medida pela FUNÇÃO, isolada do resto do instalador (que exige
|
||||
# root, Docker e um banco): o que muda de um lado para o outro é o diretório.
|
||||
R6="$WORK/caso6"; mkdir -p "$R6"; montar_pasta "$R6/deskcommcrm" 0
|
||||
(
|
||||
PROJECT_DIR="$R6/deskcommcrm" bash -c '. "$0"; marcar_instalacao_feita 0.9.0' "$COMMON"
|
||||
) >/dev/null 2>&1
|
||||
check "marcar_instalacao_feita grava o arquivo na raiz da instalação" \
|
||||
test -f "$R6/deskcommcrm/.deskcomm-instalado"
|
||||
check "e o arquivo registra a versão que subiu" \
|
||||
grep -q '^versao=0.9.0$' "$R6/deskcommcrm/.deskcomm-instalado"
|
||||
check "e registra quando (ISO-8601 em UTC, para o log do dono)" \
|
||||
grep -qE '^instalado_em=[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$' \
|
||||
"$R6/deskcommcrm/.deskcomm-instalado"
|
||||
check "e nasce com o mesmo rigor do .env (600), que é onde ele mora" \
|
||||
test "$(stat -c '%a' "$R6/deskcommcrm/.deskcomm-instalado" 2>/dev/null)" = 600
|
||||
# E a guarda o reconhece pelo arquivo, sem perguntar nada ao Docker.
|
||||
: > "$DOCKER_LOG"
|
||||
(
|
||||
cd "$R6" && bash -c '. "$0"
|
||||
if instalacao_real_do_kit_aqui; then echo REAL; else echo NOVA; fi' "$COMMON"
|
||||
) > "$WORK/caso6.txt" 2>&1
|
||||
check "a guarda reconhece o marcador sem chamar o docker" \
|
||||
grep -q '^REAL$' "$WORK/caso6.txt"
|
||||
check "e de fato não chamou o docker" docker_nao_falou
|
||||
|
||||
# O install.sh grava o marcador SÓ com o app saudável, e as duas receitas de
|
||||
# "recomeçar" o apagam junto com o `.env`. Um marcador que sobrasse depois de
|
||||
# derrubar tudo faria a guarda mentir sobre uma instalação que não existe mais
|
||||
# — a mesma classe de defeito que este conserto veio tirar.
|
||||
check "o install.sh só grava o marcador quando o app está saudável" \
|
||||
grep -qE 'if \[ "\$\{APP_SAUDAVEL:-0\}" = 1 \]; then' "$REPO_ROOT/hostgator-setup-kit/install.sh"
|
||||
check "e a receita de 'recomeçar' apaga o marcador junto com o .env" \
|
||||
grep -q 'rm -f .env ${MARCA_INSTALACAO_NOME' "$REPO_ROOT/hostgator-setup-kit/install.sh"
|
||||
check "e o painel de recuperação do install.sh também o apaga" \
|
||||
grep -q 'rm -f \${MARCA_INSTALACAO_NOME' "$REPO_ROOT/hostgator-setup-kit/install.sh"
|
||||
check "e o marcador está no .gitignore (estado da VPS, não do repositório)" \
|
||||
grep -qx '.deskcomm-instalado' "$REPO_ROOT/.gitignore"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo '── 7. O NOME ANTIGO FOI REMOVIDO: nada chama mais o critério do .env'
|
||||
# `instalacao_do_kit_ja_existe` era a função do critério de `main` (compose +
|
||||
# `.env`). Se ela tivesse sobrado no arquivo, o próximo conserto da guarda
|
||||
# voltaria a usá-la por engano — e o defeito voltaria sem nenhuma mudança
|
||||
# visível no diff.
|
||||
check "a função do critério antigo (compose + .env) não existe mais" \
|
||||
bash -c '! grep -q "^instalacao_do_kit_ja_existe()" "$0"' "$COMMON"
|
||||
check "e ninguém no kit a chama" \
|
||||
bash -c '! grep -rq "instalacao_do_kit_ja_existe" hostgator-setup-kit/' "$REPO_ROOT"
|
||||
|
||||
printf '\nprovas: %d vermelho(s) de %d\n' "$FAILS" "$TOTAL"
|
||||
if [ "$FAILS" -eq 0 ]; then
|
||||
echo "OK — a guarda só considera instalação real (#1778) e o caminho de recuperação do #1775 continua aberto."
|
||||
else
|
||||
echo "FALHOU — $FAILS prova(s)."
|
||||
fi
|
||||
exit $((FAILS > 0))
|
||||
Reference in New Issue
Block a user