Cut over-engineering found by a repo-wide audit
docker / test (8.5) (push) Successful in 3m10s
linter / quality (push) Successful in 1m5s
tests / ci (8.5) (push) Successful in 3m9s
docker / build-and-push (push) Successful in 21m5s
docker / release (push) Skipped

- Config: auth, services, logging, queue and database only repeated the
  framework's own files and are gone; the others keep only the keys that
  differ (app version, cache serializable_classes, session cookie name,
  Markdown mail theme, the shares disk, three Octane values, Livewire's
  pagination theme and payload guards).
- Email verification is removed: User never implemented MustVerifyEmail,
  so it was never enforced, and SealShare has a single admin and no
  registration. CreateNewUser goes with it.
- FileEncryptionService::encryptFile() and generateSalt() were only used
  by tests; tests build files with encryptTestFile() in tests/Pest.php.
- The expiration options are defined once, as Share::EXPIRATIONS. "30 Days"
  now lasts 30 days instead of a calendar month, and Admin settings only
  save a default expiration that is one of the options.
- One-caller helpers are inlined, the uploader reads chunk responses with
  XHR's responseType, and starter-kit leftovers are removed.
- Docker: PHP reads the PHP_* limits from the environment itself
  (${VAR:-default} in uploads.ini); both entrypoints stop writing the ini.
  docker-compose.yml shares the app and scheduler variables through one
  anchor. The dev image installs gd for the screenshot publisher and fake
  test images.
- Development runs in Docker only: the composer dev script, concurrently,
  laravel/pail, laravel/sail, autoprefixer and the shell-quote override
  are gone.
- phpunit.xml forces the test environment with <server> entries, so tests
  run in the dev container no longer use its real database.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
surtic86
2026-09-18 23:14:33 +02:00
co-authored by Claude Opus 5
parent a62edbcefb
commit 4530298398
57 changed files with 240 additions and 2784 deletions
+17
View File
@@ -51,6 +51,23 @@ test('admin can save settings', function () {
expect(Setting::get('default_expiration'))->toBe('7d');
});
test('the default expiration only accepts the offered options', function () {
$admin = User::query()->where('is_admin', true)->first();
$component = Livewire::actingAs($admin)
->test(AdminSettings::class)
->set('defaultExpiration', '99y')
->call('saveSettings')
->assertHasErrors(['defaultExpiration' => 'in']);
expect(Setting::get('default_expiration'))->toBeNull();
$component
->set('defaultExpiration', '')
->call('saveSettings')
->assertHasNoErrors();
});
test('admin can set system password', function () {
$admin = User::query()->where('is_admin', true)->first();
Livewire::actingAs($admin)
@@ -1,67 +0,0 @@
<?php
use App\Models\User;
use Illuminate\Auth\Events\Verified;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\URL;
test('email verification screen can be rendered', function () {
$user = User::factory()->unverified()->create();
$response = $this->actingAs($user)->get(route('verification.notice'));
$response->assertOk();
});
test('email can be verified', function () {
$user = User::factory()->unverified()->create();
Event::fake();
$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1($user->email)]
);
$response = $this->actingAs($user)->get($verificationUrl);
Event::assertDispatched(Verified::class);
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
$response->assertRedirect(route('admin.dashboard', absolute: false).'?verified=1');
});
test('email is not verified with invalid hash', function () {
$user = User::factory()->unverified()->create();
$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1('wrong-email')]
);
$this->actingAs($user)->get($verificationUrl);
expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
});
test('already verified user visiting verification link is redirected without firing event again', function () {
$user = User::factory()->create([
'email_verified_at' => now(),
]);
Event::fake();
$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1($user->email)]
);
$this->actingAs($user)->get($verificationUrl)
->assertRedirect(route('admin.dashboard', absolute: false).'?verified=1');
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
Event::assertNotDispatched(Verified::class);
});
+15
View File
@@ -249,6 +249,21 @@ test('file upload with expiration sets expires_at', function () {
expect($share->expires_at)->not->toBeNull();
});
test('a 30 day expiration lasts 30 days, not a calendar month', function () {
Storage::fake('shares');
$this->travelTo(new DateTimeImmutable('2026-02-01 12:00:00'));
$component = Livewire::test(FileUploader::class);
uploadThroughPage($component, ['file.txt' => 'content']);
$component
->set('expiration', '30d')
->call('createShare')
->assertRedirectContains('/share/');
expect(Share::query()->first()->expires_at->toDateTimeString())->toBe('2026-03-03 12:00:00');
});
test('file upload with max downloads sets limit', function () {
Storage::fake('shares');
-1
View File
@@ -41,7 +41,6 @@ test('every page is one page template, one h1 and the same width', function (Clo
return $test->get(route('system-password'));
}],
'verify email' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->unverified()->create())->get(route('verification.notice'))],
'confirm password' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->create())->get(route('password.confirm'))],
'profile' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->create())->get(route('profile.edit'))],
'password' => [fn (TestCase $test): TestResponse => $test->actingAs(User::factory()->create())->get(route('user-password.edit'))],
+2 -3
View File
@@ -27,10 +27,9 @@ test('profile information can be updated', function () {
expect($user->name)->toEqual('Test User');
expect($user->email)->toEqual('test@example.com');
expect($user->email_verified_at)->toBeNull();
});
test('email verification status is unchanged when email address is unchanged', function () {
test('the profile saves with its own unchanged email address', function () {
$user = User::factory()->create();
$this->actingAs($user);
@@ -42,7 +41,7 @@ test('email verification status is unchanged when email address is unchanged', f
$response->assertHasNoErrors();
expect($user->refresh()->email_verified_at)->not->toBeNull();
expect($user->refresh()->name)->toEqual('Test User');
});
test('user can delete their account', function () {
+1 -2
View File
@@ -3,7 +3,6 @@
use App\Livewire\ShareDownload;
use App\Models\Share;
use App\Models\ShareFile;
use App\Services\FileEncryptionService;
use App\Services\ShareService;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
@@ -280,7 +279,7 @@ test('a password share created before key wrapping still unlocks and downloads',
$source = tempnam(sys_get_temp_dir(), 'old');
file_put_contents($source, 'old content');
Storage::disk('shares')->makeDirectory($share->token);
app(FileEncryptionService::class)->encryptFile($source, Storage::disk('shares')->path($share->token.'/old.enc'), bin2hex(hash_pbkdf2('sha256', 'old-password', hex2bin($salt), 100000, 32, true)), 1024);
encryptTestFile($source, Storage::disk('shares')->path($share->token.'/old.enc'), bin2hex(hash_pbkdf2('sha256', 'old-password', hex2bin($salt), 100000, 32, true)), 1024);
unlink($source);
Livewire::test(ShareDownload::class, ['share' => $share])