Skip to content

Add request-aware runtime configuration hooks#425

Merged
binaryfire merged 10 commits into
0.4from
feature/request-aware-resolvers
Jul 7, 2026
Merged

Add request-aware runtime configuration hooks#425
binaryfire merged 10 commits into
0.4from
feature/request-aware-resolvers

Conversation

@binaryfire

@binaryfire binaryfire commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Context

Laravel applications can often get away with changing configuration or singleton state while a request is running. A request has a short lifecycle, and that makes mutation a convenient extension point for things like trusted hosts, stateful domains, URL origins, or package-specific runtime options.

Hypervel has a different constraint. The worker outlives the request, and multiple requests can be active in the same worker at the same time. Mutating global configuration or shared singleton state during a request is therefore not just a style issue; it can leak behavior into unrelated requests.

This PR moves several of those extension points to request-aware APIs. The goal is to preserve the ergonomics of configuring request-derived behavior while making the storage model explicit and safe for Hypervel's runtime.

What changed

Sanctum

Sanctum's stateful-domain handling now supports a callback-based resolver. This replaces the previous subclass/override shape with an explicit API that can be registered from a service provider.

The resolver is evaluated at request time and takes precedence over the static sanctum.stateful configuration. Static configuration remains the default behavior when no resolver is registered.

URL generation

Asset origin overrides are now scoped to the current request/coroutine instead of being stored as worker-shared URL generator state.

This keeps URL::useAssetOrigin() useful for request-specific asset hosts without allowing one request's asset origin to bleed into another request. The existing public signature stays the same.

The URL generator also no longer exposes a request-state flush helper. Request context is already destroyed centrally by the test/runtime context cleanup path, so a bespoke URL-only flush method added unnecessary API surface.

Trusted hosts

TrustHosts now supports a request-aware resolver for trusted host patterns.

This gives applications a way to decide accepted hosts from the current request without mutating global middleware configuration. The resolver accepts multiple host patterns. If it resolves to an empty set, the middleware fails closed rather than silently trusting everything.

TrustProxies is intentionally unchanged. Proxy trust is infrastructure-level configuration and should remain fixed for the process.

Passkeys

The custom WebAuthn resolver APIs were renamed to match the framework's resolve...Using(...) convention.

This is mostly an API consistency change, but it matters because these callbacks are part of the same request-aware configuration surface. Callers and docs were updated together.

Wayfinder

Hypervel Wayfinder no longer pretends to support Laravel's global forced-root generation behavior.

Laravel can read URL::forceRootUrl() from a globally-mutated URL generator during code generation. Hypervel's equivalent runtime API is URL::useOrigin(), which is request-scoped by design. Reading that from a build-time command would be the wrong model.

Wayfinder now keeps the behavior that fits Hypervel:

  • generated URLs are relative by default;
  • the path portion of app.url is still preserved for subdirectory deployments;
  • explicit route domains are still emitted;
  • forced schemes for explicit domain routes are retained through a URL generator getter rather than private-property reflection.

The intentional Laravel difference is documented in the Wayfinder README.

Supporting cleanup

This branch also includes a small amount of supporting cleanup that came out of the same audit:

  • Telescope entry factory sequencing now lets the factory assign sequence values directly.
  • Old 0.3 docs were moved under the archive area so the active docs location is unambiguous.
  • The contributor guidance now records a few Hypervel conventions that came up during the work.

Why this shape

The common pattern in this PR is: static configuration remains static, request-specific behavior moves behind an explicit resolver or coroutine-scoped value.

That keeps the Laravel-style configuration model where it is safe, and avoids carrying over the parts that depend on a per-request PHP process lifecycle.

This also makes the distinction visible in code. A callback named resolve...Using(...) or a method documented as request-scoped communicates a very different contract than changing config() or a singleton property mid-request.

Compatibility

Defaults are unchanged unless an application opts into one of the new resolver hooks.

The main intentional behavior difference is Wayfinder forced-root generation. That behavior was already inert in Hypervel after URL origins became request-scoped. This PR removes the dead plumbing and documents the Hypervel behavior instead of adding a new build-time root configuration surface.

Validation

This branch was reviewed with Claude during development and the final Wayfinder cleanup was signed off after review.

