Skip to content

Sync package updates and check QUERY requests for request forgery - #66

Merged
binaryfire merged 25 commits into
0.4from
upstream-sync-batch-3
Oct 20, 2026
Merged

binaryfire merged 25 commits into
0.4from
upstream-sync-batch-3

Conversation

@binaryfire

@binaryfire binaryfire commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Upstream Updates

  • QUERY request forgery checks — Check QUERY requests for request forgery. The middleware treated QUERY as a reading method and skipped its origin and token checks. Since method override is enabled, a cross-site form could POST with _method=QUERY and reach a QUERY route with the visitor's session cookie but without either check. Port upstream's tests, and cover spoofed POSTs from the query string and the body, with and without a valid token, and QUERY in origin-only mode. Port the matching CSRF and routing documentation.
  • Remote file size limit — Set the remote file size limit, ai.remote_files.max_size, in kilobytes as upstream does, and reject a response that declares a larger Content-Length before downloading its body. Hypervel already limited decoded downloads; the default stays 32 MiB and null still disables the limit. The streaming check keeps using the body's position instead of upstream's stat call on every chunk. Document the unit and the early rejection.
  • Gemini thought steps — Rebuild stored Gemini model turns with their thought step before their text, the order Gemini expects.
  • AI tool documentation — Add moving files to the FileStorage tool list, and note that Groq only supports web search and code execution on its GPT-OSS models and ignores the web search max, allow and location methods. The rest was already documented.
  • Scout engine and import tests — Port the tests for queued imports keeping their queue and connection, missing Typesense collections being created with the model's indexable name, and Meilisearch escaping whereIn and whereNotIn values. Hypervel already had all three fixes. Upstream's job tests replace two Hypervel duplicates.
  • Telescope query previews — Format query previews in the SQL dialect of their connection's driver, and show queries from drivers the formatter doesn't support as recorded. Port upstream's Vitest setup and preview tests and run them in CI. MongoDB isn't supported, so its JSON formatting is left out. Update source-map-js to 1.2.2 and rebuild the dashboard assets.
  • Wayfinder QUERY routes — Port upstream's tests for QUERY routes, which Hypervel's Wayfinder already supported. Document their generated query method and how forms spoof them.
  • Wayfinder without a database — Add wayfinder:generate --skip-database for builds that can't reach the database. Route binding types then come from casts and @property docblocks instead of the schema. Document the option.
  • MCP client authentication — Document MCP client authentication with bearer tokens, linking user accounts with OAuth, and client metadata, and explain how it differs from authenticating clients to your own servers.
  • Blade stack order — Explain that @stack only renders content pushed before it is reached.
  • Signed URL input — Warn that a signed URL's signature doesn't cover the request body, so signed values should be read with query().
  • Role model guards — Make hasRole() and hasAllRoles() respect the requested guard when given a Role model. A role from another guard used to match.
  • Permission lookup indexes — Upstream indexes cached permissions by name and key. Hypervel already had these indexes, but built them by reading attributes, so loading the catalog ran name and guard accessors, and an indexed lookup could disagree with filtering when an accessor or cast changed a value. Build the name index from stored attributes, and use an index only when reading its attributes returns the stored values. Upstream also rescans returned models for unsaved changes. Hypervel keeps lookups free of that rescan and documents that a changed role or permission must be saved before further lookups. Port upstream's tests and lookup benchmark.
  • Saloon cached responses and rate limits — Port the tests that cached responses don't count against rate limits. Hypervel's Saloon manager already checks the cache before rate limiting.

Additional Hypervel Fixes

  • Pass socket read timeouts by name in the HTTP and database test fixtures. Swoole\Coroutine\Socket::recv() takes the length first, so ten calls meant to wait two or three seconds instead read at most two or three bytes at a time, with no time limit.
  • Add a Permission section to the Laravel porting guide, covering the expiration_seconds setting, the same-backend lock requirement and saving changed models before further lookups.
  • Match Role models in a list passed to hasAllRoles() or hasExactRoles(), and a single model passed to hasExactRoles(), by key and guard. They were compared by name, so a role with the same name from another guard matched.
  • Remove a stale link from the HTTP testing docs to a QUERY route limitation that no longer exists.
  • Let the benchmark harnesses run full measurements without an extra confirmation flag. Their READMEs now just ask for an idle machine.

The full suite, formatting and static analysis pass, along with the Scout integration tests against Meilisearch and Typesense and the Telescope and Wayfinder JavaScript tests. CI will run the full suite and supported service matrix.

Note

Require forgery verification for QUERY requests and sync package updates

  • Removes QUERY from the safe-method list in PreventRequestForgery, so cross-site QUERY requests now require an origin or CSRF token, including method-override spoofs; adds tests and CSRF/routing docs
  • Reworks permission lookup indexes in PermissionRegistrar: cached catalogs record which indexes are safe, indexed lookups decline unsupported value types, and models with accessors or disallowed casts fall back to filtering
  • Makes HasRoles guard-aware for Role model inputs in hasRole, hasAllRoles, and hasExactRoles
  • Changes AI remote-file max_size to kilobytes (default 32 MiB via MAX_KILOBYTES), with pre-checks on declared Content-Length and decoded byte counting; adds --skip-database option to wayfinder:generate and dialect-aware SQL formatting in the Telescope query preview
  • Simplifies benchmark tooling by removing the idle-confirmed flag and setup guards across all benchmark suites
  • Behavioral Change: existing QUERY endpoints without CSRF tokens now fail verification; configs setting max_size in bytes are now interpreted as kilobytes; indexed permission lookups skip accessor-transformed attributes

Macroscope summarized 48c1c8a.

