NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

Sentinel::fake() vymení manažéra — vo fasáde aj v kontajneri, takže sa podvrhne aj injektovaný SentinelManager — za nahrávací fake, ktorý nepotrebuje kľúče a nezapisuje pečate ani záznamy denníka:

use RoundlyConsulting\Sentinel\Enums\VerificationStatus;
use RoundlyConsulting\Sentinel\Facades\Sentinel;

$fake = Sentinel::fake();

$fake->fakeStatus($invoice, VerificationStatus::Tampered, 'financial', changed: ['a:amount']);
$this->get("/invoices/{$invoice->id}")->assertStatus(409);

Sentinel::assertVerified($invoice);
Sentinel::assertNothingAcknowledged();

$fake->fakeLedgerFindings(new LedgerFinding(LedgerFindingKind::ChainBroken, 3, 17, Invoice::class, 1, 'financial', 'previous digest', 'mysql'));
$this->artisan('sentinel:verify --ledger --allow-empty')->assertExitCode(1);

Produkčná sémantika, ktorú zachováva

  • Definície kompiluje skutočný register: neznáma pečať, model bez pečatí alebo neplatná definícia vyhodí výnimku presne ako v produkcii.
  • Politika zápisu do zmeneného modelu platí aj pre naskriptované stavy: pri refuse vyhodí Eloquent aktualizácia modelu podvrhnutého ako zmenený TamperedModelException.
  • Dôvody, aktéri, politika potvrdenia aj sealing.allow_suspension sa vynucujú s tými istými výnimkami.
  • Idempotencia (aj middleware jobov) a nonce bežia na skutočnom stavovom automate nad úložiskami v pamäti: prehratie, 409, 422, jediné spotrebovanie.
  • sentinel.signed a verify() vrátia syntetický VerifiedSignature (id kľúča fake), pokiaľ ho nenaskriptujete; odchádzajúce sign() požiadavku zaznamená a vráti nepodpísanú.
  • Importy kľúčov sa overia a rozparsujú ako v produkcii; výsledkom sú syntetické KeyInfo a nič sa neuloží.
  • Skeny rešpektujú where a progress a fakeLedgerFindings() riadi verifyLedger() so skutočnou sémantikou LedgerReport, takže sentinel:verify --ledger pri naskriptovanom porušení skončí kódom 1.
  • Zaznamená každé volanie, aj cez HasSeals, handly a pod-prístupy — a nespustí žiadne udalosti.

Ovládanie

Predvolené overenie je Intact. Každé ovládanie vracia fake, takže sa dajú reťaziť, a ovládanie aj asercie sa dajú volať aj staticky na fasáde:

OvládanieÚčinok
fakeStatus(Model $model, VerificationStatus $status, ?string $seal = null, ?array $changed = null, ?string $reason = null)Každé overenie modelu (jednej pečate alebo všetkých) vráti tento stav, kým ho nezmeníte — alebo kým fake pečať znovu nezapečatí či nepotvrdí. Missing má predvolene seal_deleted (ktoré seal() odmietne); pre nikdy nezapečatený riadok nastavte never_sealed.
fakeStatusOnce(...)Len najbližšie overenie.
fakeVerifiedSignature(?VerifiedSignature $signature = null)Čo vráti overenie podpisu.
rejectSignatures(SignatureRejection $reason)Každé overenie podpisu sa odmietne (401).
fakeLedgerFindings(LedgerFinding ...$findings)Každé overenie denníka hlási tieto zistenia, kým metódu nezavoláte znova — bez argumentov pre čistý denník.
recorded(?string $method = null)list<RecordedCall> (method, arguments, result).
use RoundlyConsulting\Sentinel\DataTransferObjects\LedgerFinding;
use RoundlyConsulting\Sentinel\DataTransferObjects\VerifiedSignature;
use RoundlyConsulting\Sentinel\Enums\{Algorithm, LedgerFindingKind, SignatureRejection};