Checks run across the branch included:

  • composer fix
  • composer test:parallel
  • composer test tests/Wayfinder
  • composer lint
  • composer analyse
  • pnpm test
  • targeted integration tests for Sanctum, routing URL generation, TrustHosts, Passkeys, Telescope, and Wayfinder

Summary by CodeRabbit

  • New Features

    • Added per-request resolution for trusted hosts, stateful domains, and passkey-related origins/IDs.
    • Improved asset URL handling with separate origin support and better HTTPS generation options.
  • Bug Fixes

    • Strengthened host validation so requests fail closed when trusted host settings can’t be resolved.
    • Made URL and routing overrides apply only where intended, improving consistency across requests and coroutines.
  • Documentation

    • Expanded guidance for dynamic host, Sanctum, URL origin, and passkey configuration.
    • Clarified framework behavior and updated several setup examples and notes.

Add concise agent guidance for three recurring Hypervel conventions.\n\nRecord src/boost/docs as the documentation location, prefer jsonb() for JSON columns so PostgreSQL receives jsonb while other supported databases compile to compatible storage, and require optional framework events to be guarded with hasListeners() so hot paths skip event construction and dispatch when nobody is listening.
Replace Hypervel's custom Sanctum statefulDomains() override point with a boot-time resolveStatefulDomainsUsing() callback that receives the current request. This mirrors the request-aware resolver pattern used by CORS while keeping the resolver itself worker-lifetime static state.

The middleware now resolves stateful domains through the callback when one is registered, falls back to sanctum.stateful_domains otherwise, and normalizes the result to non-empty strings. The old subclass fixture test was replaced with coverage for callback precedence, request injection, and flushState() clearing back to config behavior.

Register the new Sanctum middleware flushState() with the global PHPUnit after-each cleanup subscriber so resolver state cannot leak between tests. Also clarify Testbench Foundation Application's flushState() comment to make clear it is not the global framework static-state cleanup list.

Update the Sanctum docs to show registering the resolver from a service provider instead of replacing the middleware class, with wording that presents per-tenant/per-host rules only as examples of application-specific request-derived domains.

Verified with: composer test -- tests/Sanctum/EnsureFrontendRequestsAreStatefulTest.php; composer test -- tests/Sanctum; composer test -- tests/Testbench/Foundation/ApplicationTest.php tests/Testbench/CreatesApplicationTest.php tests/Testbench/TestCaseTest.php tests/Testbench/Foundation/Bootstrap/CreateVendorSymlinkTest.php; composer analyse; composer lint.
Drop UrlGenerator::flushRequestState() now that URL-owned coroutine context is cleaned by the coroutine lifecycle and the test subscriber's global CoroutineContext::flush() call.

UrlGenerator::flushState() now only clears the class's macro state. This keeps static-state cleanup focused on actual class-level state instead of duplicating broader context cleanup.

The URL facade docblock no longer advertises flushRequestState(), and the routing static-state coverage now treats UrlGenerator like the other Macroable routing classes instead of asserting request-context cleanup through flushState().

Verification: composer fix reached the parallel test suite after passing formatting and static analysis, but hit a Telescope prune sequence collision. A clean follow-up composer test:parallel run passed: 21435 tests, 60722 assertions, 643 skipped.
Remove the EntryModel factory's random sequence default so tests use the database-assigned bigIncrements value from the telescope_entries schema.

The previous random_int(1, 10000) assignment manually populated a unique auto-increment column and could collide whenever a test created multiple Telescope entries. That was the source of the intermittent PruneCommandTest unique constraint failure.

Refresh the entry model in RouteTest before asserting its sequence because EntryModel uses uuid as a non-incrementing primary key, so Eloquent does not hydrate the database-assigned sequence onto the model after create().

Verification: ./vendor/bin/phpunit tests/Telescope/Http/RouteTest.php; composer test:parallel.
Store URL::useAssetOrigin() overrides in coroutine context instead of mutating the singleton URL generator's configured asset root.

This keeps ASSET_URL / app.asset_url as the app-wide asset origin while allowing request-specific asset origins without leaking across concurrent Swoole requests or later requests handled by the same worker.

Update asset URL generation to prefer the request-scoped forced asset root, then the configured asset root, then the current request root. Passing null to useAssetOrigin() now clears only the request-scoped override and falls back to the configured/default origin.