Swoole\Coroutine\Socket::recv() takes the read length first and the
timeout second. Ten calls in the HTTP and database test fixtures passed
2 or 3 positionally, intending a timeout, so each read returned at most
two or three bytes and waited without a time limit. Pass the timeout by
name. The remaining positional recv() calls are on HTTP, HTTP/2 and gRPC
clients, whose first argument is the timeout. The affected test files
pass.
Laravel master's QUERY route support (laravel/framework#60655, ported
earlier) treats QUERY as a reading method, so PreventRequestForgery
skipped its origin and token checks. Method override is enabled, so a
cross-site form POST with _method=QUERY, in the query string or the
body, reached QUERY routes without either check when the browser sent
the session cookie. Laravel 13.x verifies QUERY on purpose
(laravel/framework#61797 at 3bb5d6084544), so isReading() now covers
only HEAD, GET and OPTIONS, with a source comment explaining why.

Port #61797's two tests, and cover spoofed POSTs from both request bags,
without and with a valid token, and QUERY in origin-only mode. Port the
matching csrf.md and routing.md wording from laravel/docs 13.x
(226b0649c7, at 12080c72699b), and drop http-tests.md's stale link to
the removed Swoole QUERY warning. The rest of #61797 already matched the
#60655 port. Formatting, static analysis and the full suite pass.
laravel/ai#1139 (laravel/ai 1.x at d44ae14d17fb) limits fetched remote
files in kilobytes and rejects a response whose Content-Length exceeds
the limit before reading its body. Hypervel already bounded downloads
in bytes. ai.remote_files.max_size is now in kilobytes, shipped as
32 * 1024 and matched by the public MAX_KILOBYTES constant, keeping null
to disable the limit, the validation, cancellation precedence and
URL-free messages in upstream's wording.

Port the on_headers rejection. The sink keeps its tell()-based check,
since upstream's getSize() adds clearstatcache() and fstat() for every
chunk. The transport drops a compressed response's Content-Length
before on_headers, so the sink still bounds decoded bytes. Port
upstream's five tests with Hypervel's fakes, replacing a duplicate
faked-limit test, move the loopback cases to kilobytes and add a real
server case that is rejected before any body is sent.

Document the kilobyte unit and the early rejection in ai-sdk.md and the
README difference. The same file also takes laravel/docs#11401 (13.x at
12080c72699b): move in the FileStorage tool list and Groq's GPT-OSS
notes for web search and code execution. Formatting, static analysis
and the AI suite pass.
laravel/ai#1150 (laravel/ai 1.x at d44ae14d17fb): Gemini expects a
model turn's thought step before its text, but mapAssistantMessage()
rebuilt stored turns with the text first. Emit the thought step first;
this is the only place Gemini turns are rebuilt. Port upstream's mapping
test and its persistence-test update. Formatting, static analysis and
the AI suite pass.
laravel/scout#1015 (laravel/scout 11.x at d6d1774c4fa5) makes queued
imports keep their queue and connection. Hypervel's MakeRangeSearchable
already prefers its own queue and connection, so only the tests are
ported: the queue-import command test, and upstream's two job tests in
place of Hypervel's two duplicates, keeping upstream's key and count
assertions. The Scout suite passes.
laravel/scout#1013 (laravel/scout 11.x at d6d1774c4fa5) creates missing
Typesense collections with the model's indexable name. Hypervel's
createCollectionFromModel() already receives that name on update. Give
Hypervel's matching unit test upstream's name and port upstream's
integration test, where the schema has no name and the read collection
is never created. It passes against Typesense 27.1.
laravel/scout#1014 (laravel/scout 11.x at d6d1774c4fa5) escapes values
in Meilisearch whereIn and whereNotIn filters. Hypervel's filters()
already escapes them, so upstream's unit and integration tests are
ported; the integration test filters on title. Both fail without the
escaping, and both pass against Meilisearch.
laravel/telescope#1770 (laravel/telescope 5.x at dcc6674c825f) formats
query previews by driver. Port formatQuery(), sqlDialect(), the pgsql
and sqlsrv aliases, raw output for unknown drivers and the
highlightQuery/querycode rename. MongoDB is unsupported, so its alias,
the JSON grammar and branch, and queryLanguage() are omitted with
REMOVED comments; the preview keeps a static language-sql class.

Port upstream's Vitest harness (dev dependencies, config and scripts)
and preview.test.js at upstream's location, without the MongoDB-only
cases and with SQL clipboard and ready cases. The CI JavaScript job
installs npm 11.21.0, which Telescope's devEngines require, and runs
npm ci and npm test in src/telescope. The lockfile also takes
laravel/telescope#1772, bumping source-map-js to 1.2.2 as upstream
does. dist is rebuilt. npm ci and npm test pass.
laravel/wayfinder#324 (laravel/wayfinder main at 81df21e16dc1) adds
QUERY route support. Hypervel's Wayfinder already has the query Method
type, so port upstream's QueryMethod.test.ts with its SearchController
fixture and two QUERY routes. The usage docs follow with the next
commit's Wayfinder docs. The Wayfinder JavaScript tests in both modes,
the type check and the PHP suite pass.
laravel/wayfinder#331 (laravel/wayfinder main at 81df21e16dc1) adds
wayfinder:generate --skip-database, for builds where the database is
unreachable. Port the option and BindingResolver::skipDatabase(), which
clears cached columns when the setting changes and is reset by
flushState(). Hypervel types bindings from casts, then the schema, then
docblocks, so skipping the schema falls through to the docblock.

Port upstream's SkipDatabaseTest. Its model is non-incrementing, since
an incrementing key's int cast correctly outranks the docblock. The
test fails without the skip check or the cache reset.

Document the option, noting that casts still apply. wayfinder.md also
takes #324's QUERY usage and form-spoofing paragraphs, adapted to
Route::query(); method override spoofs _method=QUERY over POST.
Formatting, static analysis and the Wayfinder suites pass.
Port laravel/docs d9b95fe9c8 (13.x at 12080c72699b): the notes
separating server and client authentication, the client example and
optional named-client wording, and the Bearer Tokens, Linking User
Accounts With OAuth and Client Metadata sections with upstream's
projects example, where withOAuth() and withToken() configure separate
state. Hypervel's coroutine-owned named clients, TokenSet return types,
scope storage (now projects_scope, also in the scopes example) and the
custom redirectUri note are kept.
Port laravel/docs#11409 (13.x at 12080c72699b) to blade.md. @stack
compiles to yieldPushContent() where it is reached, as in Laravel, so
pushes rendered after the stack do not appear in it.
Port laravel/docs#11413 (13.x at 12080c72699b) to the end of urls.md's
signature validation section, after Hypervel's ValidateSignature
additions. Request::getInputSource() uses the JSON body even for GET
requests, and all() gives it precedence over the query string.
spatie/laravel-permission#2978 (main at 264c0dedebca): hasRole() with a
Role model ignored the requested guard, so a role from another guard
matched. Filter Role models by a non-empty guard, as Hypervel does for
role names, and have hasAllRoles() delegate to hasRole(), keeping the
partition check. hasPermissionTo() keeps upstream's behavior, where a
Permission model's own guard wins. Port upstream's data-provider test;
its different-guard case fails before the fix. The Permission suite
passes.
spatie/laravel-permission#2969 (main at 264c0dedebca) indexes cached
permissions by name and key. Hypervel's catalog already indexed key and
name+guard lookups, but built them from attribute reads, so loading ran
name and guard accessors, and an index could disagree with filtering
when an accessor or cast changed the value. Build the name index from
raw attributes, and use an index only when reading its attributes
returns the stored value (the key may keep its key-type cast).
Non-integer, non-string lookup values use the filter, and filterModels()
compares names through enum_value() for enum-returning name accessors.

Upstream rescans returned models to catch unsaved changes. Instead, the
owner-approved contract is that callers save a changed cached role or
permission before looking up roles or permissions again, keeping lookups
free of rescans. It is documented in the source, the package README,
permission.md and the porting guide. The porting guide also gains the
expiration_seconds and same-backend lock requirements, and its AI SDK
entry takes the remote file size default from laravel/ai#1139.

Port upstream's shared lookup tests, accessor test, custom-collection
cases and an exact-matching version of its loose-comparison test, and
add a current key-accessor lookup regression. REMOVED comments cover
the unsaved-mutation, runtime boolean-cast and excluded-key tests. Port
the lookup benchmark as an explicitly run fixture outside normal test
discovery. Formatting, static analysis and the Permission suite pass.
saloonphp/rate-limit-plugin#30 (v2 at 180c3f757f55) stops cached
responses from counting against rate limits. Hypervel's
SaloonManager::send() already reads the cache before rate limiting, so
cache hits use no capacity. Port upstream's five CacheHitRateLimitTest
cases, sending a cacheable CachedUserRequest in place of upstream's
fake-response middleware, and faking real requests with Http::fake(),
since Saloon fakes use no capacity. Four cases fail if cache hits go
through rate limiting. The Saloon suite passes.
The benchmark harnesses refused full-size runs unless they were given
--idle-confirmed or BENCH_IDLE_CONFIRMED=1, and their READMEs asked for
an owner-confirmed idle window. That encoded a private review workflow
into public developer tools. Remove the flags and their rejection
paths, so a run without smoke mode measures at full size, and describe
the requirement as ordinary guidance to run on an idle machine.

Smoke and probe modes, workload settings, service and port validation,
cleanup and correctness assertions are unchanged. Sentry's
components.sh keeps an explicit mode, now smoke|measure|inventory,
still clears an inherited BENCH_SMOKE, and passes no fetcher flag in
measure mode. Reproduction commands in the READMEs and results files
drop the flag; recorded results are unchanged. The PHP files pass
php -l, components.sh passes bash -n, and each harness's help and
argument checks were run without measuring.
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: hypervel/components-backup/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7102d97c-7b08-48e6-913c-d23a0186ea51

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Verify QUERY requests and sync package fixes, tests, and docs

🐞 Bug fix ✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Verify QUERY requests against forgery, and enforce guards and safe cached-permission lookups.
• Limit remote downloads earlier, correct Gemini turn order, and add database-free Wayfinder
 generation.
• Sync package tests and documentation, improve Telescope previews, and simplify benchmark runs.
Diagram

