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

Každý vstup — fasáda, handle, trait modelu, middleware, validačné pravidlo, makro kolekcie, overenie pri načítaní aj skeny — vedie k tomu istému overovaču a tomu istému verdiktu:

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

$result = Sentinel::for($invoice)->verify();              // the default seal
$result = Sentinel::for($invoice, 'identity')->verify();  // a named seal
$result = Sentinel::verify($invoice, 'financial');        // the same, flat

$result->status;              // VerificationStatus::Intact, ::Tampered, …
$result->reason;              // 'mac', 'seal_deleted', 'newer_version', … (null when intact)
$result->changedAttributes;   // ['a:amount'] — names only, never values
$result->changedColumns();    // ['amount'] (and changedComputed() for c:* fields)
$result->onlyComputedChanged(); // only computed (c:*) values drifted — an explicit seal() re-seals that
$result->toArray();           // status, reason, ids, key, changed names — never values
$result->isIntact();

$invoice->isIntact();                                    // every seal
$invoice->verifySeal('identity');
Sentinel::verifyAll($invoice)->allIntact();              // VerificationReport over every seal
Sentinel::verifyMany($invoices, 'financial')->failures();
Sentinel::for($invoice)->verifyOrFail();                  // TamperedModelException when not intact

Akcia berie VerifyRequest; checkLedger: false pre jedno volanie vynechá porovnanie s denníkom:

use RoundlyConsulting\Sentinel\Actions\Seals\VerifyModelAction;
use RoundlyConsulting\Sentinel\DataTransferObjects\VerifyRequest;

$result = app(VerifyModelAction::class)->execute(new VerifyRequest($invoice, 'financial', checkLedger: false));

Výsledok

VerificationResult nesie status, reason, typ, id a pečať modelu, version a ledgerVersion, ring, keyId, algorithm, sealedAt, changedAttributes, context (VerificationContext) a outdatedIsIntact. isIntact() je true pre Intact, Unsealed a — pri predvolenom verification.outdated_is_intact — aj Outdated; failed() je jeho negácia a toArray() nikdy neobsahuje hodnoty. verifyAll() a verifyMany() vracajú VerificationReport s results, allIntact(), failures(), count(), counts() a throwIfTampered().

Stavy

StavVýznam
IntactPečať zodpovedá uloženým hodnotám aj denníku.
OutdatedNeporušená, ale zapečatená podľa staršej definície (predvolene sa počíta ako neporušená; sentinel:reseal --only-outdated).
UnsealedBenevolentná pečať, ktorá sa nikdy nezapísala.
TamperedHodnoty sa zmenili mimo aplikácie (mac), posunuli sa len vypočítané hodnoty (computed — zápisy a seal() ju znovu zapečatia), hodnoty sa už nedajú kanonizovať (canonicalization) alebo bol sfalšovaný záznam denníka (ledger_entry).
MissingStriktná pečať chýba: seal_deleted (história existuje), never_sealed, unsealed.
StaleObnovila sa staršia pečať: newer_version, not_in_ledger, ledger_mismatch (entity_recreated pri znovu použitom id).
UnknownKey, RevokedKey, RetiredKeyPečatiaci kľúč je neznámy/čakajúci/poškodený, odvolaný alebo vyradený.
AlgorithmNotAllowed, AlgorithmMismatchAlgoritmus kľúča nie je povolený / líši sa od uloženého.
MalformedRiadok pečate je poškodený (neznámy formát, nedekódovateľný manifest, neplatné kódovanie MAC).
UnverifiableV riadku chýba zapečatený stĺpec (missing_attribute), uložená pečať pokrýva vypočítané pole, ktoré definícia už nedeklaruje (missing_computed), alebo overenie riadku pri skene vyhodilo výnimku (error).

Každé zlyhanie spustí TamperDetected (synchrónne) a zaloguje varovanie do verification.log_channel — len názvy, nikdy hodnoty. Overovanie len číta: zámky berie iba v rámci kontroly pred zápisom.

Poradie stavov

Vyhodnocuje sa v poradí a vyhráva prvá zhoda. Stavy 6–11 sa rozhodnú ešte pred výpočtom MAC a riadky 15–18 sa vykonajú pri zapnutom verification.check_ledger (jeden indexovaný dopyt):