Document the split between app-wide ASSET_URL configuration and per-request URL::useAssetOrigin() overrides, and add coroutine isolation coverage for both asset origins and normal URL origins.

Reviewed-by: Claude via Codesonic.

Verification: ./vendor/bin/phpunit tests/Routing/RoutingUrlGeneratorTest.php; composer test:parallel.
Rename the Hypervel-owned passkey relying party ID and allowed origins callbacks to resolveRelyingPartyIdUsing and resolveAllowedOriginsUsing so they match the framework convention for config-derived resolver hooks.

Update the internal callback property names, all Passkeys and Fortify tests, and the Boost Fortify documentation examples and worker-state list to use the new API names.

Document the naming rule in AGENTS.md, including the intentional redirectUsing exception for Laravel-established redirect hook conventions.

Validated with focused Passkeys/Fortify tests and composer fix, including PHP CS Fixer, PHPStan, the full parallel suite, package checks, and dogfood testbench tests. Reviewed and signed off by Claude.
Add TrustHosts::resolveHostsUsing() so applications can resolve trusted host patterns from the current request during middleware execution while preserving the existing hosts(): array override point and TrustHosts::at() boot configuration API.

Normalize empty trusted host pattern lists to a named never-matching sentinel so enabled TrustHosts fails closed instead of disabling validation. This covers both the new resolver path and existing dynamic at() callbacks that resolve to no hosts.

Document the resolver contract in the requests docs: the resolver is the complete authority for the request, must return every trusted pattern, and returning an empty array rejects the request. Also record the fail-closed behavior as a Laravel difference in the HTTP package README.

Add integration coverage for verified request-aware host patterns, unrecognized host rejection, empty legacy closures failing closed, missing app.url configuration failing closed, and resolver cleanup through flushState.

Validated with focused TrustHosts tests and composer fix, including PHP CS Fixer, PHPStan, the full parallel suite, package checks, and dogfood testbench tests. Reviewed and signed off by Claude.
Remove the dead forced-root state left behind after Hypervel moved URL origin overrides to request-scoped URL::useOrigin() context. Wayfinder now intentionally preserves app.url base paths and explicit route domains, but no longer pretends to support Laravel's global forced-root generation behavior.

Replace Wayfinder's reflection of UrlGenerator internals with a getForcedScheme() accessor so the remaining forced-scheme behavior for explicit domain routes stays supported without private-property reflection. Document forceScheme() and forceHttps() as boot-only because they mutate worker-shared URL generator state.

Record the intentional Laravel difference in the Wayfinder README and add an end-to-end generation test proving forced HTTPS still applies to explicit domain routes.

Verified with: pnpm test src/wayfinder/tests/AppUrlRootResolution.test.ts; pnpm test; composer test tests/Wayfinder; composer lint; composer analyse.
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@binaryfire, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 20 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8768cda4-1992-4cd8-b7cb-4e61c4a395e7

📥 Commits

Reviewing files that changed from the base of the PR and between ff42cac and 76c8368.

📒 Files selected for processing (5)
  • src/boost/docs/requests.md
  • src/http/src/Middleware/TrustHosts.php
  • src/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php
  • tests/Integration/Http/Middleware/TrustHostsTest.php
  • tests/Sanctum/EnsureFrontendRequestsAreStatefulTest.php
📝 Walkthrough

Walkthrough

This PR introduces request-aware and boot-time resolver callback APIs across TrustHosts, Passkeys, and Sanctum middleware (e.g., resolveHostsUsing, resolveRelyingPartyIdUsing, resolveAllowedOriginsUsing, resolveStatefulDomainsUsing), migrates UrlGenerator's forced root/asset origin overrides to coroutine context, removes forcedRoot support from Wayfinder, updates associated flushState cleanup, and refreshes documentation and tests accordingly.

Changes

Resolver Callback Migration and Coroutine-Scoped URL Origins

Layer / File(s) Summary
TrustHosts request-aware host resolution
src/http/src/Middleware/TrustHosts.php, src/http/README.md, src/boost/docs/requests.md, tests/Integration/Http/Middleware/TrustHostsTest.php
Adds REJECT_ALL_HOST_PATTERN sentinel, $hostsResolver static property, resolveTrustedHostPatterns(), and public resolveHostsUsing(); fails closed when no hosts resolve; documented and covered by new integration tests.
Passkeys resolver renames
src/passkeys/src/Passkeys.php, src/boost/docs/fortify.md, tests/Passkeys/*, tests/Fortify/PasskeyTest.php
Renames internal *UsingCallback fields to *Resolver and public methods relyingPartyIdUsing/allowedOriginsUsing to resolveRelyingPartyIdUsing/resolveAllowedOriginsUsing; updates flushState() and detection logic; all call sites and docs updated.
Sanctum stateful-domain resolution
src/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php, src/boost/docs/sanctum.md, src/testing/src/PHPUnit/AfterEachTestSubscriber.php, tests/Sanctum/EnsureFrontendRequestsAreStatefulTest.php
Removes statefulDomains() in favor of resolveStatefulDomains(), adds resolveStatefulDomainsUsing() and flushState(); wires flush into test cleanup; docs and tests updated.
UrlGenerator coroutine-scoped forced origins
src/routing/src/UrlGenerator.php, src/support/src/Facades/URL.php, src/boost/docs/urls.md, tests/Routing/*
Introduces FORCED_ASSET_ROOT_CONTEXT_KEY, removes forcedRoot instance property, updates asset()/formatRoot()/useAssetOrigin() to use CoroutineContext, adds getForcedScheme(), removes flushRequestState() from PHPDoc and flushState() call chain.
Wayfinder forcedRoot removal
src/wayfinder/src/GenerateCommand.php, src/wayfinder/src/Route.php, src/wayfinder/README.md, src/wayfinder/tests/*
Removes forcedRoot from Route constructor and command, replaces reflection-based scheme lookup with getForcedScheme(), updates docs/tests to reflect request-scoped useOrigin() behavior.
Documentation and unrelated maintenance
AGENTS.md, _archive/README.md, src/telescope/database/factories/EntryModelFactory.php, tests/Telescope/Http/RouteTest.php
Adds porting guidance rules, updates archive deletion note, switches Telescope factory to generate uuid/batch_id instead of sequence.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant TrustHosts
  participant HostsResolver
  Client->>TrustHosts: handle(request)
  TrustHosts->>TrustHosts: resolveTrustedHostPatterns(request)
  alt hostsResolver set
    TrustHosts->>HostsResolver: call(request)
    HostsResolver-->>TrustHosts: host patterns
  else no resolver
    TrustHosts->>TrustHosts: hosts()
  end
  alt patterns empty
    TrustHosts->>TrustHosts: use REJECT_ALL_HOST_PATTERN
  end
  TrustHosts-->>Client: allow or SuspiciousOperationException
Loading
sequenceDiagram
  participant Request
  participant EnsureFrontendRequestsAreStateful
  participant Config
  Request->>EnsureFrontendRequestsAreStateful: fromFrontend(request)
  EnsureFrontendRequestsAreStateful->>EnsureFrontendRequestsAreStateful: resolveStatefulDomains(request)
  alt resolver registered
    EnsureFrontendRequestsAreStateful->>EnsureFrontendRequestsAreStateful: call resolver(request)
  else no resolver
    EnsureFrontendRequestsAreStateful->>Config: get sanctum.stateful_domains
  end
  EnsureFrontendRequestsAreStateful-->>Request: stateful/not-stateful decision
Loading

Possibly related PRs

  • hypervel/components#415: Both PRs modify src/testing/src/PHPUnit/AfterEachTestSubscriber.php's post-test framework-state flushing flow.
  • hypervel/components#421: Both PRs modify Sanctum's EnsureFrontendRequestsAreStateful stateful-domain resolution logic.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the core change: adding request-aware runtime configuration hooks across the affected components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/request-aware-resolvers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown

Greptile Summary

This PR moves several extension points from process-global or static state into request-aware APIs, making them safe for Hypervel's long-lived Swoole workers where multiple requests run concurrently. The default behavior is unchanged unless an application explicitly opts into a resolver.

  • TrustHosts gains resolveHostsUsing(), which replaces the static trusted-host list per request; empty resolver results now fail closed via the (?!) regex pattern instead of trusting any host.
  • EnsureFrontendRequestsAreStateful adds resolveStatefulDomainsUsing() and removes the old subclass-override path (statefulDomains()); asset origin overrides in UrlGenerator move from instance state to coroutine-scoped CoroutineContext so one request's useAssetOrigin() call cannot bleed into concurrent requests.
  • Passkeys resolver methods are renamed to the resolve…Using() convention; Wayfinder drops the dead forced-root code path and documents the intentional difference from Laravel.

Confidence Score: 5/5

Safe to merge. The fail-closed defaults, coroutine isolation, and state cleanup are all correctly implemented and well-tested.

All new resolver hooks default to the existing static configuration, so no behaviour change unless explicitly opted into. Fail-closed patterns are correctly applied and covered by integration tests. Asset origin override is moved to CoroutineContext with the right precedence order. Boot-only warnings are consistently applied, and every new flushState() entry is registered in AfterEachTestSubscriber.

No files require special attention.

Important Files Changed

Filename Overview
src/http/src/Middleware/TrustHosts.php Adds resolveHostsUsing() for per-request trusted-host resolution; fail-closed (?!) pattern correctly applied when resolver returns an empty set; Boot-only. docblock and flushState() registration are both in order.
src/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php Removes subclass-override statefulDomains() and replaces it with resolveStatefulDomainsUsing(); filterDomainList() consistently guards against non-string entries; flushState() added to AfterEachTestSubscriber.
src/routing/src/UrlGenerator.php Asset origin override moved from instance property to CoroutineContext for request isolation; flushRequestState() removed (context is cleaned up by coroutine lifecycle); getForcedScheme() getter added for Wayfinder; logic is correct.
src/passkeys/src/Passkeys.php Renames relyingPartyIdUsing to resolveRelyingPartyIdUsing and allowedOriginsUsing to resolveAllowedOriginsUsing to match the resolve...Using convention; docblocks include Boot-only. warnings; all tests updated.
src/wayfinder/src/GenerateCommand.php Drops forcedRoot property and reflection-based private-property access; uses new getForcedScheme() getter instead; consistent with the intentional removal of forced-root support documented in the README.
src/testing/src/PHPUnit/AfterEachTestSubscriber.php Adds EnsureFrontendRequestsAreStateful::flushState() to the global cleanup registry; TrustHosts::flushState() was already present; ordering is alphabetically consistent.
src/support/src/Facades/URL.php Removes @method static void flushRequestState() annotation to match the deleted method on UrlGenerator.
src/telescope/database/factories/EntryModelFactory.php Removes the random sequence default from the factory definition, allowing direct sequence assignment; straightforward cleanup.
tests/Routing/RoutingUrlGeneratorTest.php Adds coroutine isolation tests for both forced origin and forced asset origin; the parallel() + usleep() pattern follows the AGENTS.md guidance for proving per-coroutine isolation.
tests/Integration/Http/Middleware/TrustHostsTest.php Adds comprehensive tests for the new resolver API including fail-closed behavior, empty resolver, non-array resolver, and flush-state clearing.

Reviews (2): Last reviewed commit: "fix(http): harden request-aware resolver..." | Re-trigger Greptile

Comment thread src/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/boost/docs/requests.md (1)

927-945: 🧹 Nitpick | 🔵 Trivial

Consider noting caching guidance for per-request resolver lookups.

The example queries the database inside the resolver, which runs on every trusted-host check (per resolveTrustedHostPatterns() in TrustHosts.php). Worth a brief note recommending callers cache verified domains (e.g., in-process cache/Redis) to avoid a DB round-trip on every request.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/boost/docs/requests.md` around lines 927 - 945, The
TrustHosts::resolveHostsUsing example in the request docs currently shows a
per-request database lookup inside the resolver, which can cause a DB hit on
every trusted-host check. Update the guidance near the TrustHosts and
resolveTrustedHostPatterns usage to note that callers should cache verified
domain lookups (for example with an in-process cache or Redis) before resolving
host patterns, and mention that the resolver should read from cache rather than
querying VerifiedDomain directly on every request.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php`:
- Around line 100-119: The registered-resolver branch in resolveStatefulDomains
currently assumes the callback always returns an array of strings, unlike the
config fallback which validates the shape first. Update the
static::$statefulDomainsResolver path to defensively check that the resolver
result is an array and filter out non-string or empty entries before calling
array_filter, matching the hardening already used for
config('sanctum.stateful_domains', []).

In `@tests/Integration/Http/Middleware/TrustHostsTest.php`:
- Around line 66-134: Add explicit : void return types to each newly added test
method in TrustHostsTest, including
testRequestAwareResolverUsesVerifiedHostPatterns,
testRequestAwareResolverRejectsUnrecognizedHosts,
testEmptyLegacyHostClosureFailsClosed,
testMissingTrustedHostConfigurationFailsClosed, and
testFlushStateClearsRequestAwareResolver, so they match the PHPUnit test method
conventions used elsewhere in the class.

---

Nitpick comments:
In `@src/boost/docs/requests.md`:
- Around line 927-945: The TrustHosts::resolveHostsUsing example in the request
docs currently shows a per-request database lookup inside the resolver, which
can cause a DB hit on every trusted-host check. Update the guidance near the
TrustHosts and resolveTrustedHostPatterns usage to note that callers should
cache verified domain lookups (for example with an in-process cache or Redis)
before resolving host patterns, and mention that the resolver should read from
cache rather than querying VerifiedDomain directly on every request.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 498dc312-3e3d-4da0-a796-a284a77ace9b

📥 Commits

Reviewing files that changed from the base of the PR and between b87676c and ff42cac.

⛔ Files ignored due to path filters (9)
  • _archive/docs/0.3/.vuepress/public/favicon.ico is excluded by !**/*.ico
  • _archive/docs/0.3/.vuepress/public/home.png is excluded by !**/*.png
  • _archive/docs/0.3/.vuepress/public/icon.png is excluded by !**/*.png
  • _archive/docs/0.3/.vuepress/public/icon.svg is excluded by !**/*.svg
  • _archive/docs/0.3/.vuepress/public/images/prompts-example.png is excluded by !**/*.png
  • _archive/docs/0.3/.vuepress/public/images/whoops.png is excluded by !**/*.png
  • _archive/docs/0.3/.vuepress/public/logo.png is excluded by !**/*.png
  • _archive/docs/0.3/.vuepress/public/logo.svg is excluded by !**/*.svg
  • _archive/docs/0.3/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (113)
  • AGENTS.md
  • _archive/README.md
  • _archive/docs/0.3/.vuepress/config.js
  • _archive/docs/0.3/.vuepress/sidebar.js
  • _archive/docs/0.3/.vuepress/styles/palette.scss
  • _archive/docs/0.3/README.md
  • _archive/docs/0.3/docs/artisan.md
  • _archive/docs/0.3/docs/authentication.md
  • _archive/docs/0.3/docs/authorization.md
  • _archive/docs/0.3/docs/blade.md
  • _archive/docs/0.3/docs/broadcasting.md
  • _archive/docs/0.3/docs/cache.md
  • _archive/docs/0.3/docs/collections.md
  • _archive/docs/0.3/docs/configuration.md
  • _archive/docs/0.3/docs/console-tests.md
  • _archive/docs/0.3/docs/container.md
  • _archive/docs/0.3/docs/context.md
  • _archive/docs/0.3/docs/contracts.md
  • _archive/docs/0.3/docs/contributions.md
  • _archive/docs/0.3/docs/controllers.md
  • _archive/docs/0.3/docs/coroutine.md
  • _archive/docs/0.3/docs/csrf.md
  • _archive/docs/0.3/docs/data-objects.md
  • _archive/docs/0.3/docs/database-testing.md
  • _archive/docs/0.3/docs/database.md
  • _archive/docs/0.3/docs/deployment.md
  • _archive/docs/0.3/docs/eloquent-collections.md
  • _archive/docs/0.3/docs/eloquent-factories.md
  • _archive/docs/0.3/docs/eloquent-mutators.md
  • _archive/docs/0.3/docs/eloquent-relationships.md
  • _archive/docs/0.3/docs/eloquent-resources.md
  • _archive/docs/0.3/docs/eloquent-serialization.md
  • _archive/docs/0.3/docs/eloquent.md
  • _archive/docs/0.3/docs/encryption.md
  • _archive/docs/0.3/docs/errors.md
  • _archive/docs/0.3/docs/events.md
  • _archive/docs/0.3/docs/facades.md
  • _archive/docs/0.3/docs/filesystem.md
  • _archive/docs/0.3/docs/hashing.md
  • _archive/docs/0.3/docs/helpers.md
  • _archive/docs/0.3/docs/horizon.md
  • _archive/docs/0.3/docs/http-client.md
  • _archive/docs/0.3/docs/http-tests.md
  • _archive/docs/0.3/docs/installation.md
  • _archive/docs/0.3/docs/introduction.md
  • _archive/docs/0.3/docs/lifecycle.md
  • _archive/docs/0.3/docs/localization.md
  • _archive/docs/0.3/docs/logging.md
  • _archive/docs/0.3/docs/mail.md
  • _archive/docs/0.3/docs/middleware.md
  • _archive/docs/0.3/docs/migrations.md
  • _archive/docs/0.3/docs/mocking.md
  • _archive/docs/0.3/docs/nested-set.md
  • _archive/docs/0.3/docs/notifications.md
  • _archive/docs/0.3/docs/packages-porting.md
  • _archive/docs/0.3/docs/packages.md
  • _archive/docs/0.3/docs/pagination.md
  • _archive/docs/0.3/docs/permission.md
  • _archive/docs/0.3/docs/processes.md
  • _archive/docs/0.3/docs/prompts.md
  • _archive/docs/0.3/docs/providers.md
  • _archive/docs/0.3/docs/queries.md
  • _archive/docs/0.3/docs/queues.md
  • _archive/docs/0.3/docs/rate-limiting.md
  • _archive/docs/0.3/docs/redis.md
  • _archive/docs/0.3/docs/requests.md
  • _archive/docs/0.3/docs/responses.md
  • _archive/docs/0.3/docs/routing.md
  • _archive/docs/0.3/docs/sanctum.md
  • _archive/docs/0.3/docs/scheduling.md
  • _archive/docs/0.3/docs/seeding.md
  • _archive/docs/0.3/docs/session.md
  • _archive/docs/0.3/docs/socialite.md
  • _archive/docs/0.3/docs/strings.md
  • _archive/docs/0.3/docs/structure.md
  • _archive/docs/0.3/docs/telescope.md
  • _archive/docs/0.3/docs/testbench.md
  • _archive/docs/0.3/docs/testing.md
  • _archive/docs/0.3/docs/urls.md
  • _archive/docs/0.3/docs/validation.md
  • _archive/docs/0.3/docs/views.md
  • _archive/docs/0.3/package.json
  • _archive/docs/0.4/permission.md
  • src/boost/docs/fortify.md
  • src/boost/docs/requests.md
  • src/boost/docs/sanctum.md
  • src/boost/docs/urls.md
  • src/http/README.md
  • src/http/src/Middleware/TrustHosts.php
  • src/passkeys/src/Passkeys.php
  • src/routing/src/UrlGenerator.php
  • src/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php
  • src/support/src/Facades/URL.php
  • src/telescope/database/factories/EntryModelFactory.php
  • src/testbench/src/Foundation/Application.php
  • src/testing/src/PHPUnit/AfterEachTestSubscriber.php
  • src/wayfinder/README.md
  • src/wayfinder/src/GenerateCommand.php
  • src/wayfinder/src/Route.php
  • src/wayfinder/tests/AppUrlRootResolution.test.ts
  • src/wayfinder/tests/generate.php
  • tests/Fortify/PasskeyTest.php
  • tests/Integration/Http/Middleware/TrustHostsTest.php
  • tests/Passkeys/CoroutineIsolationTest.php
  • tests/Passkeys/Feature/Actions/GenerateRegistrationOptionsTest.php
  • tests/Passkeys/Feature/Actions/GenerateVerificationOptionsTest.php
  • tests/Passkeys/Feature/PasskeysTest.php
  • tests/Passkeys/Feature/WebAuthnTest.php
  • tests/Passkeys/PasskeysStaticStateTest.php
  • tests/Routing/RoutingStaticStateTest.php
  • tests/Routing/RoutingUrlGeneratorTest.php
  • tests/Sanctum/EnsureFrontendRequestsAreStatefulTest.php
  • tests/Telescope/Http/RouteTest.php
💤 Files with no reviewable changes (2)
  • src/support/src/Facades/URL.php
  • src/telescope/database/factories/EntryModelFactory.php

Comment thread tests/Integration/Http/Middleware/TrustHostsTest.php Outdated
Normalize Sanctum stateful-domain resolver output through the same filtering path as static configuration so malformed resolver values cannot throw while checking a request. Non-array resolver results now degrade to an empty stateful-domain list, matching the existing config fallback behavior.

Make TrustHosts treat non-array request-aware resolver results as an empty trusted-host list. This preserves the middleware's fail-closed behavior by flowing through the reject-all sentinel instead of surfacing a raw TypeError.

Add focused regression coverage for malformed Sanctum resolver output and fail-closed TrustHosts resolver output. Also align TrustHostsTest methods with the repository's : void test method convention.

Document that request-aware trusted-host resolvers run for each request and should resolve against cached verified-host data rather than querying the database every time.

Verified with: composer test tests/Sanctum/EnsureFrontendRequestsAreStatefulTest.php; composer test tests/Integration/Http/Middleware/TrustHostsTest.php; composer lint; composer analyse.
@binaryfire

Copy link
Copy Markdown
Collaborator Author

@greptileai @coderabbitai thanks for the review. I went through the findings against the branch and pushed 76c836875 with the fixes.

What changed:

  • Sanctum now normalizes resolver output through the same filtering path as static sanctum.stateful_domains config. Non-array resolver results become an empty list; non-string and empty entries are dropped. Added tests for both malformed entries and non-array output.
  • TrustHosts now handles non-array request-aware resolver results as an empty trusted-host list, which preserves the fail-closed behavior through the reject-all sentinel instead of leaking a raw TypeError. Added a regression test.
  • TrustHostsTest now has : void on all test methods in the file.
  • The TrustHosts docs now call out that request-aware resolvers run during trusted-host resolution for each request, so production code should resolve against cached verified-host data rather than querying the database each time.

Validation run after the changes:

  • composer test tests/Sanctum/EnsureFrontendRequestsAreStatefulTest.php
  • composer test tests/Integration/Http/Middleware/TrustHostsTest.php
  • composer lint
  • composer analyse

I also replied on the individual inline threads with the specific resolution for each one.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
git log --oneline -5 76c836875 2>/dev/null || echo "commit not found locally"
git show --stat 76c836875 2>/dev/null | head -50

Length of output: 2319


@binaryfire Thanks for the detailed follow-up and for verifying with the lint/analyse/test suite. I confirmed commit 76c836875 on the branch and it matches your description:

  • Sanctum's resolveStatefulDomains() now filters resolver output through the same non-empty-string path as the static config fallback.
  • TrustHosts::resolveTrustedHostPatterns() treats non-array resolver output as an empty list, so it flows into the REJECT_ALL_HOST_PATTERN sentinel instead of throwing a TypeError.
  • TrustHostsTest methods are now consistently typed : void.
  • src/boost/docs/requests.md now documents that request-aware resolvers run per request and should hit cached/verified host data instead of the database each time.

This all looks solid and directly addresses the fail-closed/type-safety concerns raised earlier. I'll check the individual inline thread replies for the specific resolutions as well.

[resolve]

@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown

The fixes look solid. Here's the summary:

Sanctum (EnsureFrontendRequestsAreStateful) — the filterDomainList helper is clean. Both resolver and config paths now go through the same normalization. Non-array results degrade to [], non-string and empty entries are stripped. The new tests cover both cases (testStatefulDomainsResolverIgnoresInvalidEntries, testStatefulDomainsResolverIgnoresNonArrayResults).

TrustHostsresolveTrustedHostPatterns now consistently filters the result of either path (resolver or $this->hosts()), and an empty result flows to REJECT_ALL_HOST_PATTERN. testNonArrayRequestAwareResolverResultFailsClosed confirms the fail-closed behavior end-to-end.

Test hygiene — all TrustHostsTest methods have : void. The new tests use flushState() correctly and have exception assertions placed before the call that triggers them.

One small observation: testNonArrayRequestAwareResolverResultFailsClosed uses static fn (): mixed => null which sidesteps the declared Closure(Request): array<int, string> return type. That's intentional for a malformed-input regression test — the point is to confirm the middleware doesn't throw a TypeError when a resolver misbehaves at runtime. The test proves the contract holds under that condition.

Everything looks correct. The hardening is consistent across both components and the test coverage directly targets the failure modes that were raised. No further changes needed on my end.

@binaryfire binaryfire merged commit e49b6b1 into 0.4 Jul 7, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant