Make source() respect strict entries like get() does

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feature/betriebsmodus
nexxo 2026-07-30 11:21:07 +02:00
parent ecf948f30f
commit 727f2e41db
3 changed files with 41 additions and 7 deletions

View File

@ -169,6 +169,7 @@ final class SecretVault
return match (true) {
$this->row($key, $mode) !== null => 'stored',
$this->isStrict($key) => 'none',
filled(config(self::REGISTRY[$key]['config'])) => 'environment',
default => 'none',
};

View File

@ -29,17 +29,37 @@ beforeEach(function () {
it('prefers a stored key over the environment, and says which is in force', function () {
$vault = app(SecretVault::class);
expect($vault->get('stripe.secret'))->toBe('sk_env_fallback')
->and($vault->source('stripe.secret'))->toBe('environment');
// This test uses dns.token (not stripe.secret) to preserve the original
// assertion: a non-strict entry falls back to the environment and reports
// it as its source. Stripe is exempt from fallback (it is strict),
// tested separately in StripeStrictModeTest.
config()->set('provisioning.dns.token', 'env_token_fallback');
$vault->put('stripe.secret', 'sk_live_stored_value', Operator::factory()->create());
expect($vault->get('dns.token'))->toBe('env_token_fallback')
->and($vault->source('dns.token'))->toBe('environment');
expect($vault->get('stripe.secret'))->toBe('sk_live_stored_value')
->and($vault->source('stripe.secret'))->toBe('stored');
$vault->put('dns.token', 'stored_value', Operator::factory()->create());
expect($vault->get('dns.token'))->toBe('stored_value')
->and($vault->source('dns.token'))->toBe('stored');
// Removing it falls back rather than leaving nothing.
$vault->forget('stripe.secret');
expect($vault->get('stripe.secret'))->toBe('sk_env_fallback');
$vault->forget('dns.token');
expect($vault->get('dns.token'))->toBe('env_token_fallback');
});
it('strips the environment from stripe when nothing is stored', function () {
// Stripe is a strict entry: it never falls back to the environment, and
// source() never reports it as in force when it is not stored. This
// prevents the silent contradiction: get() returns null while source()
// claims 'environment', and the console would tell the operator a key is
// in force while the billing system refuses to use it.
$vault = app(SecretVault::class);
config()->set('services.stripe.secret', 'sk_env_from_config');
expect($vault->get('stripe.secret'))->toBeNull()
->and($vault->source('stripe.secret'))->toBe('none');
});
it('stores the value encrypted, and never in the clear', function () {

View File

@ -54,3 +54,16 @@ it('lets every other entry keep falling back', function () {
expect($this->vault->get('dns.token'))->toBe('live-token');
});
it('does not report the environment as the source of a strict key', function () {
// source() muss dieselbe Regel anwenden wie get(): ist der Eintrag strikt
// und der Platz des aktiven Modus leer, ist die Quelle 'none', nicht
// 'environment'. Sonst meldet die Konsole dem Betreiber einen Stripe-
// Schlüssel als „in Kraft" (source sagt 'environment'), während die
// Kasse ihn nicht benutzt (get gibt null zurück). Dieser stille Widerspruch
// ist genau die Art, gegen die dieses Vorhaben gebaut ist.
config()->set('services.stripe.secret', 'sk_live_from_env');
OperatingMode::set(OperatingMode::Test);
expect($this->vault->source('stripe.secret'))->toBe('none');
});