#PodmienkaStavDôvod
1Model nie je sealable / pečať nie je deklarovanávyhodí SealingMisconfiguredException—
2Žiadny riadok pečate; hlava denníka je živáMissingseal_deleted
2aŽiadny riadok pečate; hlava denníka je tombstone s neplatným MACTamperedledger_entry
3Žiadny riadok pečate; striktnáMissingunsealed / never_sealed
4Žiadny riadok pečate; benevolentnáUnsealed—
5Neznámy formát, nedekódovateľný manifest, stĺpec manifestu, ktorý nepatrí pečati ani tabuľke, MAC nie je base64url, verzia < 1Malformedpríslušná kontrola
6Uložený kruh nie je kruh pečate ani v acceptRingsUnknownKeyring_not_accepted
7Kľúč nenájdený / čakajúci / zlyhala integrita obálkyUnknownKeynot_found / pending / integrity
8Kľúč odvolanýRevokedKey—
9Kľúč vyradenýRetiredKey—
10Algoritmus kľúča nepovoľuje pečať ani kruhAlgorithmNotAllowed—
11Uložený algoritmus ≠ algoritmus kľúčaAlgorithmMismatch—
12Zapečatený stĺpec chýba v načítaní / vypočítané pole už nie je deklarovanéUnverifiablemissing_attribute / missing_computed
13Aktuálne hodnoty sa nedajú kanonizovaťTamperedcanonicalization
14MAC / podpis neplatný, no MAC atribútov dokazuje posun len vypočítaných hodnôtTamperedcomputed
14aMAC / podpis neplatný inakTamperedmac
15Denník: existuje záznam novší než riadok pečateStalenewer_version
16Denník: žiadny záznam vo verzii riadku pečateStalenot_in_ledger
17Denník: MAC pečate v zázname ≠ MAC riadkuStaleledger_mismatch
18Denník: MAC záznamu neplatný alebo podpísaný kruhom, ktorý pečať neprijímaTamperedledger_entry
19Uložený manifest ≠ aktuálna definíciaOutdated—
20InakIntact—

Zmenené atribúty

S kľúčom HMAC a zapnutými značkami polí (predvolené) ukladá každá pečať kľúčované 128-bitové značky pre každé pole. Pri neplatnom MAC sú zmenenými atribútmi polia, ktorých prepočítaná značka sa líši, plus polia prítomné len na jednej strane. Značky slúžia len na diagnostiku: ich úprava iba zavádza zoznam — pečať aj tak zlyhá. Asymetrické pečate značky neukladajú, preto je changedAttributes null.

Overenie pri načítaní

Pečať deklarovaná s ->verifyOnRetrieve(Reaction::Throw) overí každý načítaný model: Throw zistenie nahlási (TamperDetected a riadok v logu) a vyhodí TamperedModelException; Report nahlási a model nechá načítať. Bez explicitnej reakcie platí verification.retrieve_reaction. Kontrola denníka je pri načítaní vypnutá, pokiaľ nezapnete verification.retrieve_checks_ledger, a čiastočný select() bez vlastných stĺpcov pečate sa preskočí. Sentinel::withoutVerification() overenie pozastaví a Sentinel::model(Invoice::class)->find($id) zámerne načíta zmenený riadok (pozri Potvrdzovanie zmien).

Skeny

Sentinel::model($class)->scan() overí všetky riadky po dávkach vrátane soft-deleted. Closure where (alebo builder daného modelu) zúži sken jedného modelu bez načítania do pamäte — len filtruje, nikdy nemení poradie — a callback progress dostane po každej dávke počet spracovaných riadkov:

$report = Sentinel::model(Invoice::class)->scan('financial', chunk: 500);
$report->scanned;          // rows × seals verified
$report->counts;           // list<StatusCount>
$report->findings;         // up to maxFindings VerificationResult
$report->truncated;
$report->hasFindings();                                                         // any failure
$report->hasFindings(VerificationStatus::Tampered, VerificationStatus::Missing); // only these
$report->count(VerificationStatus::Outdated);

$report = Sentinel::model(Invoice::class)->scan(where: fn ($query) => $query->where('tenant_id', 7));
$report = Sentinel::model(Invoice::class)->scan('financial', where: Invoice::query()->whereYear('created_at', 2026), limit: 10_000);

Všeobecný tvar je Sentinel::scan(new ScanOptions(models: […], seal: null, chunk: 500, checkLedger: true, limit: null, maxFindings: 1000, checkSchema: false, where: null, progress: null)) a sentinel:verify ho obaľuje.

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.