Skip to content

The target manager HTTP API returns 500 for invalid input instead of a useful error #3394

Description

@adamtheturtle

What happens

The target manager container's HTTP API is the documented way for Docker users to configure the mock — docs/source/docker.rst shows a curl call against POST /cloud_databases and documents the accepted JSON fields. That API does not validate its input, so a wrong value produces a 500 rather than a useful error.

Probing it directly:

valid empty body                 -> 201
bad state_name                   -> 500
bad state_name casing            -> 500
bad database_type_name           -> 500
request_rate_limits malformed    -> 500
request_rate_limits wrong type   -> 500
request_quota is a string        -> 500
delete unknown database          -> 404
target on unknown database       -> 500
vumark target unknown db         -> 500

The underlying exceptions:

KeyError: 'inactive'                              # state_name
KeyError: 'project_inactive'                      # state_name, wrong case
KeyError: 'cloud'                                 # database_type_name
KeyError: 'window_seconds'                        # request_rate_limits entry missing a key
ValueError: not enough values to unpack           # target on an unknown database
beartype...BeartypeCallHintParamViolation: ... RequestRateLimits.from_dict ...
beartype...BeartypeCallHintParamViolation: ... CloudDatabase.__init__() parameter request_quota ...

create_cloud_database does States[state_name] and DatabaseType[database_type_name] on unvalidated input, passes unvalidated values straight into CloudDatabase(...) where beartype rejects them, and calls RequestRateLimits.from_dict on whatever was supplied.

Why it matters

{"state_name": "inactive"} is a very easy thing to send. docs/source/docker.rst documents the valid values as WORKING, PROJECT_INACTIVE, PROJECT_SUSPENDED and PROJECT_HAS_NO_API_ACCESS, but a user who lowercases one gets an empty 500 with nothing naming the field or the accepted values. The same applies to database_type_name and to any request_rate_limits object which is not exactly right — and request_rate_limits has the most structure of any field here, so it is the one most likely to be got wrong.

This API is also the piece of the project a non-Python user interacts with most directly. They cannot read the States enum to work out what was wrong.

The handling is not uniformly missing, which is the encouraging part: delete_cloud_database and delete_vumark_database already catch the not-found case and return 404. The pattern exists; it is just not applied to the create routes.

Suggested resolution

Validate the request body and return a 400 which names the offending field and the accepted values.

The project already depends on pydantic-settings, and pydantic is already configured for mypy in pyproject.toml, so declaring a pydantic model for the create-database body would give field-level errors, correct types and a serialisable error response without new dependencies. That also removes the hand-written request_json.get(field, random_database.field) chain, which is currently how defaults are applied.

create_target and create_vumark_target should return 404 for an unknown database name, matching what delete_cloud_database already does, rather than letting the single-element unpack raise. Those two are reached by the VWS container as well as by users, so a clear 404 also makes a misconfigured deployment easier to diagnose.

Related to #3392 in kind — unvalidated input reaching code which assumes it is well formed — but on a different API, with a different audience, and a different fix.

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