from __future__ import annotations import pytest from app.core.system.tenant_context import DeliveryMode, TenantScope from app.core.system.tenant_resources import ( TenantResourceError, build_tenant_namespace, build_tenant_resource_manifest, ) @pytest.mark.parametrize( "resource", ["object", "graph", "cache", "index", "keys", "connectors", "models", "plugins", "backup", "audit_export"], ) def test_tenant_namespaces_are_resource_specific_and_cannot_cross_scope(resource: str): alpha = TenantScope("tenant-alpha", DeliveryMode.SHARED_CONTROL_PLANE) beta = TenantScope("tenant-beta", DeliveryMode.SHARED_CONTROL_PLANE) alpha_namespace = build_tenant_namespace(alpha, resource, "daily-export") beta_namespace = build_tenant_namespace(beta, resource, "daily-export") assert alpha_namespace != beta_namespace assert alpha_namespace.startswith("tenant-alpha/") assert beta_namespace.startswith("tenant-beta/") @pytest.mark.parametrize( "value", [ "../tenant-beta", "tenant-alpha/../tenant-beta", "https://tenant-beta.example/object", "tenant-аlpha", # Cyrillic a, not ASCII a. "tenant-alpha\\tenant-beta", ], ) def test_namespace_contract_rejects_escape_url_and_unicode_homograph(value: str): scope = TenantScope("tenant-alpha", DeliveryMode.SHARED_CONTROL_PLANE) with pytest.raises(TenantResourceError, match="tenant_resource_invalid"): build_tenant_namespace(scope, "object", value) def test_manifest_is_hash_only_and_provider_is_default_disabled(): scope = TenantScope("tenant-alpha", DeliveryMode.SHARED_CONTROL_PLANE) manifest = build_tenant_resource_manifest( scope, resource="backup", name="backup-001", digest="a" * 64, ) assert manifest["tenant_id"] == "tenant-alpha" assert manifest["provider_enabled"] is False assert "secret" not in manifest assert manifest["digest"] == "sha256:" + "a" * 64