#!/bin/sh
#
# NENHUM SEGREDO VERSIONADO -- o portao do CI e do `pre-push`, num lugar so.
#
#     sh scripts/conferir-segredos.sh          # a arvore de trabalho (o CI)
#     sh scripts/conferir-segredos.sh <commit> # um commit (o pre-push chama
#                                              # para cada um que o push leva)
#
# Sai com 1 se achar credencial literal fora das excecoes declaradas, e com 2
# se o `git grep` nao conseguir ler.
#
# ---------------------------------------------------------------------------
# POR QUE UM ARQUIVO SO (03/10/2026, SEGREDOS)
#
# O padrao morava em duas copias -- o passo "Nenhum segredo versionado" do CI
# e o `.githooks/pre-push` -- e elas ja tinham divergido: o conserto do D89 (o
# colchete da atribuicao a indice) entrou no CI e nunca chegou ao pre-push.
# Com o CI parado por cobranca desde 13/09/2026, o pre-push era o unico dos
# dois rodando, e era o mais cego.
#
# O QUE OS DOIS NAO VIAM, medido em 03/10/2026 com os dois literais no HEAD
# (os dois sairam com 0, e este sai com 1 sobre o mesmo HEAD):
#
#   - a chave de PRODUCAO do Asaas, atribuida a `$this->apiKey`: `api_?key`
#     nao casa `apiKey` sem ignorar maiusculas, e o valor COMECA COM `$`, que
#     o padrao excluia de qualquer aspa;
#   - o token das rotinas, atribuido a `$this->tokenPadrao`: o nome nao estava
#     na lista.
#
# ---------------------------------------------------------------------------
# O PADRAO
#
# - IGNORA MAIUSCULAS (`-i`): `apiKey`, `SECRET`, `clientSecret`.
# - `token_?padrao`, e a chave `token` ENTRE ASPAS -- a do `cron.token` nos
#   modelos do `local.php`. O `token` solto NAO entra: casava duas constantes
#   de teste (`SEGREDO_DO_TOKEN`, `ID_ESCOLHIDO_COM_TOKEN`), e portao que grita
#   com fixture ensina a ignora-lo.
# - O colchete opcional depois da aspa: a atribuicao a indice (D89).
# - ASPA SIMPLES ACEITA `$`; aspa dupla, nao. Em PHP e em shell a aspa simples
#   nao interpola -- la dentro, `$` e parte do valor. Na dupla, `$` e quase
#   sempre interpolacao de variavel, e continua excluido.
#
# Medido antes de ligar, sobre o HEAD de 03/10/2026: 7 linhas -- os 3 literais
# (Asaas, cron e visagismo) e as 4 excecoes abaixo. Com o `token` solto, 9.
#
# ---------------------------------------------------------------------------
# AS EXCECOES, cada uma com o motivo. Cada linha da lista e uma expressao sobre
# `arquivo:linha:conteudo`, e so perdoa aquele arquivo naquela forma.
#
#   1. VisagismoController, a atribuicao a `$this->tokenPadrao`. FICA por
#      decisao do dono: o visagismo e futuro, e mexer nele nao e deste
#      trabalho. O VALOR E O MESMO do token das rotinas, e continua aqui (e no
#      historico do git) mesmo depois de rotacionado: a rotacao do
#      `cron.token` de producao -- linha 9 do passo 5 do dia 0, crontab e
#      `local.php` no mesmo passo -- e o que faz este valor deixar de abrir as
#      26 rotinas. O que fazer com o visagismo e pergunta do lote de 03/10. E e
#      por causa dele que existe a busca PELO VALOR, abaixo. Ver o D4.
#   2. postgres/papeis.sql.modelo, o `PASSWORD` do papel `bvip_app`: e a
#      variavel do psql (`senha_app`), preenchida na hora. Nao ha senha no
#      arquivo.
#   3. scripts/ensaiar-sessao-do-erp.php, o ternario da mensagem "PEDIU
#      SENHA": o `:` dele tem a forma do de um YAML.
#   4. tests/, a constante `SENHA` privada: a senha INVENTADA do usuario de
#      fixture. A convencao da casa e justamente essa -- senha de teste so em
#      constante nomeada --, e o `-i` passou a ve-la.
#
# Excecao que nao perdoa mais nada e AVISADA: a lista encolhe por conserto.
#
# As expressoes trocam as aspas por `.` de proposito: escritas com as aspas,
# elas mesmas casariam o padrao, e este arquivo se acusaria.
#
# ---------------------------------------------------------------------------
# PELO VALOR, E NAO SO PELO NOME (03/10/2026, revisao do SEGREDOS).
#
# O padrao acima pega a ATRIBUICAO a um nome conhecido. Medido com linhas
# inventadas, deixava passar 13 de 21 formas -- entre elas as que uma
# regressao de verdade usaria: o valor-padrao na fabrica
# (`['cron']['token'] ?? '...'`), o literal como argumento
# (`new Asaas('...')`, `hash_equals('...', $t)`), uma constante de outro nome.
# Para os dois segredos que ESTAVAM no codigo, o valor e conhecido -- entao o
# portao os procura pelo valor, em qualquer forma:
#
#   - A CHAVE DO ASAAS tem prefixo fixo, `$aact_`, seguido de dezenas de
#     caracteres. O prefixo com 20 ou mais deles casa a chave em qualquer
#     forma, e nao casa quem so menciona o prefixo num texto.
#   - O TOKEN DAS ROTINAS continua escrito no VisagismoController (a excecao 1).
#     O portao le o valor DE LA, em memoria, e exige que ele nao apareca em
#     nenhum outro arquivo (`git grep -F`). Se o visagismo um dia sair do
#     codigo, nao ha mais o que procurar, e o portao avisa.
#
# Medido antes de ligar: na arvore de 03/10/2026, nenhuma linha a mais; sobre
# o HEAD, as mesmas duas que o nome ja pegava (Asaas.php e
# CronJobController.php).
#
# O que continua fora do alcance: um segredo NOVO, de valor desconhecido,
# atribuido a um nome que nao esta na lista. Nenhum portao textual pega isso.
#
# ---------------------------------------------------------------------------
# NAO IMPRIME O VALOR. O `git grep -n` do passo antigo imprimia a linha inteira
# -- no log do CI, a credencial que o portao acabava de achar. Aqui sai so
# `arquivo:linha`.

