Coerce container-valued query params and scrub handoff state on read - #456
Merged
TonsOfFun merged 1 commit intoSep 16, 2026
Merged
Conversation
Three hardenings the hosted platform made to its own copy of the dashboard controllers in September, ported to the engine so a host that mounts it gets the same behaviour. A query value can arrive as a container (`minutes[]=1&minutes[]=2`, or `page[x]=1`), and neither Array nor ActionController::Parameters responds to `to_i`. Every list the dashboard paginates or windows read those params directly and turned a malformed query into a 500. Api::BaseController gains integer_param and clamped_param: a multi-valued param means its first value, a nested object floors to the default. Applied to agent runs, agent analytics, the account analytics, interactions and session recordings. Sandboxes#compare read `providers` as a list. A bare string or a nested object raised NoMethodError; it is now a 400. A recording's show response returned the handoff state — a copy of the visitor's cookies and web storage — unscrubbed, both as its own key and nested inside metadata, while every other read path redacted. Both are now stripped of cookies, session_storage and local_storage; only #handoff returns them, to the owner, when they continue the session. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DkXcH6XVKyD5wYnpLuH9iE
TonsOfFun
pushed a commit
to activeagents/activeagents
that referenced
this pull request
Sep 16, 2026
The platform's own copy of the dashboard — the React app under app/javascript, the API controllers it read, and the models and services behind them — is replaced by the actionagent engine mounted at /dashboard, configured for this platform in config/initializers/action_agent.rb: multi-tenant, sessions resolved from this app's cookie, agents per user and keys and traces per account, plan quotas and usage metering, per-account provider credentials, trace retention by plan, and the cloud sandbox backends this platform operates. This app keeps what a hosted product has and a self-hosted install does not: accounts and sessions, plans and billing, the admin console, benchmarks, the in-container sandbox runner, trace ingest at /v1/traces on its own TelemetryTrace subclass, and the MCP endpoint at /mcp. Merges claude/activeagents-local-engine-ky54n7 (the August extraction) onto current main and repoints the gems at the engine's repository. Every model, service and serializer the engine now owns is an alias of the engine's class, so existing references keep working. The September security fixes main made to the deleted controllers are carried by the engine, whose own tests cover them; the three it lacked (container-valued query params, compare's providers validation, the handoff-state scrub on show) are ported in activeagents/activeagent#456, which the Gemfile pins until it merges. Tests that exercised those controllers now do so through the mount at /dashboard/api. Two behaviours change with the engine's contract. It authenticates every endpoint, so an anonymous caller gets a 401 (or, in a browser, this app's sign-in page) rather than a scoped 404, and sandboxes no longer have an anonymous demo pool. Compare meters one execution per provider, as run does. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DkXcH6XVKyD5wYnpLuH9iE
7 tasks
Contributor
Author
|
Retargeted to One thing to add before this merges: a changelog entry. On this branch the section is |
TonsOfFun
pushed a commit
that referenced
this pull request
Sep 16, 2026
The merge of #456 brings the container-valued query parameter coercion, the compare providers validation and the recording show scrub onto the release line; the 1.6.2 section now lists them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DkXcH6XVKyD5wYnpLuH9iE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three hardenings the hosted platform (activeagents/activeagents) made to its own copy of the dashboard controllers in September, ported to the engine so a host that mounts it gets the same behaviour. Needed by activeagents/activeagents#132, which replaces that copy with the mounted engine.
minutes[]=1&minutes[]=2, orpage[x]=1), and neither Array norActionController::Parametersresponds toto_i.Api::BaseControllergainsinteger_param/clamped_param(a multi-valued param means its first value; a nested object floors to the default), applied to agent runs, agent analytics, account analytics, interactions and session recordings.sandboxes#comparevalidatesproviders. A bare string or a nested object used to raiseNoMethodError; it is now a 400.session_recordings#showscrubs the handoff state. The response returned the visitor's cookies and web storage unscrubbed, both as its own key and nested insidemetadata, while every other read path redacted. Both are stripped ofcookies,session_storageandlocal_storage; only#handoffreturns them, to the owner.Test plan
actionagent/test/param_coercion_test.rbcovers each coerced endpoint and thecomparerejectionsession_recording_privacy_test.rbgains a nested handoff-state casegemfiles/rails8.gemfile: 405 runs, 0 failures🤖 Generated with Claude Code
https://claude.ai/code/session_01DkXcH6XVKyD5wYnpLuH9iE
Generated by Claude Code