Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Laravel Package

laravel-chronicle/filament

Filament plugin for Laravel Chronicle that surfaces audit logs in your admin panel. Browse, search, filter, and inspect recorded model events and field-level changes, with a dedicated resource for reviewing activity history and debugging data updates.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the panel package alongside the core ledger and register the plugin on a Filament panel:

composer require laravel-chronicle/filament
public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(ChroniclePlugin::make());
}

Look at three things before you let anyone near it:

  1. The registered actions on the ledger resource — verifyEntry, verifySegment, verifyChain, verifyAnchor, verifyAllAnchors, exportLedger, verifyExport, downloadLatestExport, complianceReport, downloadLatestReport, eraseSubject.
  2. The gates behind their ->visible() calls — these are your authorization surface, one per capability.
  3. The entry policy and the resource — this is what enforces the ledger's read-only invariant. It is independent of the button gates and was never affected by the 1.5.0 changes.

First use case: open the resource, run verifyChain over a segment, then exportLedger and pull the artifact via downloadLatestExport. Before that, map each gate to a role in your app so the panel isn't gated on the package defaults.

Upgrading to 1.5.0 is a plain composer update laravel-chronicle/filament. No API or config changes; authorized callers see identical behaviour.

Implementation Patterns

One gate, two enforcement points. 1.5.0 makes every gated action re-check, at execution, the same gate its button visibility already used. That is the pattern to preserve: define a single Gate::define('chronicle-export', ...) (or policy method) and consume it for both ->visible() and the execution-time check. Two separate predicates will drift, and drift is exactly the failure mode this release closes.

Keep verification cheap and scheduled. Layer the verification actions — verifyEntry for a single hash, verifySegment for a range, verifyChain for the full chain, verifyAnchor for one external anchor, verifyAllAnchors for the set. Scheduled full-chain verification plus a dashboard widget is the common shape; the granular actions are for triage when the aggregate check fails.

Treat exports and reports as asynchronous. exportLedger and complianceReport do not return data synchronously — they enqueue work, and downloadLatestExport / downloadLatestReport fetch the artifact later. Drive them from a queued context or accept the two-step UX. Note the pre-1.5.0 exposure here was limited to enqueuing work an unauthorized caller couldn't see, because the export runs through a queued job rather than returning decrypted data to the caller.

Erasure is the one write path. eraseSubject was already enforcing execution-time authorization before this release and is unchanged. Treat it as privileged regardless: it is the only action that mutates anything, and it warrants an approval step and its own audit trail in your application.

Custom actions are your responsibility. If you register your own actions against the resource, 1.5.0 does not cover them. Give each one an execution-time gate check, and write a denial test for it — the structural tripwire in ExecutionTimeGuardTest pins the package's action set, not yours.

Mirror the enforcement test for your own code. The package's ExecutionTimeGuardTest is a good template: reach the real handler while bypassing the visibility guard exactly as a crafted request would, force the gate off, and assert (a) a denial notification was sent and (b) no work happened — nothing verified or recorded, no job dispatched, no report written, no proof entry appended. In your own tests that means Notification::fake(), Queue::assertNothingPushed(), Storage::assertMissing(), and a ledger entry count that did not move.

Copy the tripwire idea. Pin the exact set of actions you expect to be gated in a test. When someone adds an action and forgets the denial check, the test fails at the right moment instead of after the fact.

Scope gates per tenant. Where the panel is multi-tenant, the gate should resolve through a policy that scopes to the current tenant, so a crafted invocation referencing another tenant's entry fails at execution rather than relying on the record not being listed.

Gotchas and Tips

  • ->visible() is not authorization. It controls whether a button renders; it does not stop a crafted request that invokes the handler directly. This is the entire substance of 1.5.0. Never treat a hidden button as a security boundary.
  • Calibrate urgency correctly. This is defense-in-depth hardening, not a fix for an exposed breach. Nothing here could mutate, delete, or reorder a ledger entry; the read-only invariant held throughout via the entry policy and resource. The realistic pre-fix exposure was triggering a verification or enqueuing an export/report the caller's UI wouldn't have shown them, with no decrypted data returned synchronously. Update for the hardening; don't page anyone.
  • Denial notifications are visible. Denied actions send a notification. Check the channel configuration and copy, and expect extra noise in test output and in logs where users legitimately poke at actions they can't use.
  • A legit user being denied means the two checks disagree. The fix made execution use the same gate as visibility, so a mismatch now points at the gate itself evaluating differently in the action request than at render — a predicate that reads request state, tenant context, session, or a model that changed in between. Debug the gate, not the action.
  • Livewire requests are a fresh request. The handler invocation re-evaluates authorization in a new request cycle with its own auth context. If your gate depends on anything assembled at render time, it won't be there.
  • Queued exports run as the worker. A gate checked only inside the job runs as the worker identity, not the requester. Authorize at the action boundary — which is what 1.5.0 does — not solely inside the job.
  • Download actions are gated too. downloadLatestExport and downloadLatestReport are in the gated set. Don't lean on unguessable storage URLs as your access control; keep the gate and the disk permissions aligned.
  • The tripwire failure is intentional. If a test fails telling you to add an execution-time denial test, that's the design working. Add the test — don't relax the assertion.
  • Overriding an action moves the obligation to you. If you subclass the resource or swap an action implementation, the packaged execution-time re-check no longer necessarily applies. Keep the gate call in whatever replaces it.
  • Forcing the gate off in tests is easiest via a Gate::define(..., fn () => false) override or a Gate::before returning false; assert denial and absence of side effects, since a passing notification assertion alone doesn't prove nothing happened.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin