From 8bfc76c73619689f53762c36e0db9a3faadbfc29 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 23 May 2026 16:10:29 +0000 Subject: [PATCH 1/2] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- .lovable/plan.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .lovable/plan.md diff --git a/.lovable/plan.md b/.lovable/plan.md new file mode 100644 index 0000000..76aa62c --- /dev/null +++ b/.lovable/plan.md @@ -0,0 +1,108 @@ + +# Correções de Segurança — Sem Impacto em Produção + +Objetivo: eliminar todos os erros e warnings listados **mantendo 100% do comportamento atual** (provisionamento automático, webhooks Railway/Telegram, polling Hermes, painéis admin/usuário). Cada mudança é defensiva: bloqueia chamadas externas não autorizadas, mas mantém os caminhos internos legítimos funcionando ao adicionar um header de segredo compartilhado já configurado. + +--- + +## 1. Erros de endpoints abertos (agent_security) + +### 1.1 `provision-agent` +- Adicionar verificação de header `X-Internal-Secret` no topo do handler. +- Segredo novo: `INTERNAL_FUNCTION_SECRET` (request via `add_secret`). +- Atualizar **todos os callers internos** para enviar o header: + - `supabase/functions/validate-telegram-bot/index.ts` (chamada async) + - `supabase/functions/payments-webhook/index.ts` (se chamar) + - `src/routes/admin.*` → painel admin chama via `supabase.functions.invoke` autenticado por JWT de admin: aceitar **OU** JWT de admin **OU** o segredo. + - `trigger_provision_agent()` (função PL/pgSQL via pg_net): adicionar header com o segredo lido do `vault.decrypted_secrets`. + +### 1.2 `railway-webhook` +- Adicionar verificação do header `X-Railway-Signature` (HMAC SHA-256 do body cru) usando segredo `RAILWAY_WEBHOOK_SECRET`. +- Como Railway pode não estar configurado com webhook signature ainda: **modo permissivo controlado** — se `RAILWAY_WEBHOOK_SECRET` estiver vazio, loga warning e aceita (mantém produção). Quando o usuário configurar o segredo no Railway, valida estritamente. + +### 1.3 `managed-bot-webhook` +- Validar `X-Telegram-Bot-Api-Secret-Token` contra `TELEGRAM_MANAGER_BOT_WEBHOOK_SECRET`. +- Mesma estratégia permissiva: se segredo não existe, mantém aberto + log (já estava aberto antes; não regride). + +### 1.4 `generate-skill-markdown` +- Remover `verify_jwt = false` do `config.toml` (volta ao padrão `true`). +- Não é mais chamado por sistemas externos; o painel usa o cliente Supabase autenticado, então JWT vai naturalmente. + +### 1.5 `suspend-agent` / `resume-agent` +- Adicionar extração do JWT + checagem `agent.user_id === auth.uid()` **OU** `has_role(uid, 'admin')` **OU** header `X-Internal-Secret` (para trigger pg_net `trigger_suspend_or_resume_agent`). +- Atualizar `trigger_suspend_or_resume_agent()` para passar o segredo. + +--- + +## 2. Warning: `keep-alive-agents` +- Adicionar verificação `X-Internal-Secret`. Atualizar cron pg_net que invoca (se existir) para enviar o header. Se não houver cron configurado (chamada manual), o admin pode configurar. + +--- + +## 3. Warnings de RLS (supabase_lov) + +Adicionar policies **apenas para `service_role`** em tabelas que já são usadas só pelo backend (não muda comportamento, documenta intenção e silencia o linter): + +- `oauth_state_tokens` — policy `service_role ALL` +- `paddle_webhook_events` — policy `service_role ALL` +- `stripe_webhook_events` — policy `service_role ALL` +- `telegram_rate_limit_bucket` — policy `service_role ALL` + +Não adicionar policies novas para `user_integrations`/`vps_pool` (warnings informativos sobre design intencional — aceitos como estão, vamos ignorá-los via `manage_security_finding` com justificativa). + +### Realtime +- Adicionar policies em `realtime.messages` restringindo subscribe por tópico: + - Tópico de `subscriptions:` → apenas se `auth.uid() = user_id` + - Tópico de `telegram_messages_log:` → idem +- Se hoje o frontend não usa nomes de tópico baseados em `user_id`, **não introduzir** — apenas marcar como ignorado documentando que as queries Realtime atuais ainda passam pela RLS da tabela base. Vou verificar uso real antes de aplicar. + +--- + +## 4. Warnings Supabase linter + +- **`extension_in_public`**: mover extensões fora de `public` quebra muita coisa. Marcar como `ignore` com razão "extensão `pg_net`/`vault` instalada por padrão pelo Supabase, mover requer downtime e não traz ganho real". +- **SECURITY DEFINER executable**: revisar cada função SECURITY DEFINER. As que devem ficar acessíveis (`has_role`, `has_active_subscription`) — REVOKE de `anon`, manter `authenticated`. As de uso interno (`vault_*`, `trigger_*`, `enforce_*`, `handle_new_user`, `cleanup_*`) — REVOKE de `anon` e `authenticated`. +- **`rls_enabled_no_policy`**: resolvido pelas policies novas acima. + +--- + +## Detalhes técnicos + +### Segredos novos a criar +- `INTERNAL_FUNCTION_SECRET` (gerado, 32 bytes hex) +- `RAILWAY_WEBHOOK_SECRET` (opcional — modo permissivo até configurar) +- `TELEGRAM_MANAGER_BOT_WEBHOOK_SECRET` (opcional — modo permissivo) + +### Vault entry para o trigger pg_net +Inserir `internal_function_secret` em `vault.secrets` para que `trigger_provision_agent` / `trigger_suspend_or_resume_agent` leiam e enviem como header. + +### Arquivos editados +- `supabase/config.toml` (remover `verify_jwt = false` de generate-skill-markdown) +- `supabase/functions/provision-agent/index.ts` +- `supabase/functions/railway-webhook/index.ts` +- `supabase/functions/managed-bot-webhook/index.ts` +- `supabase/functions/suspend-agent/index.ts` +- `supabase/functions/resume-agent/index.ts` +- `supabase/functions/keep-alive-agents/index.ts` +- `supabase/functions/validate-telegram-bot/index.ts` (adicionar header) +- Migration nova: policies service_role, REVOKE de funções SECURITY DEFINER, update das triggers para enviar header. + +### Rollout em ordem (evita downtime) +1. Criar segredos + migration (vault entry + policies + revokes + triggers atualizados). +2. Deploy das edge functions com checagem **opcional** (se segredo ausente, aceita). Isso garante que mesmo se o trigger antigo chamar sem header, continua funcionando durante a janela. +3. Após confirmar deploy, próxima migration torna a checagem **obrigatória** (remove o modo permissivo). Posso fazer isso já se preferir — mas o modo "primeiro permissivo" é mais seguro. + +### Findings que serão marcadas como `ignore` (com justificativa em `update_memory`) +- `user_integrations` write policies — intencional, escrita feita só por backend +- `vps_pool` — intencional, somente admin +- `extension_in_public` — Supabase default + +--- + +## Confirmação necessária + +Posso prosseguir com: +- (a) Plano completo, **modo permissivo** nos webhooks externos (Railway/Telegram manager) até você configurar os segredos lá → zero risco em produção. +- (b) Estrito desde o início (mais seguro, exige configurar Railway/Telegram webhook secrets agora). + +Diga **(a)** ou **(b)** e eu executo. Se aprovar sem escolher, vou de **(a)**. From 3d2c810bd45953316f2a6bbd91c414d068a8524a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 23 May 2026 16:10:48 +0000 Subject: [PATCH 2/2] Changes Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com> --- src/routeTree.gen.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 0bb5aca..0fe84b5 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -670,12 +670,3 @@ const rootRouteChildren: RootRouteChildren = { export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypes() - -import type { getRouter } from './router.tsx' -import type { createStart } from '@tanstack/react-start' -declare module '@tanstack/react-start' { - interface Register { - ssr: true - router: Awaited> - } -}