Skip to content

Sync main repo#3

Open
ludioao wants to merge 8 commits intoAccordous:masterfrom
jdavidbakr:master
Open

Sync main repo#3
ludioao wants to merge 8 commits intoAccordous:masterfrom
jdavidbakr:master

Conversation

@ludioao
Copy link
Member

@ludioao ludioao commented Sep 22, 2025

Summary by CodeRabbit

  • Novas Funcionalidades

    • Rastreamento de links agora usa URLs assinadas.
    • Middleware de validação aprimorado com redirecionamento configurável e validação por evento/fallback.
    • Novo evento de validação de link e listener padrão que valida com base em domínios presentes no conteúdo.
  • Refatoração

    • Fluxo de rastreamento e rotas simplificados; remoção de endpoints/métodos legados.
  • Documentação

    • README atualizado com exemplo de registro do provedor e explicações ampliadas.
  • Testes

    • Suites ajustadas para URLs assinadas e ambiente de e-mail em log.
  • Chores

    • Nova opção de configuração para listeners de fallback.

LukeTowers and others added 7 commits April 28, 2025 06:28
Use strlen($pixel) instead of hardcoded 42 to ensure Content-Length matches the actual response size. Prevents FastCGI upstream warnings and ensures proper response behaviour across environments.
This PR declares the property `sent_email` in the `ValidActionEvent` class.
@coderabbitai
Copy link

coderabbitai bot commented Sep 22, 2025

Walkthrough

Este PR adiciona validação de links assinados via middleware customizado, introduz ValidLinkEvent e um listener de fallback por domínio, migra geração de links para URL::signedRoute, remove funções/rotas legadas, atualiza ServiceProvider/Controller/config/docs e adapta testes para URLs assinadas.

Changes

