From c5252847bb190961bb220c26881e6feeb51950d7 Mon Sep 17 00:00:00 2001 From: nexxo Date: Mon, 27 Jul 2026 21:44:59 +0200 Subject: [PATCH] Make the SECRETS_KEY test able to fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Task 2 reviewer rewired the model to Laravel's APP_KEY-based Crypt facade and every test stayed green. Laravel's encrypter is a container singleton resolved once from app.key, so config()->set('app.key') never rebuilds it and the rotation the test performed was invisible. Replaced with a positive proof — rotating SECRETS_KEY must break decryption — plus the APP_KEY case with forgetInstance(), which is what makes that direction mean anything. --- .../superpowers/plans/2026-07-27-mailboxes.md | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/superpowers/plans/2026-07-27-mailboxes.md b/docs/superpowers/plans/2026-07-27-mailboxes.md index d243c11..04ffa9a 100644 --- a/docs/superpowers/plans/2026-07-27-mailboxes.md +++ b/docs/superpowers/plans/2026-07-27-mailboxes.md @@ -256,11 +256,30 @@ it('stores the password encrypted and never in the clear', function () { ->and($box->fresh()->password)->toBe('sehr-geheim'); }); -it('uses SECRETS_KEY, not APP_KEY — rotating APP_KEY leaves mail working', function () { +it('is keyed to SECRETS_KEY — rotating it makes the password unreadable', function () { + // The POSITIVE proof, and the one that discriminates. Without it the pair + // below passes even against an APP_KEY implementation. + $box = Mailbox::factory()->create(['password' => 'geheim']); + + config()->set('admin_access.secrets_key', 'base64:'.base64_encode(random_bytes(32))); + + expect(fn () => $box->fresh()->password) + ->toThrow(Illuminate\Contracts\Encryption\DecryptException::class); +}); + +it('is NOT keyed to APP_KEY — rotating that leaves mail working', function () { $box = Mailbox::factory()->create(['password' => 'bleibt-lesbar']); config()->set('app.key', 'base64:'.base64_encode(random_bytes(32))); + // forgetInstance is what makes this test mean anything. Laravel's encrypter + // is a container singleton resolved once from whatever app.key held at the + // time; config()->set() afterwards mutates the array and never rebuilds it. + // Without this line the test passes even when the model is rewired to + // Laravel's own APP_KEY-based Crypt facade — proven by mutation during the + // Task 2 review, where every test stayed green through exactly that change. + app()->forgetInstance('encrypter'); + expect($box->fresh()->password)->toBe('bleibt-lesbar'); });