Skip to content

hosting: a resolver returning TenantResolution(None, source) leaves tenant_source set with no tenant bound #424

Description

@antosubash

Problem

request.state.tenant_source is documented as None when no tenant was bound, and the built-in paths honour that. The (tenant_id, source) tuple path in _normalise and the tenants module's resolver both blank the source when tenant_id is None. A custom resolver that returns a TenantResolution directly skips that: _normalise passes the object through unchanged.

if isinstance(result, TenantResolution):
    return result          # TenantResolution(None, "header") stays source="header"

So a resolver returning TenantResolution(None, "header", ("X-Tenant-ID",)) leaves the request with tenant_id=None, tenant_source="header". Code that branches on tenant_source (for example to choose between Vary: <header> and Cache-Control: private, the use case in #367) then believes a tenant was resolved from the header when none was.

Reproduction

Found by independent QA on #384 and still on main at 7db61a0 (framework/hosting/simple_module_hosting/_tenant.py, _normalise): register app.state.tenant_resolver returning TenantResolution(None, "header", ("X-Tenant-ID",)) and read request.state in a route. It shows tenant_id=None, tenant_source='header'.

Expected

_normalise applies the same rule to every result shape: when tenant_id is None, the source is None. The vary names are kept, since the header's absence was still an input. For example:

if isinstance(result, TenantResolution):
    return result if result.tenant_id is not None else TenantResolution(None, None, result.vary)

Tests to add

  • A resolver returning TenantResolution(None, "header", ("X-Tenant-ID",)) → tenant_source is None, and the response still has Vary: X-Tenant-ID.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions