trypost/tests/TestCase.php
Paulo Castellano c3b8af7189 refactor: collapse media-attach helpers back into MediaAttacher
The previous split (MediaAttacher + MediaDownloader + UrlSafetyGuard
interface + DnsUrlSafetyGuard impl + provider binding) was over-engineered
for one production implementation. Roll it all back into a single
MediaAttacher class and delegate to the existing `Workspace::addMediaFromPath`
helper for storage + Media row creation (the same path the web upload
flow uses).

What's gone:
- app/Services/Post/MediaDownloader.php
- app/Services/Post/UrlSafetyGuard.php (interface)
- app/Services/Post/DnsUrlSafetyGuard.php (impl)
- tests/Unit/Services/Post/DnsUrlSafetyGuardTest.php
- The provider bind in AppServiceProvider

What's still defended:
- Streaming download via Http::sink with a Guzzle progress callback that
  aborts mid-stream once MAX_BYTES is exceeded (no body buffered in PHP).
- Redirects disabled so a 200→302 trick can't pivot to internal hosts.
- IP-literal SSRF guard: rejects loopback / private / link-local /
  reserved ranges via FILTER_FLAG_NO_PRIV_RANGE | NO_RES_RANGE. DNS
  hostnames are accepted — finer SSRF (DNS rebinding etc.) is left to
  network-level egress controls. This is a deliberate simplification:
  the prior DNS resolution defense added a class + interface + provider
  binding for marginal gain when the realistic attack surface is
  hard-coded internal IPs.
- Strict MIME allowlist (no SVG, no PDF, no application/*).
- Lock-then-merge into post.media[] to avoid lost-update races.

Tests bypass the SSRF check via the static `MediaAttacher::fakeUrlSafety()`
called once in tests/TestCase::setUp — same idiom as Mail::fake / Bus::fake.
2026-05-04 14:02:50 -03:00

31 lines
646 B
PHP

<?php
declare(strict_types=1);
namespace Tests;
use App\Services\Post\MediaAttacher;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
/**
* Indicates whether the default seeder should run before each test.
*
* @var bool
*/
protected $seed = true;
protected function setUp(): void
{
parent::setUp();
$this->withoutVite();
// Bypass the SSRF check during tests so Http::fake() with
// synthetic hosts like cdn.example.com isn't rejected.
MediaAttacher::fakeUrlSafety();
}
}