Source code for cadrumo.adapters.persistence.storage.runtime_repository
"""Runtime-owned :class:`SecureObjectRepository` factories.Builds :class:`SecureObjectRepository` instances bound to the active profile'sunlocked storage route, so callers obtain a repository without resolving thestorage namespace or key material themselves."""from__future__importannotationsfromcollections.abcimportGeneratorfromcontextlibimportcontextmanagerfromtypingimportTYPE_CHECKINGfrom....core.bucket_pointerimportresolve_active_bucket_idfrom....core.configimportSettings,classify_storage_route,load_settingsfrom....core.config_supportimportStorageRouteKindfrom.errorsimportStorageValidationErrorfrom.namespace_registryimportSTORAGE_NAMESPACE_REGISTRYfrom.runtimeimportinspect_bucket_storage_runtimefrom.runtime_readinessimportStorageRuntimeReadinessCode,runtime_not_ready_errorfrom.sql.secure_objectsimportSecureObjectRepositoryifTYPE_CHECKING:frompathlibimportPathdef_active_bucket_id_for_source(source:Settings,*,include_process_pointer:bool,)->str|None:"""Resolve the active bucket for ``source`` without ignoring scoped settings."""override=(source.cadrumo_active_profileor"").strip()ifoverride:returnoverrideroute=classify_storage_route(source)ifroute.kindisStorageRouteKind.ACTIVE_BUCKET_DATABASE:returnroute.bucket_idifinclude_process_pointer:returnresolve_active_bucket_id()returnNone
[docs]defsecure_object_repository_for_bucket(bucket_id:str,settings:Settings|None=None,)->SecureObjectRepository:"""Return a bucket-attached :class:`SecureObjectRepository` through storage runtime."""returninspect_bucket_storage_runtime(bucket_id,settingsorload_settings()).secure_object_repository()
[docs]defsecure_object_repository_for_active_bucket()->SecureObjectRepository:"""Return a :class:`SecureObjectRepository` attached to the selected active profile bucket."""bucket_id=resolve_active_bucket_id()ifbucket_idisNone:raiseruntime_not_ready_error(StorageRuntimeReadinessCode.NO_ACTIVE_SESSION)returnsecure_object_repository_for_bucket(bucket_id)
[docs]defsecure_object_repository_for_active_bucket_or_default_route(settings:Settings|None=None,)->SecureObjectRepository:"""Return a :class:`SecureObjectRepository` for the active bucket, or the process default. This lower-level storage helper is for repository base classes that still support explicit injected/default SQL engines in tests and bootstrap-adjacent code. It does not catch active-bucket runtime errors: once a bucket is selected, route/session failures surface from ``secure_object_repository_for_bucket`` instead of falling back to a bare repository. """source=settingsorload_settings()bucket_id=_active_bucket_id_for_source(source,include_process_pointer=settingsisNone,)ifbucket_idisNone:from.sql.engineimportget_enginereturnSecureObjectRepository(engine=get_engine(source),namespace_registry=STORAGE_NAMESPACE_REGISTRY)returnsecure_object_repository_for_bucket(bucket_id,source)
[docs]defsecure_object_repository_for_cold_bootstrap_state(settings:Settings|None=None,)->SecureObjectRepository:"""Return a :class:`SecureObjectRepository` for cold-root recovery reads. This is the narrow bootstrap exception used before any active profile bucket pointer exists. Normal profile-bound code must use ``secure_object_repository_for_active_bucket`` or ``secure_object_repository_for_bucket`` so route/session mismatches fail closed at the storage runtime boundary. """from....core.bucket_pointerimportresolve_active_bucket_idsource=settingsorload_settings()route=classify_storage_route(source)ifroute.kindisStorageRouteKind.EXPLICIT_DATABASE_URL:raiseStorageValidationError(translated_message="errors.storage.runtime.cold_bootstrap_explicit_database_refused",)ifroute.kindisStorageRouteKind.ACTIVE_BUCKET_DATABASEor(settingsisNoneandresolve_active_bucket_id()isnotNone):raiseStorageValidationError(translated_message="errors.storage.runtime.cold_bootstrap_active_profile_refused",)from.sql.engineimportget_enginereturnSecureObjectRepository(engine=get_engine(source),namespace_registry=STORAGE_NAMESPACE_REGISTRY)
[docs]@contextmanagerdefsecure_object_repository_for_staged_bucket(bucket_id:str,*,database_file:Path,)->Generator[SecureObjectRepository]:"""Yield a repository for a bucket's database BEFORE its capsule is published. The one route the storage runtime cannot serve, and the reason is structural rather than an oversight. :meth:`~adapters.persistence.storage.runtime.StorageRuntime.secure_object_repository` rebuilds its settings from a storage root plus an active profile, so it always resolves the FINAL ``buckets/<bucket_id>/`` path; and capsule creation writes revision one into a staging directory that becomes that bucket only at the publishing rename. The cold-bootstrap factory is no substitute either -- it refuses an explicit database route by design, because its own job is the no-pointer-yet case rather than this one. So the staging database is addressed explicitly. What stays runtime-owned is everything that made a direct construction worth forbidding: the namespace registry, the session-bucket binding, the secure-session requirement, and the engine's lifetime. A caller receives an open repository and cannot leak the engine behind it. The caller still owns binding the DEK that opens these rows: the staged capsule's key exists only in the creating transaction, which is precisely why no ambient session serves this bucket yet. Args: bucket_id: The profile UUID the staged rows will belong to. Bound as the repository's session bucket, so a session serving a different profile refuses rather than writing across capsules. database_file: The staging database's path. Directory creation is left to the engine deliberately: it refuses to bring a bucket root into existence -- a bucket exists only once its capsule is published -- and creates the parents only after that check. Creating them here first would satisfy the guard by making its subject exist, which is exactly the second bucket creator the refusal is written against. Yields: A :class:`SecureObjectRepository` open on the staged database. """from.sql.engineimportcreate_engine_from_settingsengine=create_engine_from_settings(Settings(cadrumo_database_url=f"sqlite:///{database_file.as_posix()}"))try:yieldSecureObjectRepository(engine=engine,namespace_registry=STORAGE_NAMESPACE_REGISTRY,active_session_bucket_id=bucket_id,require_secure_active_session=True,)finally:engine.dispose()