rennf93/laravel-guard
Laravel Guard is a lightweight package for adding configurable guard-based access control to Laravel apps. It integrates with Laravel’s authentication system, making it easy to define guards, manage providers, and protect routes with simple configuration.
Architecture fit. This is a Laravel/Symfony-HTTP-kernel middleware adapter over a separately versioned security engine (rennf93/guard-core-php). v1.6.0 is the first release that makes that layering visible to consumers: the adapter's composer.json floor moves to ^4.4.0, and the release notes explicitly state that a large share of behavior change "comes from the engine, not from this adapter." Architecturally that is fine — a thin adapter with a pinned engine is a reasonable split — but it means the adapter's semver is not the blast radius. A ^1.x constraint on this package can pull engine behavior changes into a production app on a patch/minor bump of the adapter. Treat the engine version, not the adapter version, as the thing to pin and review.
Integration feasibility. Integration remains a standard Laravel middleware registration (handle() → downstream → finish()), with configuration in SecurityConfig. Two feasibility points changed materially:
finish() and handle() were typed to Illuminate\Http\Response, so any route returning response()->json(...), a redirect, or a streamed response threw a TypeError on the pass-through path. That is not a cosmetic bug — it means essentially any nontrivial Laravel API could not run behind this middleware. Anyone who evaluated and rejected the package earlier for this reason should re-evaluate. It also implies the package had limited real-world exposure on JSON APIs before now, which is a maturity signal to weigh.enableDynamicRules and enableEnrichment without enableAgent: true no longer validate and the engine throws when built. This converts a previously silent no-op into a boot-time exception. That's better hygiene, but it is a deploy-time hard failure for any existing config that set those flags optimistically.Technical risk.
X-Forwarded-For, stops trusting a mapped peer inside an IPv4 CIDR of trustedProxies, and canonicalizes list entries at match time. Combined with the IP precedence change (whitelist decides alone; blacklist applies only when no whitelist is configured; route lists shadow global lists), this can widen and narrow allow/deny surfaces simultaneously. A ban, rate limit, or list entry may now match a client it did not match before — and, symmetrically, may stop matching. This must be validated against real proxy topology before rollout, not after.ip_blacklist dynamic rule is now a timed ban for ipBanDuration seconds rather than a merge into the static list. Any workflow relying on dynamic rules to accumulate state is now behaviorally wrong, silently. This is the single most likely source of "security policy stopped working" incidents.detectionMaxScanSeconds budget (default 10.0, range 0.1–60.0) caps regex scan CPU, which is a good DoS mitigation, but it introduces a weighted pattern_timeout threat — a request can now be flagged that previously scanned clean to the end. If threat weights feed block decisions, this is a new false-positive vector; if they feed dashboards, alert rules need updating.suggest, not a dependency. The agent wiring is now documented and listed under suggest, but dynamic rules and enrichment require an agent handler to validate. The dependency relationship is real while the declaration is advisory. This is a packaging wart that will produce confusing runtime failures for teams who read suggest.d as "optional."Key questions.
TypeError fix present in any v1.5.x patch, or is v1.6.0 the only path to a working JSON API integration? This determines whether the engine-floor bump is optional or forced.symfony/http-foundation bounds?pattern_timeout contribute to block decisions by default, and at what weight?guard-core-php separately? The adapter's health is now coupled to a second package's release discipline.rennf93/guard-agent-php production-grade, and what happens at runtime if enableAgent: true is set but the suggest package is absent?Stack fit. Standard Laravel HTTP kernel middleware; no queue, no service provider boot gymnastics implied, no DB migration. It sits in the request path for every non-excluded route, so it is a latency-sensitive, synchronous dependency. The widened return types to Symfony\Component\HttpFoundation\Response mean it now composes correctly with the full range of Laravel responses (JSON, redirect, streamed), which is the baseline expectation for middleware in a modern Laravel API. Fit is good; the block path still returns Illuminate\Http\Response from the translator, so block responses are HTML/content bodies rather than the app's negotiated format — worth confirming that's acceptable for an API-only service.
Migration path. Treat this as a two-part upgrade, not a patch:
rennf93/guard-core-php constraint at 4.4.x in the root composer.json so the transitive floor cannot drift on a future adapter patch. This is the single highest-value action in the whole upgrade.SecurityConfig for the agent triad (enableDynamicRules, enableEnrichment, enableAgent). Fix before deploying, or the engine throws at construction.Compatibility. The response-type fix is backwards compatible for callers receiving blocks (narrower Illuminate\Http\Response is a subtype) and strictly additive elsewhere. No adapter API or config keys are removed or renamed. The breaking surface is entirely behavioral and inherited from the engine — which is precisely why a composer outdated review will not surface it.
Sequencing. Recommended order: (a) pin engine + audit config in a branch; (b) run the full test suite plus your own contract tests for every response type your app returns; (c) shadow-deploy to staging with production-like proxy headers and diff security decisions for 24–72h; (d) update observability (log parsers, threat-weight dashboards) and deploy together; (e) canary in production with a fast rollback that includes the engine pin, not just the adapter version.
Maintenance. Ownership cost goes up modestly: you now track two release streams. The adapter's release notes are effectively a changelog for the engine, which is helpful but also a signal that you should watch guard-core-php releases directly rather than waiting for the adapter to re-narrate them. Expect ongoing config-schema churn — the agent-requires-flag validation is the second config-semantics change implied by "follows the reference," and "follows the reference" is a phrase that will recur. Budget a recurring review of SecurityConfig against engine reference behavior each minor bump.
Support. The suggest-not-require declaration for the agent package is an operational tax: failures will manifest as engine-construction exceptions rather than missing-dependency errors, which lengthens triage. Document the agent as a hard prerequisite for dynamic rules in your runbook, and have the team own that mapping since the package metadata does not enforce it.
Scaling. The new detectionMaxScanSeconds budget is a net positive for tail latency under adversarial traffic — it bounds regex CPU per request, which is the classic ReDoS-in-middleware failure mode. Default of 10.0s is generous for a request-path scan; teams with tight p99 SLOs should lower it and validate the resulting pattern_timeout rate. Note the budget converts CPU exhaustion into a detection event, so under sustained attack you will generate threat volume proportional to the attack, which has its own logging and alerting cost. Middleware also runs on every request, so capacity planning should treat it as additive per-request CPU on the hot path.
Failure modes. Ranked by operational pain:
enableAgent: true — loud, fast, easy to catch in CI if you build the engine in a test.pattern_timeout threats on expensive-but-legitimate requests. Mitigation: baseline timeout rate in staging before enabling any block action on it.Ramp-up. Low for a PHP/Laravel team: one middleware registration, one config object, standard response lifecycle. The learning cost is concentrated in the security semantics rather than the code — IP trust and precedence, dynamic rule lifecycle, threat weighting, and what each SecurityConfig flag actually gates. A competent Laravel developer is productive in under a day; the security engineer who owns policy needs noticeably longer, and should own the staging diff exercise. Verification claims are strong (168/168 checks, 100% line coverage, composer validate --strict and composer audit clean) but are the maintainer's own gates on PHP 8.5.11 with a private Redis — they demonstrate release hygiene, not that your proxy topology and your rule set behave the same way. Allocate real time to the staging diff; that is where the actual risk in this release lives.
How can I help you explore Laravel packages today?