Resource hydration: from handle to target¶
What it is¶
A handle is a name; hydration turns it into a ConnectionConfig - what to connect to, which
credential version produced it, and for which tenant:
resolver = ResourceResolver(secrets=provider, cache=cache, check_tenant=..., tracer=tracer)
config = await resolver.hydrate(ResourceHandle("db/reports"))
The decisions that carry weight¶
The cache key includes the credential version. That is what makes a stale target impossible rather than merely unlikely: a rotation changes the version, hence the key, hence a rebuild.
Hydration never becomes a third enforcement point. A wrong-tenant hydration asserts isolation (the target cannot be reached), not a second authorization decision - the design keeps one enforcement point, and a test asserts the isolation rather than a refusal.
A target can carry its own connection settings (ConnectionConfig.server_settings). A schema
belongs to the deployment; asyncpg takes a search_path only as a connection setting, and
improvising one at a call site would put deployment knowledge in the query path.
ConnectionConfig renders without its target. Everything that logs a hydrated connection
therefore cannot leak credential material by accident.
Evidence¶
11 test functions across tests/unit/test_resource_hydration.py, run with the project gate:
Parametrized cases expand these functions further; the counts here are functions, which is what the documentation check verifies.
Limits¶
Hydration does not health-check the target it produces; a connection that fails fails at the connector, where the connector's own policy applies.