graph TD
  A["Direct QUERY or POST"] --> B["Method override"] --> C{"Reading method?"} -->|No| D["Origin or token"] --> E["QUERY route"]
  C -->|GET HEAD OPTIONS| F["Read route"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Disallow QUERY method overrides
  • ➕ Removes the cross-site form override path.
  • ➖ Does not establish a consistent verification policy for direct QUERY requests.
  • ➖ Breaks the form behavior exposed by Wayfinder.
2. Rescan returned permission models on every lookup
  • ➕ Could reflect unsaved in-memory changes to shared models.
  • ➖ Adds lookup work proportional to catalog size.
  • ➖ Conflicts with the documented save-before-lookup contract.

Recommendation: Keep the PR's approach: verify QUERY regardless of transport, while retaining method-override support. Build permission indexes without invoking name or guard accessors, fall back to filtering where indexed values could disagree, and require saving changed models before further lookups.

Files changed (76) +1721 / -280

Enhancement (14) +49 / -79
app.jsRebuild the Telescope dashboard asset +8/-8

Rebuild the Telescope dashboard asset

• Updates the distributed dashboard bundle for the query-preview changes.

src/telescope/dist/app.js

BindingResolver.phpAllow binding resolution without schema queries +19/-0

Allow binding resolution without schema queries

• Adds a database-skip mode so binding types come from casts and docblocks when schema access is disabled. Clears cached columns when the mode changes and resets it with other resolver state.

src/wayfinder/src/BindingResolver.php

GenerateCommand.phpExpose Wayfinder's --skip-database option +3/-1

Expose Wayfinder's --skip-database option

• Adds the command option and passes its value to binding resolution before generating output.

src/wayfinder/src/GenerateCommand.php

BroadcastBenchmark.phpRemove broadcast benchmark confirmation gate +1/-5

Remove broadcast benchmark confirmation gate

• Allows full measurements without an extra environment flag while retaining required local-service checks.

tests/Benchmarks/Ai/Fixtures/BroadcastBenchmark.php

ConversationBenchmark.phpRemove conversation benchmark confirmation gate +1/-2

Remove conversation benchmark confirmation gate

• Drops the smoke-or-idle confirmation assertion while retaining disposable database validation.

tests/Benchmarks/Ai/Fixtures/ConversationBenchmark.php

EmbeddingCacheBenchmark.phpRemove embedding benchmark confirmation gate +1/-5

Remove embedding benchmark confirmation gate

• Permits measurements without a confirmation flag while still requiring a disposable Redis port.

tests/Benchmarks/Ai/Fixtures/EmbeddingCacheBenchmark.php

RuntimeBenchmark.phpAllow direct runtime benchmark measurements +0/-12

Allow direct runtime benchmark measurements

• Removes setup logic whose sole purpose was enforcing a smoke-or-idle confirmation flag.

tests/Benchmarks/Ai/Fixtures/RuntimeBenchmark.php

ScoutVectorBenchmark.phpRemove Scout vector benchmark confirmation gate +1/-2

Remove Scout vector benchmark confirmation gate

• Drops the confirmation assertion but keeps database-port and variant checks.

tests/Benchmarks/Ai/Fixtures/ScoutVectorBenchmark.php

benchmark.phpPermit Guzzle measurements without a confirmation flag +2/-5

Permit Guzzle measurements without a confirmation flag

• Removes --idle-confirmed from option parsing and the measurement gate; --smoke remains available.

tests/Benchmarks/GuzzleOwnership/benchmark.php

concurrency.phpPermit MCP measurements without confirmation +2/-5

Permit MCP measurements without confirmation

• Removes the --idle-confirmed option and gate while preserving the short --smoke mode.

tests/Benchmarks/Mcp/concurrency.php

SentryComponentBenchmark.phpRemove Sentry component benchmark confirmation gate +0/-12

Remove Sentry component benchmark confirmation gate

• Deletes setup logic that blocked runs without a smoke-or-idle confirmation flag.

tests/Benchmarks/Sentry/Fixtures/SentryComponentBenchmark.php

benchmark.phpAllow Sentry measurements without --idle-confirmed +2/-7

Allow Sentry measurements without --idle-confirmed

• Removes the option and full-size-run gate; --smoke still selects smaller correctness workloads.

tests/Benchmarks/Sentry/benchmark.php

components.shRename the Sentry component measurement mode +8/-9

Rename the Sentry component measurement mode

• Replaces idle-confirmed with measure and passes --smoke to the fetcher only in smoke mode.

tests/Benchmarks/Sentry/components.sh

request-fetcher.phpAllow direct Sentry fetcher measurements +1/-6

Allow direct Sentry fetcher measurements

• Drops the confirmation option and gate while retaining --smoke.

tests/Benchmarks/Sentry/request-fetcher.php

Bug fix (13) +152 / -66
UntrustedUrl.phpReject oversized declared remote downloads +32/-14

Reject oversized declared remote downloads

• Converts the kilobyte setting to bytes, rejects oversized decoded Content-Length values before reading the body, and retains streaming enforcement for other responses. Preserves cancellation and unrelated transport failures.

src/ai/src/Files/UntrustedUrl.php

MapsMessages.phpRestore Gemini thought steps before assistant text +5/-5

Restore Gemini thought steps before assistant text

• Rebuilds a persisted assistant turn with its thought signature ahead of model output and tool calls, matching Gemini's expected step order.

src/ai/src/Gateway/Gemini/Concerns/MapsMessages.php

PreventRequestForgery.phpVerify QUERY requests for forgery +2/-1

Verify QUERY requests for forgery

• Removes QUERY from methods that bypass origin and token checks, including requests reached through POST method override.

src/foundation/src/Http/Middleware/PreventRequestForgery.php

PermissionRegistrar.phpKeep permission indexes consistent with filtered lookups +64/-10

Keep permission indexes consistent with filtered lookups

• Builds name indexes from stored attributes without running name or guard accessors. Uses indexes only for compatible model attributes and lookup values, falling back to filtering when needed.

src/permission/src/PermissionRegistrar.php

HasRoles.phpHonor guards for Role-model checks +3/-7

Honor guards for Role-model checks

• Applies the requested guard when hasRole receives a Role model and delegates the corresponding hasAllRoles case to that check.

src/permission/src/Traits/HasRoles.php

preview.vueFormat query previews for their SQL driver +36/-19

Format query previews for their SQL driver

• Maps driver aliases to supported formatter dialects and leaves unsupported queries unchanged. Displays, copies, and highlights the resulting SQL preview.

src/telescope/resources/js/screens/queries/preview.vue

BedrockHttpTest.phpUse the intended Bedrock socket timeout +1/-1

Use the intended Bedrock socket timeout

• Passes the fixture's recv timeout by name instead of accidentally limiting its read length.

tests/Ai/BedrockHttpTest.php

HttpStreamingTest.phpCorrect streaming fixture read timeouts +2/-2

Correct streaming fixture read timeouts

• Uses named socket timeouts when waiting for provider connections to close.

tests/Ai/HttpStreamingTest.php

DatabaseConnectionLeaseTest.phpCorrect database fixture socket timeout +1/-1

Correct database fixture socket timeout

• Uses the named recv timeout while reading test-server request headers.

tests/Database/DatabaseConnectionLeaseTest.php

CurlStreamingHandlerTest.phpCorrect cURL streaming fixture timeout +1/-1

Correct cURL streaming fixture timeout

• Passes the intended socket read timeout by name rather than as a byte count.

tests/Http/Client/CurlStreamingHandlerTest.php

LoopbackHttpServer.phpCorrect loopback server read timeouts +2/-2

Correct loopback server read timeouts

• Uses named timeouts for both header and body reads in the shared HTTP test server.

tests/Http/Fixtures/LoopbackHttpServer.php

concurrent-stream-deadlines.phpCorrect concurrent deadline fixture timeouts +2/-2

Correct concurrent deadline fixture timeouts

• Uses named socket timeouts when reading headers and waiting for a stalled client.

tests/Http/Fixtures/concurrent-stream-deadlines.php

concurrent-stream-headers.phpCorrect concurrent header fixture timeout +1/-1

Correct concurrent header fixture timeout

• Passes the intended socket timeout by name when reading request headers.

tests/Http/Fixtures/concurrent-stream-headers.php

Tests (19) +1232 / -75
preview.test.jsTest SQL query previews across drivers +117/-0

Test SQL query previews across drivers

• Covers dialect selection, unknown-driver passthrough, generic fallback, formatted clipboard content, and highlighting.

src/telescope/resources/js/screens/queries/preview.test.js

QueryMethod.test.tsTest generated QUERY route helpers +104/-0

Test generated QUERY route helpers

• Checks standalone and mixed-method routes, named routes, query parameters, and POST-based form spoofing.

src/wayfinder/tests/QueryMethod.test.ts

UntrustedUrlTest.phpCover kilobyte limits and early download rejection +86/-20

Cover kilobyte limits and early download rejection

• Tests default, exact, excessive, compressed, and unlimited downloads, including rejection before a declared oversized body arrives. Verifies unrelated transport errors remain unchanged.

tests/Ai/Feature/Files/UntrustedUrlTest.php

MessageMappingTest.phpAssert Gemini thought-step ordering +24/-0

Assert Gemini thought-step ordering

• Verifies that rebuilding a text-and-tool assistant turn puts its signed thought step before the text and function call.

tests/Ai/Feature/Providers/Gemini/MessageMappingTest.php

DatabaseConversationStoreTest.phpCheck persisted Gemini turn ordering +6/-5

Check persisted Gemini turn ordering

• Adds text to a stored tool conversation and asserts the complete rebuilt step sequence and thought signature.

tests/Ai/Feature/Storage/DatabaseConversationStoreTest.php

PreventRequestForgeryTest.phpCover direct and spoofed QUERY verification +84/-12

Cover direct and spoofed QUERY verification

• Replaces the former QUERY bypass expectation with token, method-override, and origin-only coverage. Tests overrides supplied in either the query string or POST body.

tests/Http/Middleware/PreventRequestForgeryTest.php

MeilisearchFilteringIntegrationTest.phpExercise escaped Meilisearch set filters +21/-0

Exercise escaped Meilisearch set filters

• Checks against a running service that injected whereIn and whereNotIn values do not alter filter semantics.

tests/Integration/Scout/Meilisearch/MeilisearchFilteringIntegrationTest.php

TypesenseEngineIntegrationTest.phpExercise Typesense indexable collection naming +60/-0

Exercise Typesense indexable collection naming

• Adds a model whose search and index names differ and verifies missing-collection creation uses indexableAs().

tests/Integration/Scout/Typesense/TypesenseEngineIntegrationTest.php

PermissionRegistrarTest.phpExpand permission index consistency coverage +324/-0

Expand permission index consistency coverage

• Tests indexed and filtered lookup equivalence, numeric-looking values, custom accessors and collections, guard separation, invalidation, and release of cleared models.

tests/Permission/Integration/PermissionRegistrarTest.php

HasRolesTest.phpTest guard-filtered Role-model checks +23/-0

Test guard-filtered Role-model checks

• Covers matching, different, and absent guards for hasRole and hasAllRoles with Role models and arrays.

tests/Permission/Traits/HasRolesTest.php

CacheHitRateLimitTest.phpTest cached Saloon responses against rate limits +129/-0

Test cached Saloon responses against rate limits

• Verifies cache hits consume no capacity, including when a limit is exhausted, while real responses still count.

tests/Saloon/RateLimit/Feature/CacheHitRateLimitTest.php

CachedUserRequest.phpAdd a cacheable Saloon request fixture +39/-0

Add a cacheable Saloon request fixture

• Defines a GET request used to exercise actual response-cache hits in rate-limit tests.

tests/Saloon/RateLimit/Fixtures/Requests/CachedUserRequest.php

QueueImportCommandTest.phpTest Scout import queue overrides +22/-0

Test Scout import queue overrides

• Verifies queued searchable jobs use the queue selected by scout:queue-import.

tests/Scout/Unit/Console/QueueImportCommandTest.php

MeilisearchEngineTest.phpTest Meilisearch set-value escaping +22/-0

Test Meilisearch set-value escaping

• Asserts generated whereIn and whereNotIn filters escape quotes, backslashes, and attempted filter injection.

tests/Scout/Unit/Engines/MeilisearchEngineTest.php

TypesenseEngineTest.phpAlign Typesense missing-collection test naming +1/-1

Align Typesense missing-collection test naming

• Renames the existing test to emphasize creation using the model's indexable name.

tests/Scout/Unit/Engines/TypesenseEngineTest.php

MakeRangeSearchableTest.phpVerify Scout job queue and connection propagation +41/-37

Verify Scout job queue and connection propagation

• Replaces overlapping bus assertions with queue assertions for explicit parent-job settings and configured defaults.

tests/Scout/Unit/Jobs/MakeRangeSearchableTest.php

SearchController.phpAdd a controller for QUERY route fixtures +22/-0

Add a controller for QUERY route fixtures

• Provides index and show actions for generated QUERY route tests.

tests/Wayfinder/Fixtures/Controllers/SearchController.php

routes.phpRegister QUERY route fixtures +4/-0

Register QUERY route fixtures

• Adds QUERY-only and GET-plus-QUERY named routes for Wayfinder generation tests.

tests/Wayfinder/Fixtures/routes.php

SkipDatabaseTest.phpTest Wayfinder schema-free binding types +103/-0

Test Wayfinder schema-free binding types

• Compares generated binding types with and without --skip-database, confirming a docblock type replaces the schema type when skipping.

tests/Wayfinder/SkipDatabaseTest.php

Documentation (25) +160 / -58
README.mdClarify remote download size units +1/-1

Clarify remote download size units

• Documents the 32 MiB default and that max_size is configured in kilobytes, with null disabling the limit.

src/ai/README.md

ai-sdk.mdDocument download limits and AI tool capabilities +10/-4

Document download limits and AI tool capabilities

• Explains kilobyte limits and early Content-Length rejection, adds file moves to FileStorage, and states Groq's GPT-OSS-only tool support and ignored web-search options.

src/docs/ai-sdk.md

blade.mdExplain when Blade stacks render +2/-0

Explain when Blade stacks render

• Clarifies that @stack includes only content pushed before rendering reaches the directive.

src/docs/blade.md

csrf.mdInclude QUERY in CSRF guidance +2/-2

Include QUERY in CSRF guidance

• Lists QUERY among verified methods and among JavaScript requests that should send the XSRF token.

src/docs/csrf.md

http-tests.mdRemove obsolete QUERY route caveat +0/-2

Remove obsolete QUERY route caveat

• Deletes a link to a production QUERY route limitation that no longer applies.

src/docs/http-tests.md

mcp.mdExplain outgoing MCP client authentication +62/-24

Explain outgoing MCP client authentication

• Expands bearer-token and OAuth account-linking instructions, including named clients, callbacks, metadata, and token storage. Distinguishes connecting to external servers from authenticating clients to an application's own server.

src/docs/mcp.md

permission.mdDocument the save-before-lookup requirement +2/-0

Document the save-before-lookup requirement

• Warns that cached role and permission models are shared within a request or job and must be saved before further lookups after changes.

src/docs/permission.md

porting-from-laravel.mdAdd permission migration guidance +7/-1

Add permission migration guidance

• Documents the expiration_seconds setting, same-backend cache and lock requirement, and save-before-lookup behavior; also clarifies remote-file limit units.

src/docs/porting-from-laravel.md

routing.mdDescribe QUERY route verification +2/-2

Describe QUERY route verification

• Notes that QUERY routes in the web middleware group receive CSRF protection and that routes registered with any include QUERY.

src/docs/routing.md

urls.mdWarn against reading signed values from merged input +3/-0

Warn against reading signed values from merged input

• Explains that signatures cover URL values, not request bodies, and recommends query() to retrieve signed parameters.

src/docs/urls.md

wayfinder.mdDocument database-free generation and QUERY forms +17/-0

Document database-free generation and QUERY forms

• Introduces --skip-database and its binding-type fallbacks, and describes generated QUERY methods and POST form spoofing.

src/docs/wayfinder.md

README.mdState cached-model lookup expectations +1/-0

State cached-model lookup expectations

• Documents catalog indexes and the need to save modified roles or permissions before another lookup.

src/permission/README.md

README.mdUpdate AI benchmark run instructions +6/-6

Update AI benchmark run instructions

• Replaces confirmation-flag instructions with guidance to remove BENCH_SMOKE for full runs on an idle machine.

tests/Benchmarks/Ai/README.md

http.phpSimplify AI HTTP benchmark help text +1/-1

Simplify AI HTTP benchmark help text

• Asks users to run measurements on an idle machine without requiring owner confirmation.

tests/Benchmarks/Ai/http.php

README.mdSimplify Data benchmark guidance +1/-1

Simplify Data benchmark guidance

• Recommends an idle machine without requiring an owner's confirmation.

tests/Benchmarks/Data/README.md

README.mdSimplify database benchmark guidance +1/-1

Simplify database benchmark guidance

• Retains controlled-comparison instructions while replacing the owner-confirmed window requirement with idle-machine guidance.

tests/Benchmarks/Database/README.md

benchmark.phpUpdate database benchmark help text +1/-1

Update database benchmark help text

• Rewords the run guidance to ask for an idle machine.

tests/Benchmarks/Database/benchmark.php

README.mdRemove Guzzle benchmark confirmation instructions +1/-2

Remove Guzzle benchmark confirmation instructions

• Keeps smoke and idle-machine guidance but no longer requires --idle-confirmed for measured runs.

tests/Benchmarks/GuzzleOwnership/README.md

results.mdRefresh recorded Guzzle benchmark command +1/-1

Refresh recorded Guzzle benchmark command

• Removes the obsolete --idle-confirmed argument from the example.

tests/Benchmarks/GuzzleOwnership/results.md

README.mdUpdate HTTP transport benchmark guidance +1/-1

Update HTTP transport benchmark guidance

• Replaces owner-confirmed scheduling language with an idle-machine recommendation.

tests/Benchmarks/HttpTransport/README.md

benchmark.phpUpdate HTTP transport benchmark help +1/-1

Update HTTP transport benchmark help

• Simplifies its measurement warning to request an idle machine.

tests/Benchmarks/HttpTransport/benchmark.php

README.mdDocument direct MCP benchmark measurements +2/-2

Document direct MCP benchmark measurements

• Shows a full-run command without --idle-confirmed and retains idle-machine guidance.

tests/Benchmarks/Mcp/README.md

README.mdExplain permission lookup benchmark methodology +30/-0

Explain permission lookup benchmark methodology

• Documents commands, workload sizes, reported timing and memory metrics, and comparison precautions.

tests/Benchmarks/Permission/README.md

README.mdRefresh Sentry benchmark run instructions +4/-4

Refresh Sentry benchmark run instructions

• Removes confirmation flags from full-run examples, changes the component mode to measure, and retains idle-machine guidance.

tests/Benchmarks/Sentry/README.md

results.mdRemove obsolete Sentry benchmark flag +1/-1

Remove obsolete Sentry benchmark flag

• Updates a recorded measurement command to omit BENCH_IDLE_CONFIRMED.

tests/Benchmarks/Sentry/results.md

Other (5) +128 / -2
tests.ymlRun Telescope dashboard tests in CI +12/-0

Run Telescope dashboard tests in CI

• Installs a compatible npm version and the Telescope package dependencies, then runs its new test script.

.github/workflows/tests.yml

ai.phpExpress the remote file limit in kilobytes +2/-2

Express the remote file limit in kilobytes

• Changes the configured default from bytes to 32 × 1024 kilobytes, preserving a 32 MiB effective limit.

src/ai/config/ai.php

package.jsonAdd Telescope test scripts and tooling +5/-0

Add Telescope test scripts and tooling

• Adds Vitest scripts and the Vue test utilities and jsdom dependencies used by dashboard tests.

src/telescope/package.json

vitest.config.jsConfigure Telescope component tests +11/-0

Configure Telescope component tests

• Sets up Vitest with Vue 2 support, jsdom, and the dashboard test-file pattern.

src/telescope/vitest.config.js

PermissionLookupBenchmark.phpMeasure permission catalog lookup costs +98/-0

Measure permission catalog lookup costs

• Adds explicit benchmarks for name and ID lookups, misses, catalog hydration, and retained memory across configurable catalog sizes.

tests/Benchmarks/Permission/Fixtures/PermissionLookupBenchmark.php

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Old byte-valued size limits grow 1024-fold 🐞 Bug ⛨ Security
Description
UntrustedUrl::fetch() now multiplies ai.remote_files.max_size by 1024. Before this change the
published config held a byte count (32 * 1024 * 1024), so any app that published that config or
set its own byte value now gets a limit of about 32 GiB (or 1024× its custom value). The value still
passes the positive-integer check, so the remote-download memory limit is effectively gone without
any error or warning, for allowed hosts and untrusted URLs alike.
Code

src/ai/src/Files/UntrustedUrl.php[R41-47]

+        $kilobytes = config()->get('ai.remote_files.max_size', static::MAX_KILOBYTES);
-        if ($maxSize !== null && (! is_int($maxSize) || $maxSize <= 0)) {
+        if ($kilobytes !== null && (! is_int($kilobytes) || $kilobytes <= 0)) {
          throw new InvalidArgumentException('The remote file maximum size must be a positive integer or null.');
      }
+        $limit = $kilobytes === null ? null : $kilobytes * 1024;
Evidence
The old config default and docs told users to set the value in bytes (32 * 1024 * 1024, `64 * 1024
* 1024). The new code reads the same key, accepts any positive int, and computes $limit =
$kilobytes * 1024`. The README and porting guide describe the new unit, but they include no upgrade
note for Hypervel apps that already published the byte-based config, and nothing at runtime catches
values that are clearly in bytes.

src/ai/src/Files/UntrustedUrl.php[41-47]
src/ai/config/ai.php[89-99]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ai.remote_files.max_size` changed from bytes to kilobytes. Existing published configs that hold byte values (for example 33554432) now set a limit 1024 times larger, so the download limit is effectively disabled without any signal.
## Fix Focus Areas
- src/ai/src/Files/UntrustedUrl.php[41-47]
- src/ai/README.md[30-30]
- src/docs/ai-sdk.md[1066-1075]
## Recommended Fix
Add an explicit upgrade note telling users to divide a previously published `max_size` by 1024. Optionally, in `fetch()`, reject or log a warning for implausibly large values (for example above 16 * 1024 * 1024 KB) that look like leftover byte counts.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can open the rule or relationship behind a finding in one click

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/ai/src/Files/UntrustedUrl.php
@greptile-apps

greptile-apps Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 3/5 Tier: plus

[High impact] The PR reaches shared request, permission, AI, and developer-tool workflows.

The PR is not ready to merge because existing published AI settings can raise the remote download limit from 32 MiB to 32 GiB.

Fix All in Claude CodeFindings

  1. P1 Security Published download limits grow ▶
  2. P2 Check that database calls stop ▶

Summary

Adds forgery checks for QUERY requests and syncs package behavior, documentation, and tests.

  • Web routes check the origin and token for QUERY requests.
  • Remote attachment limits use kilobytes and reject oversized responses early.
  • Permission lookups use stored-value indexes when they match caller-visible values.
  • Role checks respect the requested guard when given a role model.
  • Wayfinder can generate route binding types without a database.
  • Telescope query previews use the connection's SQL dialect when supported.
  • Gemini conversation turns put thought steps before their text.
  • Wayfinder generates a query method for QUERY routes.
  • MCP docs explain how users connect accounts for client tool calls.
  • Signed URL guidance tells callers to read signed values from the query string.
  • AI tool docs describe file moves and Groq's tool limits.
  • Blade guidance explains that a stack only includes content pushed before it renders.
  • Benchmark runs no longer need an extra idle-confirmation flag.
  • Socket fixtures pass read timeouts by name.
  • Tests cover Scout and Saloon behavior already present in Hypervel.

Reviews (2) · Last reviewed commit: "Test that a compressed download is limit..." · Reviewed by Greptile

Comment on lines +41 to +47
$kilobytes = config()->get('ai.remote_files.max_size', static::MAX_KILOBYTES);

if ($maxSize !== null && (! is_int($maxSize) || $maxSize <= 0)) {
if ($kilobytes !== null && (! is_int($kilobytes) || $kilobytes <= 0)) {
throw new InvalidArgumentException('The remote file maximum size must be a positive integer or null.');
}

$limit = $kilobytes === null ? null : $kilobytes * 1024;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security Published download limits grow

Existing published config/ai.php files keep their old byte-based ai.remote_files.max_size value. Multiplying that value by 1024 turns the previous 32 * 1024 * 1024 setting into a 32 GiB limit, not 32 MiB. Remote attachments then read the full body into memory, so an untrusted attachment can exhaust worker memory or temporary storage.

Keep old settings safe through an explicit unit migration or a new setting, and tell existing users how to migrate.

How this was verified: Published application settings override package defaults, and the retained value is multiplied by 1024 before both download checks use it.

Fix in Claude Code Fix in Codex

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Declining. The byte-valued setting was never released: the AI package isn't in any tagged release, and the setting only existed on the unreleased 0.4 branch, which makes breaking changes without compatibility layers. Upstream reads this key in kilobytes, so there's no published value to migrate. The Laravel porting guide covers the different default.

Comment thread src/permission/src/Traits/HasRoles.php
Comment thread src/telescope/resources/js/screens/queries/preview.test.js
Comment on lines +72 to +76
public function testSkippingTheDatabaseReadsModelDocblocks(): void
{
$this->assertStringContainsString('post: number', $this->generate());

$this->assertStringContainsString('post: string', $this->generate(skipDatabase: true));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Check that database calls stop

This test proves that --skip-database chooses docblocks over the schema, but not that it avoids a database call. A change that tries the connection and then discards the result would still pass, yet could delay every database-free build until connection attempts time out.

Add a model connection spy and assert it is never called in skip mode.

Knowledge Base Used: Wayfinder route generation

Fix in Claude Code Fix in Codex

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Declining. getColumns() returns before calling getConnection() when the option is set, and this test already fails without that check, since the schema's integer key would win over the docblock. A connection spy would only guard against a hypothetical rewrite.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That’s fair. The observable assertion is sufficient here: without the skipDatabase branch, the schema’s integer key takes precedence and the test fails, while the generated string type proves the database-derived metadata was bypassed. A connection spy would only protect against an implementation rewrite that still made an unnecessary call, so I’m withdrawing this comment.

Comment thread tests/Benchmarks/Permission/Fixtures/PermissionLookupBenchmark.php
Since the spatie/laravel-permission#2969 port, getPermissions() and
getRoles() send enum lookup values to filterModels(), because the name
and key indexes only take strings and integers. filterModels() only
normalized the model's name, so an enum value never matched:
getPermissions(['name' => Enum::Writer, 'guard_name' => 'web']) and a
name-only enum lookup both returned nothing, although the previous
name and guard index matched them.

attributeMatches() now compares enums by their values on both sides,
as Laravel's Collection::where() does, and the name-only special case
is removed. Enum-returning name accessors still match enum and string
values. findByName() and findById() already normalize their arguments,
so the indexed lookups are unchanged.

Add a regression test for a plain permission looked up by enum, with
and without a guard, and for the enum-accessor fixture role looked up
by enum and by string. The Permission suite, formatting and static
analysis pass.
The spatie/laravel-permission#2978 port made hasRole() match a Role
model by key and the requested guard, and a single model passed to
hasAllRoles() delegates to it. A Role model inside an array or
collection was still mapped to its name, so a user with the web
testRole passed hasAllRoles([$adminTestRole]). hasExactRoles() mapped
models to names before calling hasAllRoles(), so it matched the same
way, for a single model too. Upstream has the same defect.

hasAllRoles() now checks role models through hasRole() and compares
only the remaining values by name. hasExactRoles() passes models
through unchanged and keeps its partition check before the count
comparison, so a role from another partition still throws when the
counts differ.

Add a regression test with positive controls; removing either fix
makes it fail. The Permission suite passes.
The mixed-20 scenario cycles over the last 20 permission names, and
the benchmark README documents a minimum BENCH_COUNT of 20. A smaller
value failed partway through with a lookup of bench--1. Check the
value where it is read, before inserting rows or timing anything.
The laravel/docs#11413 warning says a signature only covers the URL's
path and query string. Absolute signatures, the default, also cover
the scheme and host, since hasCorrectSignature() signs the full URL;
only relative signatures leave them out. Say that a signature covers
the URL, including its query string.
The comment said QUERY stays verified because it carries a body, but a
GET request can carry a body too. The reason is that method override
lets a cross-site form POST arrive as QUERY. Reword the comment to say
so.
The laravel/scout#1014 whereNotIn assertion only checks that the
injected record is missing, because upstream's suite seeds many
records. This test indexes two records, so assert the exact result,
which also fails when the filter drops records it should keep. The
test passes against Meilisearch.
The laravel/telescope#1770 tests passed with driverAliases emptied,
since the alias test called sqlDialect() directly and the PostgreSQL
test only checked that @> remained. They also passed when the preview
showed the raw query, since the SQLite test only checked for words in
it. Assert formatQuery()'s exact output for pgsql and sqlsrv, and the
exact formatted SQLite preview, next to upstream's assertions. npm
test passes.
laravel/ai#1139 rejects a response whose Content-Length exceeds the
limit before reading its body. The transport removes a compressed
response's Content-Length before on_headers runs, so only the decoded
size counts. Add a download size case whose gzip body is larger than
the limit while its decoded body fits, so it must be accepted.
Checking the encoded length in on_headers makes it fail.
@binaryfire
binaryfire merged commit 0f887d0 into 0.4 Oct 20, 2026
53 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