diff --git a/.gitignore b/.gitignore index 70ce19fa..b1e861fe 100644 --- a/.gitignore +++ b/.gitignore @@ -86,8 +86,11 @@ sdk/agentflow/**/__pycache__/ sdk/agentflow/**/*.py[cod] integrations/agentflow_integrations/**/__pycache__/ integrations/agentflow_integrations/**/*.py[cod] -# Local Iceberg warehouse/runtime state (intentionally untracked). -/warehouse/agentflow/ +# Local Iceberg warehouse/runtime state (intentionally untracked). DV2 SQL/Python +# source under warehouse/agentflow/dv2/ is tracked normally — only the generated +# lake and build output are excluded here. +/warehouse/agentflow/orders/ +/warehouse/agentflow/dv2/reference/build/ # Root API usage DuckDB runtime state (intentionally untracked). /agentflow_api.duckdb agentflow_bench_debug*.duckdb* diff --git a/docs/helm-deployment.md b/docs/helm-deployment.md index 6af33042..bbc2acee 100644 --- a/docs/helm-deployment.md +++ b/docs/helm-deployment.md @@ -118,7 +118,7 @@ If `ingress.enabled=true`, verify the configured host instead of using port-forw - `helm/agentflow/values.schema.json` is the chart contract for runtime values consumed from Helm. - If you add, rename, or make required a field under `config.tenants` or `secrets.apiKeys`, update the schema, chart defaults, and environment-specific values together. -- Keep the mounted file shape in `templates/configmap.yaml` and `templates/secret.yaml` aligned with the runtime Pydantic models in `src/ingestion/tenant_router.py` and `src/serving/api/auth/manager.py`. +- Keep the mounted file shape in `templates/configmap.yaml` and `templates/secret.yaml` aligned with the runtime Pydantic models in `src/tenancy.py` and `src/serving/api/auth/manager.py`. - Validate contract changes with `helm lint helm/agentflow -f k8s/staging/values-staging.yaml` before staging rehearsal. ## Upgrade diff --git a/docs/security-audit.md b/docs/security-audit.md index e6b87488..c3c588e6 100644 --- a/docs/security-audit.md +++ b/docs/security-audit.md @@ -51,7 +51,7 @@ This is stronger than soft application filtering because the query builder rewri The current evidence supports the claim "tenant-scoped DuckDB schemas with fail-closed query resolution." It does not support broader claims such as end-to-end isolation across every external dependency. -Evidence: `src/ingestion/tenant_router.py`, `src/serving/semantic_layer/query/sql_builder.py`, `src/serving/semantic_layer/query/engine.py`, `tests/integration/test_tenant_isolation.py` +Evidence: `src/tenancy.py`, `src/serving/semantic_layer/query/sql_builder.py`, `src/serving/semantic_layer/query/engine.py`, `tests/integration/test_tenant_isolation.py` ## 4. Input Validation and Contract Safety diff --git a/src/ingestion/cdc/normalizer.py b/src/ingestion/cdc/normalizer.py index dde5de72..f4432856 100644 --- a/src/ingestion/cdc/normalizer.py +++ b/src/ingestion/cdc/normalizer.py @@ -5,7 +5,7 @@ from datetime import UTC, datetime from typing import Any -from src.ingestion.tenant_router import TenantRouter +from src.tenancy import TenantRouter _SOURCE_BY_CONNECTOR: dict[str, str] = { "postgresql": "postgres_cdc", diff --git a/src/serving/semantic_layer/query/contracts.py b/src/serving/semantic_layer/query/contracts.py index 65641459..f2e048bd 100644 --- a/src/serving/semantic_layer/query/contracts.py +++ b/src/serving/semantic_layer/query/contracts.py @@ -2,10 +2,10 @@ from typing import Protocol -from src.ingestion.tenant_router import TenantRouter from src.serving.backends import ServingBackend from src.serving.backends.duckdb_backend import DuckDBBackend from src.serving.semantic_layer.catalog import DataCatalog +from src.tenancy import TenantRouter class SQLBuilderHost(Protocol): diff --git a/src/serving/semantic_layer/query/engine.py b/src/serving/semantic_layer/query/engine.py index 6e0cb36c..801711ec 100644 --- a/src/serving/semantic_layer/query/engine.py +++ b/src/serving/semantic_layer/query/engine.py @@ -8,12 +8,12 @@ import duckdb -from src.ingestion.tenant_router import TenantRouter from src.serving.backends import create_backend from src.serving.backends.duckdb_backend import DuckDBBackend from src.serving.db_pool import DuckDBPool from src.serving.duckdb_connection import connect_duckdb from src.serving.semantic_layer.catalog import DataCatalog +from src.tenancy import TenantRouter from .entity_queries import EntityQueryMixin from .metric_queries import MetricQueryMixin diff --git a/src/ingestion/tenant_router.py b/src/tenancy.py similarity index 100% rename from src/ingestion/tenant_router.py rename to src/tenancy.py diff --git a/tests/integration/test_tenant_isolation.py b/tests/integration/test_tenant_isolation.py index 2ffdb3ae..ac46a855 100644 --- a/tests/integration/test_tenant_isolation.py +++ b/tests/integration/test_tenant_isolation.py @@ -7,12 +7,12 @@ from fastapi import FastAPI, Request from fastapi.testclient import TestClient -from src.ingestion.tenant_router import TenantRouter from src.serving.api.main import app from src.serving.api.routers.agent_query import router as agent_router from src.serving.cache import QueryCache from src.serving.semantic_layer.catalog import DataCatalog from src.serving.semantic_layer.query_engine import QueryEngine +from src.tenancy import TenantRouter pytestmark = pytest.mark.integration diff --git a/tests/unit/test_tenant_router_cache.py b/tests/unit/test_tenant_router_cache.py index 0806643f..324f8d3e 100644 --- a/tests/unit/test_tenant_router_cache.py +++ b/tests/unit/test_tenant_router_cache.py @@ -4,9 +4,9 @@ from types import SimpleNamespace from typing import cast -from src.ingestion.tenant_router import TenantRouter from src.serving.semantic_layer.catalog import DataCatalog from src.serving.semantic_layer.query.sql_builder import SQLBuilderMixin +from src.tenancy import TenantRouter def test_tenant_router_reuses_loaded_config(