Cohort / File(s) Summary
Docs
README.md
Formatação e textos atualizados; exemplo de AppServiceProvider usa register() em vez de boot(); explicações sobre armazenamento de email revisadas.
Config
config/mail-tracker.php
Novo key fallback-event-listeners com DomainExistsInContentListener::class; formatação/alinhamento ajustados.
Eventos
src/Events/ValidActionEvent.php, src/Events/ValidLinkEvent.php
ValidActionEvent ganha propriedade pública sent_email; novo ValidLinkEvent com $valid, $sent_email, $url.
Listener de fallback
src/Listener/DomainExistsInContentListener.php
Novo listener que, quando log-content está ativo, marca o evento como válido se o domínio do URL existir no conteúdo do email.
Middleware de assinatura
src/Middleware/ValidateSignature.php
Novo middleware estendendo ValidateSignature: valida formato de URL, tenta validacao por assinatura e, em falha, dispara ValidLinkEvent como fallback antes de redirecionar.
Core e geração de links
src/MailTracker.php
Substitui route(...) por URL::signedRoute(...); remove método público hash_url; importa URL facade.
Controller
src/MailTrackerController.php
Consolida dispatch via Event::dispatch; usa strlen($pixel) para Content-Length; remove método getL(); refina fluxo de getN e headers.
Service Provider & Rotas
src/MailTrackerServiceProvider.php
Remove isLumen(); registra listeners de fallback a partir de config; simplifica registro de rotas (t, n com middleware ValidateSignature, sns); publica config/views sem guardas.
Modelo (docblocks)
src/Model/SentEmail.php
Atualiza phpdoc: meta pode ser `Collection
Testes & setup
tests/*, tests/SetUpTest.php
Tests adaptados para URL::signedRoute(...); remoção de try/catch em envios; import de URL; padronização de paths; mail.default = log nos testes.
Composer
composer.json
Expande constraint de illuminate/support para incluir ^13.0; atualiza dev-deps (phpunit, orchestra/testbench).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as Usuário
  participant R as Route /n
  participant M as Middleware ValidateSignature
  participant DB as Storage/DB (SentEmail)
  participant E as Event Bus
  participant L as DomainExistsInContentListener
  participant C as MailTrackerController

  U->>R: Acessa link assinado (`/n?h=...&l=...`)
  R->>M: Executa ValidateSignature
  M->>M: Valida formato de URL e assinatura
  alt Assinatura válida
    M->>C: next(request)
  else Assinatura inválida
    M->>DB: Busca SentEmail por hash
    M->>E: Dispatch ValidLinkEvent(sent_email, url)
    E->>L: handle(event)
    L-->>E: event.valid = true/false
    alt event.valid == true
      M->>C: next(request)
    else
      M-->>U: Redirect para config('mail-tracker.redirect-missing-links-to') ou "/"
    end
  end
  C->>DB: Atualiza tracker (opened_at / clicked_at)
  C-->>U: Redirect para URL destino
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutos

Poem

Fala meu truta, o link assinou, abriu o portal,
Middleware fiscal, evento faz o sinal.
Se a assinatura falhar, o listener dá o aval,
Domínio confere — segue o fluxo normal.
Pixel piscou, registro legal — MailTracker em festival 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive O título 'Sync main repo' é genérico e vago, não descrevendo especificamente quais mudanças principais foram introduzidas neste PR. Considere usar um título mais descritivo que capture as principais mudanças, como 'Add signed URL validation and fallback event listeners' ou 'Implement URL signing and event-driven link validation'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (10)
src/MailTracker.php (1)

218-224: Assinar link com TTL e escapar HTML no href.

  • Segurança: considere expirar a assinatura (ex.: horas/dias) para reduzir replay. Sugiro TTL configurável.
  • Robustez: encode do URL no atributo href evita HTML inválido quando houver &/aspas.

Aplicar:

-        return $matches[1].URL::signedRoute(
-            'mailTracker_n',
-            [
-                'l' => $url,
-                'h' => $this->hash,
-            ]
-        );
+        $ttl = config('mail-tracker.link-signature-ttl'); // segundos; null = sem expiração
+        $signedUrl = $ttl
+            ? URL::temporarySignedRoute(
+                'mailTracker_n',
+                now()->addSeconds($ttl),
+                ['l' => $url, 'h' => $this->hash]
+              )
+            : URL::signedRoute('mailTracker_n', ['l' => $url, 'h' => $this->hash]);
+        return $matches[1] . e($signedUrl);
src/Model/SentEmail.php (1)

57-69: Extrair domínios com mais precisão (suportar aspas simples e ignorar vazios).

Evita inserir null e cobre href='...'.

-    public function getDomainsInContextAttribute(){
-        preg_match_all("/(<a[^>]*href=[\"])([^\"]*)/", $this->content, $matches);
-        if ( ! isset($matches[2] ) ) return [];
-        $domains = [];
-        foreach($matches[2] as $url){
-            $domain = parse_url($url, PHP_URL_HOST);
-            if ( ! in_array($domain, $domains) ){
-                $domains[] = $domain;
-            }
-        }
-        return $domains;
-    }
+    public function getDomainsInContextAttribute()
+    {
+        if (! $this->content) return [];
+        preg_match_all('/<a[^>]*\bhref=(["\'])(.*?)\1/i', $this->content, $matches);
+        if (! isset($matches[2])) return [];
+        $set = [];
+        foreach ($matches[2] as $url) {
+            $host = parse_url($url, PHP_URL_HOST);
+            if ($host) {
+                $set[strtolower($host)] = true;
+            }
+        }
+        return array_keys($set);
+    }
src/Events/ValidActionEvent.php (1)

13-19: Tipar propriedades públicas.

Melhora autocompletar e evita uso incorreto.

-    public $skip = false;
-    public $sent_email;
+    public bool $skip = false;
+    public Model|SentEmailModel $sent_email;
src/Events/ValidLinkEvent.php (1)

13-21: Tipar propriedades e parâmetro $url.

Sinaliza contrato claro pro listener.

-    public $valid = false;
-    public $sent_email;
-    public $url;
+    public bool $valid = false;
+    public Model|SentEmailModel $sent_email;
+    public string $url;
-
-    public function __construct(Model|SentEmailModel $sent_email, $url)
+
+    public function __construct(Model|SentEmailModel $sent_email, string $url)
src/Listener/DomainExistsInContentListener.php (1)

11-17: Normalizar host e retornar cedo quando inválido.

Evita in_array(null, ...) e compara case‑insensitive.

-        $url_host = parse_url($event->url, PHP_URL_HOST);
+        $url_host = parse_url($event->url, PHP_URL_HOST);
+        if (! $url_host) {
+            return;
+        }
+        $url_host = strtolower($url_host);
         // If logging of content is on then
         if (config('mail-tracker.log-content', true)) {
-            if ($event->sent_email && !empty($event->sent_email->domains_in_context) && in_array($url_host, $event->sent_email->domains_in_context)) {
+            $domains = $event->sent_email ? array_map('strtolower', (array) $event->sent_email->domains_in_context) : [];
+            if (!empty($domains) && in_array($url_host, $domains, true)) {
                 $event->valid = true;
             }
         }
README.md (2)

192-213: Ajustar indentação dos bullets (MD007).

O linter aponta indentação 4 em vez de 2 espaços nos subitens das seções de eventos. Recomendo padronizar para 2 para evitar ruído em CI.

Exemplo de correção (mostrando um bloco representativo):

-    -   Public attribute `sent_email` contains the `SentEmail` model
+  - Public attribute `sent_email` contains the `SentEmail` model

211-214: Bullet faltando para TransientBouncedMessageEvent.

Adicionar o hífen para manter a lista consistente.

-    jdavidbakr\MailTracker\Events\TransientBouncedMessageEvent (when you receive a transient bounce. Check the event's public attributes for `bounce_sub_type` and `diagnostic_code` to determine if you want to do additional processing when this event is received.)
+-   jdavidbakr\MailTracker\Events\TransientBouncedMessageEvent (when you receive a transient bounce. Check the event's public attributes for `bounce_sub_type` and `diagnostic_code` to determine if you want to do additional processing when this event is received.)
config/mail-tracker.php (1)

108-114: Adicionar TTL configurável para assinatura de links.

Pra acompanhar a sugestão no MailTracker, proponho nova chave de config:

     'fallback-event-listeners' => [
         \jdavidbakr\MailTracker\Listener\DomainExistsInContentListener::class,
     ]
+    ,
+    /**
+     * Tempo de vida (em segundos) da URL assinada de redirecionamento. Null => não expira.
+     */
+    'link-signature-ttl' => null,
src/Middleware/ValidateSignature.php (1)

15-23: Validação de URL: restringir esquemas permitidos.

Hoje qualquer esquema válido no RFC passa (ex.: mailto:, data:). Sugiro limitar a http/https (ou tornar configurável) para reduzir superfície de open‑redirect com esquemas esquisitos mesmo quando assinados.

Aplique algo assim:

-        if (filter_var($url, FILTER_VALIDATE_URL) === false) {
+        if (filter_var($url, FILTER_VALIDATE_URL) === false) {
             throw new BadUrlLink('Mail hash: ' . $hash . ', URL: ' . $url);
-        }
+        }
+        $parts = parse_url($url);
+        if (! $parts || ! in_array(strtolower($parts['scheme'] ?? ''), ['http','https'], true)) {
+            throw new BadUrlLink('Mail hash: ' . $hash . ', URL: ' . $url);
+        }
tests/MailTrackerTest.php (1)

46-52: Aviso do PHPMD sobre parâmetro não usado.

Os métodos da handler de teste precisam do Throwable $e pela assinatura. Se o linter incomodar, podemos silenciar localmente com anotação.

Sugestão mínima:

-    public function report(Throwable $e)
+    /** @SuppressWarnings(PHPMD.UnusedFormalParameter) */
+    public function report(Throwable $e)
     {
     }
-    public function render($request, Throwable $e)
+    /** @SuppressWarnings(PHPMD.UnusedFormalParameter) */
+    public function render($request, Throwable $e)
     {
         throw $e;
     }

Also applies to: 50-53

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e9b665 and 96244f6.

📒 Files selected for processing (13)
  • README.md (6 hunks)
  • config/mail-tracker.php (3 hunks)
  • src/Events/ValidActionEvent.php (1 hunks)
  • src/Events/ValidLinkEvent.php (1 hunks)
  • src/Listener/DomainExistsInContentListener.php (1 hunks)
  • src/MailTracker.php (2 hunks)
  • src/MailTrackerController.php (3 hunks)
  • src/MailTrackerServiceProvider.php (6 hunks)
  • src/Middleware/ValidateSignature.php (1 hunks)
  • src/Model/SentEmail.php (1 hunks)
  • tests/MailTrackerControllerTest.php (3 hunks)
  • tests/MailTrackerTest.php (38 hunks)
  • tests/SetUpTest.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/Events/ValidLinkEvent.php (1)
src/MailTracker.php (1)
  • MailTracker (24-356)
src/Middleware/ValidateSignature.php (5)
src/MailTracker.php (2)
  • MailTracker (24-356)
  • sentEmailModel (76-79)
src/Events/ValidLinkEvent.php (1)
  • ValidLinkEvent (9-22)
src/Exceptions/BadUrlLink.php (1)
  • BadUrlLink (7-10)
src/Model/SentEmail.php (1)
  • SentEmail (26-70)
src/Listener/DomainExistsInContentListener.php (1)
  • handle (9-18)
src/Listener/DomainExistsInContentListener.php (2)
src/Events/ValidLinkEvent.php (1)
  • ValidLinkEvent (9-22)
src/Middleware/ValidateSignature.php (1)
  • handle (15-45)
src/MailTrackerServiceProvider.php (4)
src/MailTracker.php (1)
  • MailTracker (24-356)
src/Events/ValidLinkEvent.php (1)
  • ValidLinkEvent (9-22)
src/Listener/DomainExistsInContentListener.php (1)
  • DomainExistsInContentListener (7-19)
src/Middleware/ValidateSignature.php (1)
  • ValidateSignature (13-46)
src/MailTrackerController.php (3)
src/MailTracker.php (2)
  • MailTracker (24-356)
  • sentEmailModel (76-79)
src/Events/ValidActionEvent.php (1)
  • ValidActionEvent (9-20)
src/RecordLinkClickJob.php (1)
  • RecordLinkClickJob (13-64)
config/mail-tracker.php (1)
src/Listener/DomainExistsInContentListener.php (1)
  • DomainExistsInContentListener (7-19)
tests/MailTrackerTest.php (4)
src/MailTracker.php (3)
  • MailTracker (24-356)
  • sentEmailModel (76-79)
  • messageSent (117-128)
src/Events/EmailSentEvent.php (1)
  • EmailSentEvent (10-26)
src/RecordTrackingJob.php (1)
  • RecordTrackingJob (13-47)
src/Exceptions/BadUrlLink.php (1)
  • BadUrlLink (7-10)
🪛 PHPMD (2.15.0)
tests/MailTrackerTest.php

46-46: Avoid unused parameters such as '$e'. (undefined)

(UnusedFormalParameter)


173-173: Avoid unused local variables such as '$name'. (undefined)

(UnusedLocalVariable)


195-195: Avoid unused local variables such as '$name'. (undefined)

(UnusedLocalVariable)

🪛 markdownlint-cli2 (0.18.1)
README.md

193-193: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


195-195: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


196-196: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


198-198: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


199-199: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


200-200: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


205-205: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


206-206: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


208-208: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


209-209: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


212-212: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


213-213: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (21)
tests/SetUpTest.php (1)

62-64: Mail em testes via log: boa escolha, meu truta.

Definir mail.default = 'log' no ambiente de teste evita side‑effects e torna os testes determinísticos. Sem observações.

src/MailTracker.php (1)

12-12: Import do URL facade está correto.

Necessário para URL::signedRoute(...). Tudo certo aqui.

src/Model/SentEmail.php (1)

20-24: Atualização de PHPDoc: show.

Tipos nulos para meta e timestamps melhoram DX e ferramentas. Sem ressalvas.

README.md (1)

76-80: Exemplo no AppServiceProvider usando register(): ok.

Colocar MailTracker::ignoreMigrations() em register() é apropriado. Tudo certo.

config/mail-tracker.php (1)

108-113: Aprovado — fallback listeners (ValidLinkEvent) corretamente registrados e disparados.

ValidateSignature dispara ValidLinkEvent quando a assinatura falha; MailTrackerServiceProvider registra os listeners via Event::listen; DomainExistsInContentListener existe e trata o evento. Ver: src/MailTrackerServiceProvider.php, src/Middleware/ValidateSignature.php, src/Listener/DomainExistsInContentListener.php — fala, meu truta, sinal verde.

tests/MailTrackerControllerTest.php (2)

7-7: Import do URL facade — tudo certo.

Alinha os testes com o uso de URLs assinadas. Boa!


119-122: Uso da chave 'l' — perfeito.

Bate com o middleware ValidateSignature e com a injeção feita no MailTracker.

src/Middleware/ValidateSignature.php (2)

31-45: Fallback por evento quando assinatura falha — desenho sólido.

Resolve via ValidLinkEvent + listeners e redireciona para fallback quando inválido. Fluxo está consistente.


24-29: Checagem da assinatura — ok; confirmar existência de Request::hasValidSignatureWhileIgnoring

Fala meu truta — parseArguments + chamada parecem corretas. composer.json não referencia laravel/framework e não há vendor/ nem composer.lock; a única ocorrência da chamada é src/Middleware/ValidateSignature.php:27. Confirma localmente se Request::hasValidSignatureWhileIgnoring existe na instalação (vendor/) ou no Request usado; se não existir, troque por hasValidSignature (Laravel) ou adicione uma implementação compatível.

src/MailTrackerController.php (3)

16-20: Content-Length dinâmico no pixel — show.

Evita número mágico e garante header correto.


30-31: Dispatch via facade Event — alinhado.

Troca por Event::dispatch centraliza o padrão no pacote.


47-76: Fluxo do getN está redondo.

  • Usa 'l'/'h' do request, dispara job de click, ajusta opened_at/clicked_at e salva uma vez.
  • Redireciona sempre (tracking pode ser pulado sem quebrar UX).
    Tudo coerente com o middleware.
src/MailTrackerServiceProvider.php (3)

45-51: Listeners de fallback configuráveis — mandou bem.

Registro do ValidLinkEvent com lista de listeners via config facilita extensão sem fork.


110-114: Rota 'n' com middleware ValidateSignature — certinho.

Garante validação antes do controller e mantém o nome da rota usado pelo MailTracker/URL::signedRoute.


85-89: Confirmar typo: "emailTrakingViews" (sem 'c')

Fala, meu truta — referências encontradas em: README.md, src/MailTrackerServiceProvider.php, src/views/emails/mensaje.blade.php, src/AdminController.php, config/mail-tracker.php. Mudar o namespace quebrará compatibilidade; se for legado, mantenha. Se for corrigir antes do release, atualize todas as referências e registre ambos os namespaces no ServiceProvider (emailTrakingViews + emailTrackingViews) ou documente a migração para evitar BC break.

tests/MailTrackerTest.php (6)

387-396: URL assinada no teste de link — ok.

Cobre clique, fila e timestamps; cenário feliz está bem testado.


425-433: Caminho de fallback com rota não assinada — ótimo.

Valida o redirect configurado quando hash inválido/sem assinatura.


438-450: Validação por domínio no conteúdo — cobertura boa.

Exercita o DomainExistsInContentListener corretamente.


473-483: Entrada inválida em 'l' gera BadUrlLink — teste necessário.

Traz segurança contra lixo/strings aleatórias.


846-871: Teste de ampersands — robusto.

Regex + redirecionamento e contagem de cliques verificados. Tudo nos conformes.


928-936: Teste de apóstrofo nas URLs — beleza.

Garante que a assinatura/redirect não se perde com caracteres especiais.

Comment on lines +110 to +114
```php
'log-content-strategy' => 'filesystem',
'tracker-filesystem' => null
'tracker-filesystem-folder' => 'mail-tracker',
````
To use the filesystem you need to change the `log-content-strategy` from `database` to `filesystem`.
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Vírgula faltando no snippet de config (quebra PHP ao copiar/colar).

Entre as linhas 'tracker-filesystem' e 'tracker-filesystem-folder' falta uma vírgula.

-    'tracker-filesystem' => null
+    'tracker-filesystem' => null,
     'tracker-filesystem-folder' => 'mail-tracker',
🤖 Prompt for AI Agents
In README.md around lines 110 to 114, the PHP config snippet is missing a comma
after the 'tracker-filesystem' line which will break PHP when copy/pasting; add
a trailing comma immediately after the 'tracker-filesystem' entry so the array
elements are properly separated and the snippet is valid PHP.

Comment on lines +91 to 94
$this->get(URL::signedRoute('mailTracker_n', [
'n' => $redirect,
'h' => $email->hash,
]));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Bug: parâmetro incorreto na URL assinada ('n' vs 'l').

O middleware e o controller usam a chave 'l' para o link. Aqui está 'n', o que vai causar BadUrlLink/queda no middleware. Trocar para 'l'.

Aplique este diff:

-        $this->get(URL::signedRoute('mailTracker_n', [
-            'n' => $redirect,
-            'h' => $email->hash,
-        ]));
+        $this->get(URL::signedRoute('mailTracker_n', [
+            'l' => $redirect,
+            'h' => $email->hash,
+        ]));

Rode este script pra garantir que não ficou nenhum outro uso com a chave errada:


🏁 Script executed:

#!/bin/bash
rg -nP "signedRoute\('mailTracker_n',\s*\[\s*'n'\s*=>" -S

Length of output: 0


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "PWD: $(pwd)"
echo "---- top-level ----"
ls -la | sed -n '1,200p' || true

echo
echo "---- search: mailTracker_n ----"
rg -n --hidden -S "mailTracker_n" -C3 || true

echo
echo "---- search: signedRoute('mailTracker_n' ----"
rg -n --hidden -S "signedRoute\(\s*['\"]mailTracker_n['\"]" -P -C3 || true

echo
echo "---- search: signedRoute calls that include a literal 'n' key in params (loose) ----"
rg -n --hidden -S "signedRoute\(\s*['\"][^'\"]+['\"]\s*,\s*\[.*'n'\s*=>" -P -C3 || true

echo
echo "---- search: literal array key 'n' => ----"
rg -n --hidden -S "'n'\s*=>" -P -C2 || true

echo
echo "---- search: literal array key 'l' => ----"
rg -n --hidden -S "'l'\s*=>" -P -C2 || true

echo
echo "---- search: MailTracker-related symbols (MailTrackerController, BadUrlLink, mailTracker) ----"
rg -n --hidden -S "MailTrackerController|BadUrlLink|mailTracker" -C3 || true

echo
echo "---- show test file if exists ----"
if rg -n --hidden -S "class .*MailTrackerControllerTest" -g '!vendor' -C2 >/dev/null 2>&1; then
  f=$(rg -n --hidden -S "class .*MailTrackerControllerTest" -g '!vendor' -l)
  echo "Found: $f"
  sed -n '1,260p' "$f"
else
  echo "No MailTrackerControllerTest class found in repo."
fi

Length of output: 29272


Corrigir parâmetro incorreto na URL assinada: 'n' → 'l'

Fala meu truta — o middleware/Controller usam a chave 'l'; em tests/MailTrackerControllerTest.php (linhas 91–94) está 'n' e isso vai causar BadUrlLink. Trocar para 'l'.

-        $this->get(URL::signedRoute('mailTracker_n', [
-            'n' => $redirect,
-            'h' => $email->hash,
-        ]));
+        $this->get(URL::signedRoute('mailTracker_n', [
+            'l' => $redirect,
+            'h' => $email->hash,
+        ]));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$this->get(URL::signedRoute('mailTracker_n', [
'n' => $redirect,
'h' => $email->hash,
]));
$this->get(URL::signedRoute('mailTracker_n', [
'l' => $redirect,
'h' => $email->hash,
]));
🤖 Prompt for AI Agents
In tests/MailTrackerControllerTest.php around lines 91 to 94, the signedRoute
call uses the wrong query key 'n' which the controller/middleware expect as 'l';
update the signedRoute parameter key from 'n' to 'l' so the test builds a URL
that matches the controller's expected signed parameter (keep the same $redirect
value and 'h' => $email->hash).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@composer.json`:
- Around line 28-29: The composer constraint for "orchestra/testbench" includes
an unstable release (^11.0); update the dependency in composer.json to remove
the ^11.0 alternative and only allow stable releases (e.g., change
"orchestra/testbench": "^8.0|^9.0|^10.0" or use an explicit stable range like
">=8.0 <11.0"), then run composer update to verify compatibility and confirm the
chosen version matches the Laravel target.
- Around line 20-30: Update the PHP requirement in composer.json from "php":
"^8.1" to "php": "^8.3" so the package guarantees compatibility with Laravel 13;
locate the "require" block in composer.json (the "php" key) and change its
version constraint to ^8.3, then run composer validate and composer update (or
update your CI matrix) to ensure dependencies resolve against PHP 8.3.
- Line 22: The composer.json currently pins unavailable future releases
("illuminate/support": "^13.0" and "orchestra/testbench": "^11.0") which will
break installs; update composer.json to remove the unsupported ^13.0 from the
"illuminate/support" constraint and replace or restrict "orchestra/testbench" to
the latest available stable (e.g., "10.9.0" or "^10.9") or a dev branch if
intentional, or alternatively add a clear inline comment next to the
"illuminate/support" and "orchestra/testbench" entries noting these entries are
reserved for future support and must be reverted/updated when those versions are
officially released (refer to the package keys "illuminate/support" and
"orchestra/testbench" to locate and change the constraints).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96244f6 and 727cbfc.

📒 Files selected for processing (1)
  • composer.json

Comment on lines 20 to 30
"require": {
"php": "^8.1",
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0|^13.0",
"guzzlehttp/guzzle": "^7.2",
"aws/aws-php-sns-message-validator": "^1.8",
"aws/aws-sdk-php": "^3.258"
},
"require-dev": {
"phpunit/phpunit": "^9.5.10|^10.5|^11.5.3",
"orchestra/testbench": "^8.0|^9.0|^10.0",
"phpunit/phpunit": "^9.5.10|^10.5|^11.5.3|^12.5.12",
"orchestra/testbench": "^8.0|^9.0|^10.0|^11.0",
"mockery/mockery": "^1.4.4"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Laravel 13 minimum PHP version requirement official documentation

💡 Result:

Laravel 13 requires PHP 8.3 or higher (supported PHP range listed as 8.3–8.5 in Laravel’s official Support Policy table). [1]


Ajustar requisito de PHP para Laravel 13, meu truta!

Meu brother, a preocupação é válida mesmo! Laravel 13 requer PHP 8.3 ou superior, mas o php: ^8.1 permite versões 8.1 e 8.2 que não são oficialmente suportadas. Para garantir compatibilidade total com o Laravel 13, muda pra php: ^8.3 no composer.json.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@composer.json` around lines 20 - 30, Update the PHP requirement in
composer.json from "php": "^8.1" to "php": "^8.3" so the package guarantees
compatibility with Laravel 13; locate the "require" block in composer.json (the
"php" key) and change its version constraint to ^8.3, then run composer validate
and composer update (or update your CI matrix) to ensure dependencies resolve
against PHP 8.3.

"require": {
"php": "^8.1",
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0|^13.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Laravel 13 release date 2025 2026

💡 Result:

Laravel 13 is not a 2025 release. Laravel’s official release/support policy lists Laravel 13’s release as “Q1 2026” (no specific day announced there). Laravel 12 was released February 24, 2025, which is the current major release preceding 13. [1]

Answer: Laravel 13 release window: Q1 2026 (expected), not 2025. [1]

Sources:
[1] Laravel official docs – Release Notes / Support Policy (shows Laravel 13: “Q1 2026”)


🌐 Web query:

PHPUnit 12.5.12 packagist availability

💡 Result:

Yes—phpunit/phpunit 12.5.12 is available on Packagist (it appears in the published versions list for the package). You can install it via Composer with:

composer require --dev phpunit/phpunit:12.5.12

[1]


🌐 Web query:

Orchestra Testbench 11.0 release

💡 Result:

As of February 27, 2026, Orchestra Testbench 11.0 has not been released (no v11.0.0 tag on Packagist). Packagist shows only an 11.x-dev development branch, while the latest stable release is v10.9.0 (released 2026-01-14). [1]

Source: Packagist package page for orchestra/testbench. [1]


Meu truta, duas dependências não foram lançadas ainda!

Fala! Encontrei um problema aqui no composer.json: o ^13.0 do illuminate/support e o ^11.0 do orchestra/testbench não estão disponíveis no Packagist ainda.

  • Laravel 13: Esperado para Q1 2026 (não foi lançado ainda)
  • Orchestra Testbench 11.0: Não existe (só tem a branch 11.x-dev disponível; a versão estável mais recente é a 10.9.0 lançada em 14 de janeiro de 2026)

Essas constraints vão quebrar a instalação do package até que essas versões sejam efetivamente lançadas. Recomendo remover essas versões futuras ou adicionar um comentário indicando que são para suporte futuro.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@composer.json` at line 22, The composer.json currently pins unavailable
future releases ("illuminate/support": "^13.0" and "orchestra/testbench":
"^11.0") which will break installs; update composer.json to remove the
unsupported ^13.0 from the "illuminate/support" constraint and replace or
restrict "orchestra/testbench" to the latest available stable (e.g., "10.9.0" or
"^10.9") or a dev branch if intentional, or alternatively add a clear inline
comment next to the "illuminate/support" and "orchestra/testbench" entries
noting these entries are reserved for future support and must be
reverted/updated when those versions are officially released (refer to the
package keys "illuminate/support" and "orchestra/testbench" to locate and change
the constraints).

Comment on lines +28 to +29
"phpunit/phpunit": "^9.5.10|^10.5|^11.5.3|^12.5.12",
"orchestra/testbench": "^8.0|^9.0|^10.0|^11.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verificar as versões disponíveis dos pacotes no Packagist

echo "=== PHPUnit 12.x versions ==="
curl -s https://packagist.org/packages/phpunit/phpunit.json | jq '.package.versions | keys[] | select(startswith("12."))' | sort -V

echo ""
echo "=== Orchestra Testbench 11.x versions ==="
curl -s https://packagist.org/packages/orchestra/testbench.json | jq '.package.versions | keys[] | select(startswith("11."))' | sort -V

Repository: Accordous/mail-tracker

Length of output: 759


Ó meu truta, achei um problema sério na constraint do Orchestra Testbench!

E aí, parceiro! Verifiquei lá no Packagist e encontrei:

  • PHPUnit 12.5.12: Existe sim, e usar ^12.5.12 é válido (permite patches como 12.5.13, 12.5.14+)
  • Orchestra Testbench 11.0: Problema aqui, meu irmão! Não existem releases estáveis da v11 ainda — apenas 11.x-dev. A constraint ^11.0 tentará instalar a versão de desenvolvimento, o que pode causar instabilidade.

Recomendo verificar qual é a versão estável mais recente compatível com Laravel 13 ou aguardar um release estável do Testbench v11.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@composer.json` around lines 28 - 29, The composer constraint for
"orchestra/testbench" includes an unstable release (^11.0); update the
dependency in composer.json to remove the ^11.0 alternative and only allow
stable releases (e.g., change "orchestra/testbench": "^8.0|^9.0|^10.0" or use an
explicit stable range like ">=8.0 <11.0"), then run composer update to verify
compatibility and confirm the chosen version matches the Laravel target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants