Go to file
nexxo a39670f920 Close the safety-net gaps the review found in MailboxTransport
The reviewer continued the mutation sweep from Task 4's own commit and
found three more unpinned lines in delegate(), plus two real behaviour
gaps, all inside the same 40-line method:

- The fingerprint refresh (the headline feature: a worker's mailer
  must pick up a corrected password without a restart) had no test —
  mutating its check to "delegate === null" left the suite green.
- The implicit-TLS third argument to EsmtpTransport had no test either
  — mutating it to a hardcoded true left the suite green, because the
  only assertion touching it was instanceof EsmtpTransport, which the
  hanging variant also satisfies.
- isLogging() only ever checked for 'log', but phpunit.xml sets
  MAIL_MAILER=array for the whole suite. Task 5 wires real mailables
  to these mailers next; the first feature test that sends one without
  Mail::fake() would have opened a real SMTP connection.
- describe() and delegate() each ran their own copy of that guard —
  which is exactly how deleting it from ONLY delegate() passed the
  whole suite in the first place: __toString() kept reporting "log"
  from its own untouched copy.
- An unconfigured host/port (Settings::get('mail.host', '') and a
  stored null port casting to 0) built a transport pointed at
  smtp://:587 or silently downgraded to plaintext port 25, instead of
  refusing the way a missing mailbox already does.

Fixes: replaced isLogging() with resolution(), the one place that now
decides "log, array, null-default, or a real mailbox" — describe() and
delegate() both branch on ITS result, so a guard broken in one cannot
look fine in the other. Added an explicit RuntimeException for a blank
host or non-positive port, guarded the same way as the missing-mailbox
case just above it.

Tests: added coverage for the fingerprint rebuild (reuses the same
delegate until the password actually changes, proven by object
identity), the exact DSN string for both the STARTTLS (587) and
implicit-TLS (465) cases, 'array' and unset-default both landing on a
non-delivering transport, and the blank host/bad port throwing.
Mutated each of these four in turn on the final code and confirmed:
fingerprint check removed -> the reuse test fails (same object handed
back after the password changed); TLS argument hardcoded true -> the
587 DSN test fails ('smtps://...' where 'smtp://...:587' was
expected); NON_DELIVERING narrowed back to ['log'] -> both the array
and unset-default tests fail (a real EsmtpTransport where a safe
transport was expected); host/port guards removed -> both throw
expectations fail. Reverted each, reran, all twelve tests pass again.

Replaced the two tests that reached into delegate() via Closure::bind
to check "log or SMTP" with one behavioural test: point Settings at a
closed loopback port (127.0.0.1:1, so refusal is instant and entirely
local — no DNS, no dependency on this environment's network egress
policy) and assert Log::shouldReceive('debug')->once() while sending
for real through Mail::mailer('cp_support')->raw(...). Mutated
NON_DELIVERING to drop 'log' specifically and confirmed this test
alone catches it: a real connection attempt to the closed port throws
TransportException (Connection refused) in under 300ms. Reverted,
reran, passes again.

Also: the two tests that only checked the config array's shape and a
snapshot of the resolved address promised more than they verified —
CLAUDE.md R19 names a test that recomputes the implementation as
checking nothing. Added a source-level test that the five cp_* config
entries are parenthesis-free literals (same technique
DisplayTimezoneTest/IconLayoutTest use: a property of the file, not of
one run) as the actual "no query at boot" proof, and renamed the
send-time test to what it verifies now that the fingerprint test above
covers the live-refresh claim properly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 23:02:18 +02:00
.gitea/workflows feat(deploy): releases you can pin to, and a version that tells the truth 2026-07-26 15:21:38 +02:00
.npm chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
app Close the safety-net gaps the review found in MailboxTransport 2026-07-27 23:02:18 +02:00
bin Make the private hostnames look like nothing is there, and close the way past the proxy 2026-07-27 11:26:48 +02:00
bootstrap feat(security): the console decides who may reach it, and the owner keeps the list 2026-07-26 20:27:26 +02:00
config Resolve the sending mailbox when the mail goes out, not at boot 2026-07-27 22:28:37 +02:00
database Reuse the existing UUID trait instead of a second copy of the logic 2026-07-27 21:31:39 +02:00
deploy Show times on the operator's clock, keep storing them in UTC 2026-07-27 17:32:21 +02:00
docker Give the readiness probe long enough for a restart to finish 2026-07-27 14:46:47 +02:00
docs Make the SECRETS_KEY test able to fail 2026-07-27 21:44:59 +02:00
lang Editing in modals, an update button that is not gated on a stale reading, and a support page that is real 2026-07-27 17:55:49 +02:00
public Rebuild the public site as a document, and read prices from the catalogue 2026-07-27 03:52:25 +02:00
resources Editing in modals, an update button that is not gated on a stale reading, and a support page that is real 2026-07-27 17:55:49 +02:00
routes Editing in modals, an update button that is not gated on a stale reading, and a support page that is real 2026-07-27 17:55:49 +02:00
storage chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
tests Close the safety-net gaps the review found in MailboxTransport 2026-07-27 23:02:18 +02:00
.dockerignore chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
.editorconfig chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
.env.example Show times on the operator's clock, keep storing them in UTC 2026-07-27 17:32:21 +02:00
.gitattributes chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
.gitignore Keep the SDD scratch directory out of the repository 2026-07-27 21:06:07 +02:00
.npmrc chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
CLAUDE.md Editing in modals, an update button that is not gated on a stale reading, and a support page that is real 2026-07-27 17:55:49 +02:00
README.md chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
VERSION feat(deploy): releases you can pin to, and a version that tells the truth 2026-07-26 15:21:38 +02:00
artisan chore: bootstrap CluPilot control-plane (Laravel 13, Docker stack) 2026-07-25 00:21:30 +02:00
composer.json feat(vpn): ownership, a Developer role, and password-gated config retrieval 2026-07-25 22:31:54 +02:00
composer.lock feat(vpn): ownership, a Developer role, and password-gated config retrieval 2026-07-25 22:31:54 +02:00
docker-compose.yml Ask the tunnel gateway where it actually listens 2026-07-27 14:43:23 +02:00
package-lock.json Rebuild the public site as a document, and read prices from the catalogue 2026-07-27 03:52:25 +02:00
package.json Rebuild the public site as a document, and read prices from the catalogue 2026-07-27 03:52:25 +02:00
phpunit.xml fix(billing): a paid order opens a contract, and provisioning obeys it 2026-07-26 11:10:00 +02:00
postcss.config.js feat(portal): design foundation — Tailwind v3, tokens, self-hosted fonts 2026-07-25 00:43:01 +02:00
tailwind.config.js Rebuild the public site as a document, and read prices from the catalogue 2026-07-27 03:52:25 +02:00
vite.config.js feat(ops): update page, automatic 419 recovery, CI workflow 2026-07-26 00:58:27 +02:00

README.md

Laravel Logo

Build Status Total Downloads Latest Stable Version License

About Laravel

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:

Laravel is accessible, powerful, and provides tools required for large, robust applications.

Learning Laravel

Laravel has the most extensive and thorough documentation and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

In addition, Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

You can also watch bite-sized lessons with real-world projects on Laravel Learn, where you will be guided through building a Laravel application from scratch while learning PHP fundamentals.

Agentic Development

Laravel's predictable structure and conventions make it ideal for AI coding agents like Claude Code, Cursor, and GitHub Copilot. Install Laravel Boost to supercharge your AI workflow:

composer require laravel/boost --dev

php artisan boost:install

Boost provides your agent 15+ tools and skills that help agents build Laravel applications while following best practices.

Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the Laravel documentation.

Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the Code of Conduct.

Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via taylor@laravel.com. All security vulnerabilities will be promptly addressed.

License

The Laravel framework is open-sourced software licensed under the MIT license.