REV="${1:-}"

NOMES="password|passwd|senha|secret|api_?key|apikey|access_?token|bearer_?token|private_?key|client_?secret|token_?padrao|['\"]token"
CHAVE_ASAAS='\$aact_[A-Za-z0-9_]{20,}'
PADRAO="($NOMES)['\"]?\]?[[:space:]]*(=>|=|:)[[:space:]]*('[^']{6,}'|\"[^\"\$]{6,}\")|$CHAVE_ASAAS"

EXCECOES=$(cat <<'FIM'
^module/ISApi/src/Controller/VisagismoController\.php:[0-9]+:[[:space:]]*\$this->tokenPadrao = .
^postgres/papeis\.sql\.modelo:[0-9]+:ALTER ROLE bvip_app WITH PASSWORD :.senha_app.
^scripts/ensaiar-sessao-do-erp\.php:[0-9]+:[[:space:]]*\$paginaDoUm\[.senha.\] \? .PEDIU SENHA. : .logada.,$
^tests/[^:]+\.php:[0-9]+:[[:space:]]*private const SENHA = .
FIM
)

# Na arvore, `--untracked`: o arquivo novo, ainda fora do indice, tambem conta
# -- e e nele que o segredo novo costuma estar. Os ignorados (o `local.php`)
# ficam de fora, como devem.
if [ -n "$REV" ]; then
    NAO_VERSIONADOS=""
else
    NAO_VERSIONADOS="--untracked"
fi

# OS SCRIPTS DA CASA ENTRAM NA BUSCA (15/10/2026, a resposta 121 do dono, o
# D90). Desde a importacao o portao pulava `public/layout/scripts/` e todo
# `*.min.js`, sem motivo escrito -- o minificado, linha unica e nomes trocados,
# so daria ruido. Os oito minificados da casa sairam, e o que sobra na pasta e
# o legivel, editado a mao e entregue a todo navegador: e onde um segredo
# digitado vazaria. Medido antes de tirar as duas exclusoes: nenhuma linha
# casava nelas, nem nos `.min.js` do tema que ficaram (`public/global/scripts/`,
# `public/pages/scripts/`). Fica so a dos plugins de terceiros.
RC=0
ACHADOS=$(git grep -nEIi $NAO_VERSIONADOS -e "$PADRAO" $REV -- . \
    ':(exclude)public/global/plugins') || RC=$?

if [ "$RC" -gt 1 ]; then
    echo "NAO CONSEGUI MEDIR: o git grep saiu com $RC." >&2
    exit 2
fi

# Com revisao, o `git grep` prefixa cada linha com ela (`HEAD:arquivo:...`).
if [ -n "$REV" ]; then
    ACHADOS=$(printf '%s\n' "$ACHADOS" | sed "s|^$REV:||")
fi

LIDAS=$(printf '%s\n' "$ACHADOS" | grep -c . || true)
RESTO=$(printf '%s\n' "$ACHADOS" | grep . | grep -vE -e "$EXCECOES" || true)

printf '%s\n' "$EXCECOES" | while IFS= read -r exc; do
    if ! printf '%s\n' "$ACHADOS" | grep -qE -e "$exc"; then
        echo "AVISO: a excecao abaixo nao perdoa mais nada -- tire-a da lista."
        echo "    $exc"
    fi
done

# O VALOR DO TOKEN DAS ROTINAS, lido do VisagismoController da MESMA arvore
# (ou da mesma revisao) que se confere. Fica em variavel e nunca sai daqui: so
# `arquivo:linha` e impresso.
VISAGISMO="module/ISApi/src/Controller/VisagismoController.php"

if [ -n "$REV" ]; then
    FONTE_VISAGISMO=$(git cat-file -p "$REV:$VISAGISMO" 2>/dev/null || true)
else
    FONTE_VISAGISMO=$(cat "$VISAGISMO" 2>/dev/null || true)
fi

VALOR=$(printf '%s\n' "$FONTE_VISAGISMO" | sed -n "s/^[[:space:]]*\$this->tokenPadrao = '\([^']*\)';.*/\1/p" | head -n 1)
COM_VALOR=""

if [ "${#VALOR}" -lt 16 ]; then
    echo "AVISO: nao li o token do $VISAGISMO -- a busca PELO VALOR do token das rotinas nao rodou."
else
    RC_VALOR=0
    COM_VALOR=$(git grep -nIF $NAO_VERSIONADOS -e "$VALOR" $REV -- . ":(exclude)$VISAGISMO") || RC_VALOR=$?

    if [ "$RC_VALOR" -gt 1 ]; then
        echo "NAO CONSEGUI MEDIR: o git grep do valor saiu com $RC_VALOR." >&2
        exit 2
    fi

    if [ -n "$REV" ]; then
        COM_VALOR=$(printf '%s\n' "$COM_VALOR" | sed "s|^$REV:||")
    fi

    COM_VALOR=$(printf '%s\n' "$COM_VALOR" | grep . | cut -d: -f1,2 || true)
fi

VALOR=""
FONTE_VISAGISMO=""

if [ -n "$RESTO" ] || [ -n "$COM_VALOR" ]; then
    echo "::error::Credencial literal encontrada no codigo. Mova para config/autoload/local.php."

    if [ -n "$RESTO" ]; then
        printf '%s\n' "$RESTO" | cut -d: -f1,2 | sed 's/^/    /'
    fi

    if [ -n "$COM_VALOR" ]; then
        echo "  O VALOR do token das rotinas (o do $VISAGISMO), fora dele:"
        printf '%s\n' "$COM_VALOR" | sed 's/^/    /'
    fi

    exit 1
fi

echo "Nenhuma credencial literal encontrada (${LIDAS} linha(s) casaram, todas excecoes declaradas)."
exit 0
