Three defaults expose more to HTTP clients than an app author would expect:
- Async task endpoints are global and unauthenticated (only when
async_funcs= is used). mk_app always adds add_global_task_endpoints (qh/app.py), so GET /tasks/ lists every task of every caller — including result, error and the full server traceback (qh/async_endpoints.py to_dict) — and DELETE /tasks/{id} has no ownership check. In a multi-user app one user can read or cancel another's results.
Plan: make the global listing opt-in (global_task_endpoints=False by default), never serialise tracebacks to clients (log them server-side), and add an optional task_owner(request) -> str hook that per-task routes check.
- Exception text is returned to the client by default:
detail=f"Error in {func.__name__}: {e}" (qh/endpoint.py, same pattern in qh/base.py, qh/core.py). Exception messages routinely carry file paths, connection strings or data fragments.
Plan: keyword-only expose_errors: bool on mk_app (and the endpoint builder). Changing its default to False (generic 500 + a correlation id that is also logged) is a behaviour change for clients that display detail, so either flip it with a release note after checking dependents' frontends, or keep True and document it.
- Default output conversion falls back to
obj.__dict__ (qh/endpoint.py), which serialises private attributes (_token, password_hash, ...). Plan: drop _-prefixed keys in the fallback (or require a registered converter for arbitrary objects).
Minor: stores_qh.add_mall_access takes user_id from the URL with no auth hook, and its demo __main__ binds 0.0.0.0.
🤖 Generated with Claude Code
Three defaults expose more to HTTP clients than an app author would expect:
async_funcs=is used).mk_appalways addsadd_global_task_endpoints(qh/app.py), soGET /tasks/lists every task of every caller — includingresult,errorand the full servertraceback(qh/async_endpoints.pyto_dict) — andDELETE /tasks/{id}has no ownership check. In a multi-user app one user can read or cancel another's results.Plan: make the global listing opt-in (
global_task_endpoints=Falseby default), never serialise tracebacks to clients (log them server-side), and add an optionaltask_owner(request) -> strhook that per-task routes check.detail=f"Error in {func.__name__}: {e}"(qh/endpoint.py, same pattern inqh/base.py,qh/core.py). Exception messages routinely carry file paths, connection strings or data fragments.Plan: keyword-only
expose_errors: boolonmk_app(and the endpoint builder). Changing its default toFalse(generic 500 + a correlation id that is also logged) is a behaviour change for clients that displaydetail, so either flip it with a release note after checking dependents' frontends, or keepTrueand document it.obj.__dict__(qh/endpoint.py), which serialises private attributes (_token,password_hash, ...). Plan: drop_-prefixed keys in the fallback (or require a registered converter for arbitrary objects).Minor:
stores_qh.add_mall_accesstakesuser_idfrom the URL with no auth hook, and its demo__main__binds0.0.0.0.🤖 Generated with Claude Code