$fake->fakeStatusOnce($invoice, VerificationStatus::Stale, 'financial');          // the next verification only
$fake->fakeVerifiedSignature(new VerifiedSignature('sig1', 'http', 'acme-2026-10', Algorithm::Ed25519, time(), null, 'n-1', null, ['@method'], 'partner', 7));
$fake->rejectSignatures(SignatureRejection::Replayed);                             // sentinel.signed answers 401
$fake->fakeLedgerFindings(new LedgerFinding(LedgerFindingKind::AnchorAhead, 12, null, null, null, null, 'anchor seq 14 > 12', 'mysql'));
$fake->fakeLedgerFindings();                                                       // a clean ledger again

foreach ($fake->recorded('acknowledge') as $call) {
    $call->method;      // 'acknowledge'
    $call->arguments;   // the request DTO, or the list of scalar arguments
    $call->result;      // what the fake returned
}

Asercie

Tridsaťšesť asercií, každá prechádza a zlyháva ako v PHPUnite — neúspešná vyhodí ExpectationFailedException:

OblasťAsercie
PečateassertSealed, assertNotSealed, assertNothingSealed, assertVerified, assertNotVerified, assertNothingVerified, assertAcknowledged, assertNotAcknowledged, assertNothingAcknowledged, assertUnsealed, assertNothingUnsealed, assertSealingSuspended, assertSealingNotSuspended
Hromadné operácie a denníkassertScanned, assertResealed, assertNothingResealed, assertCheckpointed, assertLedgerVerified
KľúčeassertKeyGenerated, assertKeyImported, assertKeyRotated, assertKeyRevoked, assertKeyRetired, assertNoKeyChanges
Idempotencia a nonceassertIdempotentRun, assertNoIdempotentRuns, assertIdempotencyKeyForgotten, assertNonceIssued, assertNoNoncesIssued, assertNonceConsumed, assertNonceNotConsumed, assertSingleUseUrlIssued, assertPruned
PodpisyassertRequestSigned, assertNothingSigned, assertSignatureVerified
$fake = Sentinel::fake();

$invoice->update(['amount' => '12.00']);                           // through the model trait
$fake->assertSealed($invoice, 'financial', fn (SealResult $seal) => $seal->event === SealEvent::Resealed);

Sentinel::idempotency()->run('charge:42', 'billing', fn () => ['ok' => true]);
Sentinel::idempotency()->run('charge:42', 'billing', fn () => ['ok' => true]);
$fake->assertIdempotentRun('charge:42', replayed: true);

Http::fake();
Http::withSignature('acme-2026-10')->post('https://partner.example/events', []);
$fake->assertRequestSigned('acme-2026-10');

Skutočné pečate v testoch

Factory zapečatiteľného modelu potrebuje podpisový kľúč a testovacie prostredie ho zvyčajne nemá — prvé create() vyhodí NoSigningKeyException, ktorej správa odkáže sem. Pridajte do testovacej triedy WithSentinelKeys: pred každým testom dostane každý kruh z konfigurácie bez kľúča nový dočasný kľúč HMAC-SHA-256 (kid test-<ring>, len v pamäti procesu — nič sa nezapíše do .env ani do databázy):

use RoundlyConsulting\Sentinel\Testing\WithSentinelKeys;

uses(TestCase::class, RefreshDatabase::class, WithSentinelKeys::class)->in('Feature');

SentinelTestKeys::install(app(), Algorithm::Ed25519, rings: ['http']) urobí to isté na požiadanie — s iným algoritmom alebo pre databázový kruh (zreťazený za kľúčom z konfigurácie). Kruh, ktorý už nakonfigurovaný kľúč má, ostane nedotknutý.

Úložiská v pamäti

Fake drží idempotenčné kľúče a nonce vo vlastných InMemoryIdempotencyStore / InMemoryNonceStore — jeden na fake, takže medzi testami nič nepresiakne. Ak chcete spustiť skutočného manažéra bez tabuliek, naviažte jedno z nich samostatne:

use RoundlyConsulting\Sentinel\Contracts\IdempotencyStore;
use RoundlyConsulting\Sentinel\Testing\InMemoryIdempotencyStore;

$this->app->instance(IdempotencyStore::class, new InMemoryIdempotencyStore);

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.