Part of an ActiveAgent + actionagent dashboard functional review (multi-agent, adversarially verified). Severity: 🟠 Major.
ActionAgent.encrypt_credentials defaults to true, so ApiKey/ProviderKey declare encrypts, but the engine ships no fallback for a host that hasn't run rails db:encryption:init — including its own reference host, test/dummy. Result: the advertised MCP flow (Settings → API Keys → connect a client to <mount>/mcp) is dead on arrival and every Settings credential write 500s on a bare mount. The app carried a fallback initializer that was never ported.
Findings
Engine MCP facade and API-key issuance 500 on any host without Active Record encryption keys; app-side fallback initializer never ported
- Where:
actionagent/lib/action_agent/engine.rb:46 · severity: major · kind: drift · repo: activeagent
- What breaks: The engine's advertised MCP flow (Settings -> API Keys -> connect an MCP client to /mcp with a Bearer key) is dead on arrival on any host that has not run
rails db:encryption:init — including the engine's own reference host, test/dummy. ApiKey declares encrypts :token, deterministic: true gated only on ActionAgent.encrypt_credentials, which defaults to true (lib/action_agent.rb:395), and the dummy configures no encryption keys (no initializer; config/initializers contains only content_security_policy.rb and filter_parameter_logging.rb). POST /api/api_keys raises Missing Active Record encryption credential: active_record_encryption.deterministic_key -> HTML 500, so no key can ever be created; and because ApiKey.authenticate's find_by(token:) also encrypts the lookup value, EVERY authenticated POST /mcp raises the same error inside the authenticate_api_key! before_action (mcp_controller.rb:74-86), escaping the action's rescue and returning an HTML 500 instead of any JSON error. The platform app fixed exactly this with config/initializers/active_record_encryption.rb (derives fallback keys from the app secret, ENV override), which is why /mcp works on activeagents.ai; the engine/dummy never got the equivalent — drift, engine behind. Also drift: the app has test/controllers/api/mcp_controller_test.rb (10 cases covering auth, tools/list, tools/call, quotas, cross-account isolation, resources/read); the engine has zero tests for its MCP facade.
- Evidence: Live:
curl --noproxy localhost -X POST http://localhost:3001/activeagents/api/api_keys -H 'Content-Type: application/json' -d '{"name":"mcp-probe"}' -> 500 HTML, exception message "Missing Active Record encryption credential: active_record_encryption.deterministic_key". curl -X POST http://localhost:3001/activeagents/mcp -H 'Authorization: Bearer aa_testtoken123' ... -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}' -> 500 HTML with the same message (no-auth request correctly returns 401 JSON). Code: actionagent/app/models/action_agent/api_key.rb:19 (encrypts ... if ActionAgent.encrypt_credentials), actionagent/lib/action_agent.rb:395 (@encrypt_credentials = true default), actionagent/app/controllers/action_agent/api/mcp_controller.rb:74-86 (authenticate in before_action, outside create's rescue). Sibling fix that never crossed over: activeagents config/initializers/active_record_encryption.rb:13-20 — the same probe against the app worked (POST /api/api_keys returned a token; full JSON-RPC session verified live at :3000). Test drift: activeagents test/controllers/api/mcp_controller_test.rb exists (10 tests); grep -rl 'jsonrpc\|MCPController' actionagent/test/ matches nothing.
- Suggested fix: Port the app's fallback into the engine: add an engine initializer in actionagent/lib/action_agent/engine.rb (e.g. "action_agent.active_record_encryption", before :load_config_initializers completes on the host) that, when ActionAgent.encrypt_credentials is true and app.config.active_record.encryption.primary_key/deterministic_key/key_derivation_salt are all unset, derives them via Rails.application.key_generator.generate_key("active_record_encryption.", 32).unpack1("H*") with ACTIVE_RECORD_ENCRYPTION_* ENV overrides — mirroring activeagents/config/initializers/active_record_encryption.rb:13-20 (never override host-provided keys). Alternatively/additionally have the install generator write that initializer into the host, and add one to test/dummy. Defense in depth: rescue ActiveRecord::Encryption::Errors (Configuration) in ApiKey.authenticate and Api::ApiKeysController#create to return an actionable JSON error ("Active Record encryption is not configured; run rails db:encryption:init or set ActionAgent.encrypt_credentials = false") instead of an HTML 500. Port activeagents/test/controllers/api/mcp_controller_test.rb (10 cases) to actionagent/test/.
Every Settings credential write 500s on the engine's dummy host: Active Record encryption keys are never configured
- Where:
test/dummy/config/environments/development.rb:3 · severity: major · kind: bug · repo: activeagent
- What breaks: ActionAgent.encrypt_credentials defaults to true (actionagent/lib/action_agent.rb:395), which makes ApiKey
encrypts :token, deterministic: true (api_key.rb:19) and ProviderKey encrypts :credential (provider_key.rb:23), but the engine's own reference host test/dummy has no active_record.encryption keys anywhere (no initializer, nothing in config/environments). Result: on the running dummy, GET index endpoints work but POST /api/api_keys and POST /api/provider_keys both raise ActiveRecord::Encryption::Errors::Configuration — an unhandled 500 returning an HTML exception page. The whole Settings -> API Keys / Provider Keys create flow is dead in the shipped dummy (SettingsView surfaces only the generic 'Could not create the API key.'), the token-shown-once flow cannot be exercised at all, and any host app that skips rails db:encryption:init hits the same raw 500 instead of an actionable API error. The app side works (encryption configured): live create returned the full token once, masked thereafter, and the token authenticated telemetry ingest.
- Evidence: Live:
curl --noproxy localhost -X POST http://localhost:3001/activeagents/api/api_keys -H 'Content-Type: application/json' -d '{"name":"review-probe"}' returns the Rails diagnostics page 'ActiveRecord::Encryption::Errors::Configuration in ActionAgent::Api::ApiKeysController#create (Missing Active Record encryption credential: active_record_encryption.deterministic_key)'; same POST to /activeagents/api/provider_keys returns HTTP 500 'Missing Active Record encryption credential: active_record_encryption.primary_key'. Code: actionagent/lib/action_agent.rb:395 (@encrypt_credentials = true default), actionagent/app/models/action_agent/api_key.rb:19, actionagent/app/models/action_agent/provider_key.rb:23; grep of /home/user/activeagent/test/dummy/config finds zero encryption configuration. Contrast (working app): POST http://localhost:3000/api/api_keys returned 201 with token aa_jfke…Sihk shown once, index masked, and Bearer use on POST /api/v1/traces returned 202.
- Suggested fix: Two-part fix: (1) Make the dummy host exercise the default encrypted path by adding Active Record encryption keys to test/dummy config (e.g. config.active_record.encryption.primary_key/deterministic_key/key_derivation_salt with fixed dev-only values in development.rb, mirroring what Rails' db:encryption:init would produce). (2) In actionagent/app/controllers/action_agent/api/base_controller.rb, add
rescue_from ActiveRecord::Encryption::Errors::Base returning a JSON 500/503 that tells operators to run rails db:encryption:init or set ActionAgent.encrypt_credentials = false — matching the guidance the install generator already prints (install_generator.rb:112-113) — so misconfigured hosts get an actionable API error instead of an HTML diagnostics page the SettingsView collapses into a generic failure message.
Verification
Each finding above was produced by a dedicated per-feature review agent, then confirmed by an independent adversarial verifier (all rated high-confidence; zero rejected in this set). File:line citations are against the current main/HEAD of each repo; many were reproduced live against a booted dashboard.
ActionAgent.encrypt_credentialsdefaults to true, soApiKey/ProviderKeydeclareencrypts, but the engine ships no fallback for a host that hasn't runrails db:encryption:init— including its own reference host, test/dummy. Result: the advertised MCP flow (Settings → API Keys → connect a client to<mount>/mcp) is dead on arrival and every Settings credential write 500s on a bare mount. The app carried a fallback initializer that was never ported.Findings
Engine MCP facade and API-key issuance 500 on any host without Active Record encryption keys; app-side fallback initializer never ported
actionagent/lib/action_agent/engine.rb:46· severity: major · kind: drift · repo:activeagentrails db:encryption:init— including the engine's own reference host, test/dummy. ApiKey declaresencrypts :token, deterministic: truegated only on ActionAgent.encrypt_credentials, which defaults to true (lib/action_agent.rb:395), and the dummy configures no encryption keys (no initializer; config/initializers contains only content_security_policy.rb and filter_parameter_logging.rb). POST /api/api_keys raisesMissing Active Record encryption credential: active_record_encryption.deterministic_key-> HTML 500, so no key can ever be created; and because ApiKey.authenticate's find_by(token:) also encrypts the lookup value, EVERY authenticated POST /mcp raises the same error inside the authenticate_api_key! before_action (mcp_controller.rb:74-86), escaping the action's rescue and returning an HTML 500 instead of any JSON error. The platform app fixed exactly this with config/initializers/active_record_encryption.rb (derives fallback keys from the app secret, ENV override), which is why /mcp works on activeagents.ai; the engine/dummy never got the equivalent — drift, engine behind. Also drift: the app has test/controllers/api/mcp_controller_test.rb (10 cases covering auth, tools/list, tools/call, quotas, cross-account isolation, resources/read); the engine has zero tests for its MCP facade.curl --noproxy localhost -X POST http://localhost:3001/activeagents/api/api_keys -H 'Content-Type: application/json' -d '{"name":"mcp-probe"}'-> 500 HTML, exception message "Missing Active Record encryption credential: active_record_encryption.deterministic_key".curl -X POST http://localhost:3001/activeagents/mcp -H 'Authorization: Bearer aa_testtoken123' ... -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'-> 500 HTML with the same message (no-auth request correctly returns 401 JSON). Code: actionagent/app/models/action_agent/api_key.rb:19 (encrypts ... if ActionAgent.encrypt_credentials), actionagent/lib/action_agent.rb:395 (@encrypt_credentials = true default), actionagent/app/controllers/action_agent/api/mcp_controller.rb:74-86 (authenticate in before_action, outside create's rescue). Sibling fix that never crossed over: activeagents config/initializers/active_record_encryption.rb:13-20 — the same probe against the app worked (POST /api/api_keys returned a token; full JSON-RPC session verified live at :3000). Test drift: activeagents test/controllers/api/mcp_controller_test.rb exists (10 tests);grep -rl 'jsonrpc\|MCPController' actionagent/test/matches nothing.Every Settings credential write 500s on the engine's dummy host: Active Record encryption keys are never configured
test/dummy/config/environments/development.rb:3· severity: major · kind: bug · repo:activeagentencrypts :token, deterministic: true(api_key.rb:19) and ProviderKeyencrypts :credential(provider_key.rb:23), but the engine's own reference host test/dummy has no active_record.encryption keys anywhere (no initializer, nothing in config/environments). Result: on the running dummy, GET index endpoints work but POST /api/api_keys and POST /api/provider_keys both raise ActiveRecord::Encryption::Errors::Configuration — an unhandled 500 returning an HTML exception page. The whole Settings -> API Keys / Provider Keys create flow is dead in the shipped dummy (SettingsView surfaces only the generic 'Could not create the API key.'), the token-shown-once flow cannot be exercised at all, and any host app that skipsrails db:encryption:inithits the same raw 500 instead of an actionable API error. The app side works (encryption configured): live create returned the full token once, masked thereafter, and the token authenticated telemetry ingest.curl --noproxy localhost -X POST http://localhost:3001/activeagents/api/api_keys -H 'Content-Type: application/json' -d '{"name":"review-probe"}'returns the Rails diagnostics page 'ActiveRecord::Encryption::Errors::Configuration in ActionAgent::Api::ApiKeysController#create (Missing Active Record encryption credential: active_record_encryption.deterministic_key)'; same POST to /activeagents/api/provider_keys returns HTTP 500 'Missing Active Record encryption credential: active_record_encryption.primary_key'. Code: actionagent/lib/action_agent.rb:395 (@encrypt_credentials = true default), actionagent/app/models/action_agent/api_key.rb:19, actionagent/app/models/action_agent/provider_key.rb:23; grep of /home/user/activeagent/test/dummy/config finds zero encryption configuration. Contrast (working app): POST http://localhost:3000/api/api_keys returned 201 with token aa_jfke…Sihk shown once, index masked, and Bearer use on POST /api/v1/traces returned 202.rescue_from ActiveRecord::Encryption::Errors::Basereturning a JSON 500/503 that tells operators to runrails db:encryption:initor set ActionAgent.encrypt_credentials = false — matching the guidance the install generator already prints (install_generator.rb:112-113) — so misconfigured hosts get an actionable API error instead of an HTML diagnostics page the SettingsView collapses into a generic failure message.Verification
Each finding above was produced by a dedicated per-feature review agent, then confirmed by an independent adversarial verifier (all rated high-confidence; zero rejected in this set). File:line citations are against the current
main/HEAD of each repo; many were reproduced live against a booted dashboard.