O runner (gitea-runner) roda como root e é compartilhado com outras
automações deste servidor, então não dá pra trocar o usuário dele
globalmente. O rsync que lê o checkout continua como root (é a única
forma de ler, o workspace do runner é privado dele), mas logo depois
do sync a posse dos arquivos passa pro 'desenvolvimento', e dali em
diante (npm ci, node --check, pm2 startOrRestart/save/list) tudo roda
via sudo -u desenvolvimento - resolve o processo órfão de root que
duplicava o cron ao lado do PM2 do desenvolvimento.
${{ secrets.ENV_PRODUCTION }} usado direto dentro de um run: substitui o texto
antes do bash rodar - qualquer '$algo' dentro do conteudo do .env.production
(por exemplo em senhas) era interpretado como expansao de variavel de shell.
Com set -u ligado isso quebrou o step "Check required secrets" (variavel nao
definida = erro fatal). Sem set -u, o step "Write .env.production from
secret" teria o mesmo problema de forma silenciosa: qualquer '$algo' dentro
das credenciais reais seria substituido por vazio no arquivo escrito na VM,
corrompendo senha sem nenhum aviso.
Corrige passando o secret via env: e referenciando como variavel de ambiente
normal ($ENV_PRODUCTION) nos dois steps - bash trata o valor como dado opaco,
sem tentar expandir nada dentro dele.
O head fecha o pipe apos ler a primeira linha, o rsync recebe broken pipe e sai
com codigo de erro, e o pipefail propaga isso como falha do step inteiro -
mesmo a versao ja tendo sido impressa com sucesso. Confirmado no primeiro run
real do workflow em producao: Preflight falhou logo depois de imprimir as
versoes, todos os steps seguintes (secrets, validacao, deploy) ficaram
pulados, sem tocar na VM.
Adiciona um step que escreve o .env.production a partir do secret ENV_PRODUCTION
do Gitea Actions (com chmod 600), eliminando o modelo anterior de manter esse
arquivo manualmente na VM sem nenhuma copia de seguranca. Um step anterior falha
cedo e com mensagem clara se o secret nao estiver configurado.
Antes de sincronizar o codigo novo, guarda a versao anterior em
$DEPLOY_PATH.previous, permitindo rollback manual rapido caso o deploy suba
algo quebrado (o node --check so pega erro de sintaxe, nao de logica).
Troca a lista fixa de arquivos validados por node --check (que ja estava
desatualizada, sem cobrir arquivos tocados em mudancas recentes) por uma
varredura em todo .js do projeto.
Consolida os dois controladores legados que decidiam status/fechamento de
forma concorrente (processGlpiClosureController + processStatusController)
em um único processTicketLifecycleController, eliminando a dependência do
campo source_last (mantido só como rastro de auditoria) e a flag
ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados
reabertos no SN voltavam a ser fechados no GLPI porque a regra de
precedência de finalização do fluxo legado forçava o status do GLPI de
volta pro SN.
Correções de bugs encontrados em teste (Frente 1):
- Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING
na criação do registro, prevenindo duplicação de tickets.
- Fechamento no SN agora é confirmado por leitura ao vivo do status antes
de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200
(a API do SN pode retornar sucesso e silenciosamente ignorar um valor de
estado inválido — descoberto e corrigido também no mandante).
- Nota de encerramento do SN pro GLPI agora é idempotente e criada uma
única vez por ticket.
- Erros de sincronização passam a ter um limite de tentativas
(MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent,
exigindo intervenção manual em vez de tentar para sempre.
- Chamados criados no GLPI passam a gravar o número do ticket do SN no
campo externalid.
Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por
conta própria antes do GLPI, além da nota informativa no GLPI (agora com o
nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/
sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais
atender aquele chamado e ele é transferido pra fila de TI da CAOA.
Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e
configurável de status intermediário (Aguardando Atendimento/Em
Atendimento/Em Espera) entre os dois sistemas, controlado pela env
MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual
(nenhum espelhamento de status intermediário). Nunca afeta os status finais
(resolvido/encerrado/fora de escopo), que continuam regidos pelas regras
fixas de fechamento.
Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml),
que ainda validava os controladores antigos (já removidos) e exigia
ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>