Skip to content

id(web): web_interface_from_app_toml still accepts route/socket shapes that panic axum — invalid capture syntax and renamed-capture conflicts with host routes pass the #4779 checks #4795

Closed

Description

@dezren39

Problem

web_interface_from_app_toml (pkgs/id/src/web/app_interface.rs:214) still accepts route/socket values that panic when the router is built — the #4779 fix covered the leading-slash check, exact host-route collisions (HOST_RESERVED_ROUTES, app_interface.rs:105-150), the /api/world/* prefix, and route==socket, but it never validates the path's axum route syntax or its pattern-level conflicts with host routes.

Two verified classes survive the parser and panic in create_router_inner / world_routes_at:

  1. Syntactically invalid axum paths — unbalanced or empty captures: /foo/{bar, /foo/{}, /foo/{*}, and the legacy colon segment /:.
  2. Pattern conflicts with host routes that are not exact duplicates — /edit/{*other} (same shape as the host's /edit/{*name} under a different wildcard name) and /hash/{other} (same shape as /hash/{hash} under a different capture name). The reserved check is exact-string only, so neither matches it.

The panic sites are the registrations the parser is supposed to make safe: pkgs/id/src/web/routes.rs:322 (.route(&world_route, get(world_page_handler)), after every host route has already been registered) and pkgs/id/src/web/world_ws.rs:60 (world_routes_at(socket) registers the socket the same way, and the socket side of web_interface_from_app_toml has exactly the same missing syntax/conflict check).

Evidence (verified this run; corrected — see the correction comment)

Laptop probe (worktree at origin/main 2897a21, temporary unit test in app_interface.rs tests, web/dist placeholder copied from the primary clone, worktree removed after; log /tmp/probe-scan12c.log on the laptop, read back independently after the run): for each candidate, web_interface_from_app_toml was called, then the candidate was registered on an axum Router after the host routes /, /files, /edit/{*name}, /hash/{hash}, /api/files — the same registration create_router_inner performs.

PROBE route="/foo/{bar"       parsed_ok=true axum_panics=true
PROBE route="/foo/{}"          parsed_ok=true axum_panics=true
PROBE route="/foo/{*}"         parsed_ok=true axum_panics=true
PROBE route="/edit/{*other}"   parsed_ok=true axum_panics=true
PROBE route="/hash/{other}"    parsed_ok=true axum_panics=true
PROBE route="/:"               parsed_ok=true axum_panics=true
PROBE route="/arena"           parsed_ok=true axum_panics=false   (control)
PROBE route="/{*path}"         parsed_ok=true axum_panics=false   (NOT claimed)
PROBE route="/foo/{bar}/{bar}" parsed_ok=true axum_panics=false   (NOT claimed)
PROBE route="/api/{name}"      parsed_ok=true axum_panics=false   (not claimed)
PROBE route="/foo//bar"        parsed_ok=true axum_panics=false   (not claimed)

The mimicked router is a subset of the real host table, so the real create_router_inner (which registers ~35 host routes before the app route) can only panic on a superset of these conflicts.

Why it matters

#4779's stated contract is that this parser rejects every binding that "would panic router construction" instead of aborting startup (its doc comment at app_interface.rs:205-213 says exactly that). An app author who writes a capture in their page route — a natural thing to try for a packaged app — or who mistypes a brace still crashes id serve at router construction with an axum panic, with no parse error naming the offending field. The reserved-list approach also remains a drift hazard for pattern conflicts: any future host route with a capture creates a new conflicting shape the exact-match list cannot see.

Acceptance criteria

  • web_interface_from_app_toml rejects, with a named WebInterfaceError variant, any route or socket that is not valid axum path syntax: unbalanced braces, empty capture/wildcard names, and legacy :-prefixed segments.
  • It also rejects a route/socket whose pattern conflicts with a host-registered pattern under a different capture/wildcard name (at minimum the /edit/{*name}, /view/{*name}, /hash/{hash}, /blob/{hash}, /assets/{*path}, /ws/collab/{doc_id} shapes), not only exact string duplicates of host routes.
  • Preferably the check is structural (parse the candidate's segments/captures and compare shapes against the host table) rather than a longer exact-string list, so future host capture routes cannot drift past it; if a list is kept, a test ties it to the routes registered in create_router_inner/world_http_routes.
  • Regression tests beside the existing id(web): web_interface_from_app_toml accepts route/socket values that panic in create_router_for_app (no leading-slash or host-route collision check) #4779 tests in app_interface.rs cover the six panicking shapes above for route, and at least the invalid-syntax shapes for socket; the valid control /arena + /ws/arena still parses.
  • cargo test --lib --features web app_interface passes (laptop or CI).

Dedup

Searched open and closed issues 2026-11-03 for web_interface, route panic, axum route syntax, capture/wildcard conflicts: the only covering item is #4779 (closed, fixed on main) — this issue is its residual gap: #4779's fix checks leading slash, exact reserved strings, /api/world/* prefix, and route==socket only, and its tests do not cover capture syntax or renamed-capture conflicts. Distinct from #4060 (parse_app_manifest's separate route/socket criteria).

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Nov 3, 2026
  2. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  3. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: handed off

    • Agent: opencode-claimant
    • Task: 6798 (repo-health-code-pilot)
    • Session / ID: ses_e5e5f901cffffe7d7MLKCnqsgj
    • Route: opencode-route/workhorse, agent build
    • Claiming worker: repo-worker-code
    • Status: session created, bound in the queue lane ledger/task row, checkpointed as launched, and task packet delivered.
  4. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · correction

  5. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · correction (queue)

  6. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 3, 2026
  7. added a commit that references this issue on Nov 3, 2026
  8. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    🤖 Agent note · triaged — CONFIRMED; fix already exists as PR #4803, shepherd task 7510 enqueued to land it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions