hero_assistance _admin tab calls via /admin/rpc hit _server instead of _admin #109
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_router#109
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
When the hero_assistance admin dashboard is loaded through hero_router at /admin/, its embedded operator-side RPCs (the ui.* namespace, served locally by hero_assistance_admin) return Method not found. The same calls succeed when the dashboard is loaded by connecting directly to hero_assistance_admin's admin.sock. Looking at the request path, /admin/rpc through the router is being forwarded to hero_assistance_server's rpc.sock rather than hero_assistance_admin's admin.sock, which has no implementation of ui.* methods. The expected behavior is that //admin/rpc routes to that service's admin.sock so the local ui.* dispatch keeps working through the router. Reproduce by running lab service hero_assistance --start, opening hero_router, and clicking the Admin tab on the hero_assistance dashboard.
Reproduced today by clicking the Admin tab in
hero_assistance_admin, which firesui.getAccessListand rendersFailed to load access list: Method not found: ui.getAccessList. The same fall-through is implied for the other ADMIN_SECRETS RPCs that share theui.*prefix. The byte-passthrough/rpcproxy on_admin(incrates/hero_assistance_admin/src/main.rs, the proxy that backs both<hero-api-docs spec-url="/hero_assistance/admin/openrpc.json" rpc-url="/hero_assistance/admin/rpc">and<hero-logs-viewer rpc-url="/hero_assistance/admin/rpc">) forwards every request straight to_server, includingui.*methods that_serverhas no handler for. The fix is to add a prefix check in that proxy so request bodies whosemethodfield begins withui.dispatch locally on_admin(against the five ADMIN_SECRETS handlers) before falling through to the_serverpassthrough.Despite the title's phrasing, the load-bearing change is in
lhumina_code/hero_assistance's_admincrate, not inhero_router: the router does deliver/hero_assistance/admin/rpcto_admin'sadmin.sockcorrectly (the same socket is also reachable at/hero_assistance/ui/). Recommend re-filing this issue (or moving its body) tolhumina_code/hero_assistanceand closing here as not-a-router-bug.Correcting my earlier comment above. Re-investigating today against the current
lhumina_code/hero_assistancedevelopmentHEAD (49ea76a7), the localui.*interception on_admin's/rpcproxy actually IS in place. It sits incrates/hero_assistance_admin/src/routes.rslines 198-257 (therpc_proxyfunction parses the JSON-RPC envelope, matchesmethod.starts_with("ui."), and dispatches viaui_rpc::try_dispatchatui_rpc.rsline 52 before the byte-passthrough forward to_server). Direct curl confirms this works:The router-fronted path however explicitly targets the wrong socket. hero_router's own 502 response body names the destination it attempted:
Note the named destination:
rpc.sock, notadmin.sock. The/admin/rpcrequest never reaches_admin's interception logic because hero_router routes it to_server's rpc.sock by some component-resolution rule that treatsadmindifferently from sibling components. Theappcomponent routes correctly under the same shape, which makes the contrast clean:/hero_assistance/app/rpcapp.sock/hero_assistance/app/healthapp.sock/hero_assistance/admin/rpcrpc.sockadmin.sock/hero_assistance/admin/healthui.sock)admin.sock/hero_assistance/admin/static/*ui.sock)admin.sock/hero_assistance/rpc/rpcrpc.sockSo
/admin/*routing is half pre-admin.socklegacy (looks up the oldui.sockfor non-/rpcsubpaths, see hero_router error bodySocket 'ui.sock (admin)' not found for 'hero_assistance') and half hardcoded to the service-levelrpc.sockfor/rpcspecifically. Both branches of theadmincomponent resolution need attention. The fix is in hero_router; my earlier recommendation to re-file under hero_assistance was wrong on both of its load-bearing premises and should be retracted. The original issue body framing is correct as written.Reproduction details:
hero_assistance --startbrings the three daemons up; the customer UI at/hero_assistance/app/works correctly; the operator admin at/hero_assistance/admin/fails. Note that the_adminand_uidaemons also restart-loop on a separate health-check bug filed at lhumina_code/hero_assistance#21, which is independent of this routing issue but means reproduction needs to land curl probes within the brief alive window after each restart.Closed by
0682283ondevelopment(squash via local merge + direct push; remotedevelopment_mikis held by a stale branch from another author so no PR was opened, matching the workaround used at the prior hero_router fix).The fix is in
crates/hero_router/src/server/routes.rs:service_proxy_innerno longer rewritesPOST /<service>/admin/rpcto forward torpc.sock. The sibling-shortcut now applies only to the legacyuiwebname./admin/rpcfalls through to the existing"admin"match arm which dispatches toadmin.sockdirectly viaresolve_ui_socket. The admin-local proxy onhero_admin_lib(the byte-passthrough/rpcproxy onadmin.sock) then interceptsui.*methods locally and forwards everything else to_server'srpc.sockvia its own byte-passthrough.The shortcut decision is extracted into a pure
sibling_shortcut_rewritehelper with four unit tests pinning:uishortcut still works,adminno longer takes it, sibling webnames never took it,uiwith non-rpc paths never took it. The context-0 restriction onadminis preserved unchanged (now lives solely on the"admin"match arm).Live verify against
lhumina_code/hero_assistancepost-install:Byte-identical to what the same call returns when sent directly to
admin.sock. The control test against/hero_assistance/rpc/rpc system.pingstill returns{"pong":true}HTTP 200 (no regression on the regular RPC path).As a side effect this also fixes
/<service>/admin/health,/<service>/admin/static/*, and/<service>/admin/openrpc.jsonwhich previously returnedSocket 'ui.sock (admin)' not foundbecause the legacyui.socklookup is no longer the canonical admin path.