Skip to content

A subdomain with no app returns 200 with the web terminal instead of an error #230

Description

@ClaydeCode

What happens

A request to any subdomain of a shard that has no app behind it returns HTTP 200 with the web terminal's page, rather than an error saying the app does not exist.

Observed on a live trial shard, after its apps had been uninstalled:

$ curl -sS -o /dev/null -w '%{http_code} %{size_download}\n' https://nonexistent-app.88wxn2.freeshard.cloud/
200 904
$ curl -sS -o /dev/null -w '%{http_code} %{size_download}\n' https://88wxn2.freeshard.cloud/
200 904

Same status, same byte count, same body: the shard root and a made-up app name are indistinguishable.

Why

compile_config gives every installed app a router matched on its exact host, and the web terminal a catch-all with no host constraint at all:

https://github.com/FreeshardBase/freeshard/blob/main/shard_core/service/traefik_dynamic_config.py#L66-L72

"web-terminal": t.HttpRouter(
    rule="PathPrefix(`/`)",
    priority=1,
    entryPoints=[http_entrypoint],
    service="web-terminal",
    tls=make_http_cert_resolver(portal),
),

An app's Host(...) router wins whenever it exists, so this only shows up when it does not: a name that was never installed, an app in ERROR or still installing (NOT_ROUTABLE_STATUS), or the window while the dynamic config is being rewritten (#228). In all of those the request falls through to the terminal.

Why it matters

For a person, a wrong or stale app link silently shows the terminal instead of saying what is wrong, and a bookmarked app that later failed to install looks like it "went back to the home screen".

For anything automated it is worse, because it is a 200 that means the opposite of success. It defeated the app-update smoke test in the app-repository: an app with no route at all was recorded as started. That check now fingerprints the terminal page and rejects a body matching it, but that is a workaround for one caller, and every other client — a browser, a monitor, a peer shard — still gets a success for a missing app.

Suggested behaviour

A host that matches no app should produce a clear error rather than the terminal. Two parts, either of which helps on its own:

  1. Constrain the web-terminal router to the shard's own host, e.g. rule = f"Host({portal.domain}) && PathPrefix(/)", so it stops answering for arbitrary subdomains.
  2. Add a lowest-priority fallback router for HostRegexp({subdomain:[a-z0-9-]+}.{portal.domain}) that returns a 404 page saying the app is not installed. The splash machinery in shard_core/web/internal/app_error.py already renders app-scoped error pages, so the fallback can reuse it and tell the difference between "not installed", "installing" and "failed to install".

Worth deciding alongside #228, since both are about what a request gets when an app's router is briefly or permanently absent.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions