From b180b3ad975a75b882bee13baf744a7933d79979 Mon Sep 17 00:00:00 2001 From: Chris Bartholomew Date: Fri, 20 Feb 2026 17:43:52 -0500 Subject: [PATCH] Fix bank config API for multi-tenant schema isolation (#417) * Fix bank config API for multi-tenant schema isolation - Use fq_table() in config_resolver.py to schema-qualify bank table queries - Add authenticate_and_resolve_schema() to bank config API handlers in http.py Without these fixes, bank config operations in multi-tenant mode hit public.banks instead of tenant_xxx.banks, causing "column config does not exist" errors. * Fix method name: _authenticate_tenant not authenticate_and_resolve_schema The MemoryEngine method is _authenticate_tenant(), not authenticate_and_resolve_schema(). This was causing AttributeError on all bank config API requests. --- hindsight-api/hindsight_api/api/http.py | 9 +++++++++ hindsight-api/hindsight_api/config_resolver.py | 15 ++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/hindsight-api/hindsight_api/api/http.py b/hindsight-api/hindsight_api/api/http.py index cc16e39b..fdee358d 100644 --- a/hindsight-api/hindsight_api/api/http.py +++ b/hindsight-api/hindsight_api/api/http.py @@ -3485,6 +3485,9 @@ def _register_routes(app: FastAPI): detail="Bank configuration API is disabled. Set HINDSIGHT_API_ENABLE_BANK_CONFIG_API=true to enable.", ) try: + # Authenticate and set schema context for multi-tenant DB queries + await app.state.memory._authenticate_tenant(request_context) + # Get resolved config from config resolver config_dict = await app.state.memory._config_resolver.get_bank_config(bank_id, request_context) @@ -3520,6 +3523,9 @@ def _register_routes(app: FastAPI): detail="Bank configuration API is disabled. Set HINDSIGHT_API_ENABLE_BANK_CONFIG_API=true to enable.", ) try: + # Authenticate and set schema context for multi-tenant DB queries + await app.state.memory._authenticate_tenant(request_context) + # Update config via config resolver (validates configurable fields and permissions) await app.state.memory._config_resolver.update_bank_config(bank_id, request.updates, request_context) @@ -3557,6 +3563,9 @@ def _register_routes(app: FastAPI): detail="Bank configuration API is disabled. Set HINDSIGHT_API_ENABLE_BANK_CONFIG_API=true to enable.", ) try: + # Authenticate and set schema context for multi-tenant DB queries + await app.state.memory._authenticate_tenant(request_context) + # Reset config via config resolver await app.state.memory._config_resolver.reset_bank_config(bank_id) diff --git a/hindsight-api/hindsight_api/config_resolver.py b/hindsight-api/hindsight_api/config_resolver.py index 2f70f216..e5de3946 100644 --- a/hindsight-api/hindsight_api/config_resolver.py +++ b/hindsight-api/hindsight_api/config_resolver.py @@ -16,6 +16,7 @@ from typing import Any import asyncpg from hindsight_api.config import HindsightConfig, _get_raw_config, normalize_config_dict +from hindsight_api.engine.memory_engine import fq_table from hindsight_api.extensions.tenant import TenantExtension from hindsight_api.models import RequestContext @@ -149,8 +150,8 @@ class ConfigResolver: try: async with self.pool.acquire() as conn: row = await conn.fetchrow( - """ - SELECT config FROM banks WHERE bank_id = $1 + f""" + SELECT config FROM {fq_table("banks")} WHERE bank_id = $1 """, bank_id, ) @@ -241,8 +242,8 @@ class ConfigResolver: # Merge with existing config (JSONB || operator) async with self.pool.acquire() as conn: await conn.execute( - """ - UPDATE banks + f""" + UPDATE {fq_table("banks")} SET config = config || $1::jsonb, updated_at = now() WHERE bank_id = $2 @@ -262,9 +263,9 @@ class ConfigResolver: """ async with self.pool.acquire() as conn: await conn.execute( - """ - UPDATE banks - SET config = '{}'::jsonb, + f""" + UPDATE {fq_table("banks")} + SET config = '{{}}'::jsonb, updated_at = now() WHERE bank_id = $1 """,