feat: declare governed external provider state

This commit is contained in:
2026-08-01 17:48:32 +02:00
parent f084a0f3a9
commit 233ce40983
8 changed files with 430 additions and 366 deletions
+130
View File
@@ -24,11 +24,22 @@ from govoplan_core.core.modules import (
RoleTemplate,
)
from govoplan_core.core.operations import OperationalCheckProviderRegistration
from govoplan_core.core.provider_governance import (
ExternalProviderDeclaration,
ExternalProviderStateProviderRegistration,
ProviderBehaviorDeclaration,
ProviderObjectDeclaration,
declared_module_architecture,
)
from govoplan_core.core.views import ViewSurface
from govoplan_core.db.base import Base
from govoplan_files.backend.change_tracking import register_files_change_tracking
from govoplan_files.backend.db import models as file_models # noqa: F401 - populate Files ORM metadata
from govoplan_files.backend.documentation import documentation_topics
from govoplan_files.backend.provider_state import (
REMOTE_STORAGE_PROVIDER_ID,
remote_storage_provider_states,
)
register_files_change_tracking()
@@ -207,6 +218,58 @@ def _files_router(context: ModuleContext):
return router
REMOTE_STORAGE_PROVIDER = ExternalProviderDeclaration(
id=REMOTE_STORAGE_PROVIDER_ID,
module_id="files",
label="Remote file storage mirror",
maturity="synchronize",
operations=("discover", "search", "read", "synchronize", "preview"),
objects=(
ProviderObjectDeclaration(
object_type="remote_folder",
field_groups=("identity", "hierarchy", "display", "source_metadata"),
authority_modes=("external_authoritative", "external_mirror"),
default_authority_mode="external_mirror",
),
ProviderObjectDeclaration(
object_type="remote_file",
field_groups=("identity", "content", "version", "source_metadata"),
authority_modes=("external_authoritative", "external_mirror"),
default_authority_mode="external_mirror",
),
),
behavior=ProviderBehaviorDeclaration(
revision_tokens="Remote path, provider revision, size, and content digest are retained on managed imports.",
concurrency="A sync compares the frozen source reference and revision before creating a new managed version.",
freshness="Provider state distinguishes software availability from an unobserved live remote binding.",
health="Unsupported providers or missing optional transports fail closed; live health remains unknown without a probe.",
max_read_items=5000,
idempotency="Source profile, remote object reference, and revision/digest suppress duplicate managed versions.",
retry="Operators repeat bounded browse/import after a classified transport failure; effects are not blindly retried.",
timeout_seconds=30,
conflicts="Managed-file conflict policy is explicit; the current provider never mutates the remote source.",
outcome_unknown="An interrupted download is discarded unless its complete digest and managed version commit are confirmed.",
outcome_unknown_supported=True,
evidence="Managed versions retain connector profile, remote object identity, source revision, digest, and acquisition time.",
audit_event_types=(
"files.connector.accessed",
"files.connector.imported",
"files.connector.synced",
),
correction="A later acquisition creates a new managed version and preserves prior provenance.",
rollback="Remote reads require no remote rollback; incomplete local objects are reconciled as orphans.",
compensation="A wrongly imported managed version can be retired under Files policy without deleting the source.",
reconciliation="Re-read source metadata and digest, then compare the committed managed version and object-store inventory.",
outage="Previously imported managed versions remain available while remote spaces report unknown or stale state.",
classifications=("internal", "confidential", "personal"),
purposes=("governed file acquisition", "managed evidence snapshot"),
retention="Files retention applies to managed versions; external retention remains provider-owned.",
secret_handling="Credentials remain encrypted or deployment-owned and never appear in provider state or provenance.",
),
documentation_topic_ids=("files.governed-connectors-and-provenance",),
)
manifest = ModuleManifest(
id="files",
name="Files",
@@ -682,6 +745,46 @@ manifest = ModuleManifest(
],
},
),
DocumentationTopic(
id="files.reference.shared-storage-profile",
title="Operate Files with shared object storage",
summary="Choose local, host-shared, or S3-backed storage consistently with the runtime topology.",
body="Core supplies the common local/S3 object-storage backend while Files owns file metadata and object-key semantics. Local storage is valid for one runtime process; a shared host volume supports same-host replicas; independent hosts require an explicitly trusted HTTPS S3-compatible endpoint. Restore PostgreSQL, objects, and the master key to one coordinated recovery point.",
layer="configured",
documentation_types=("admin",),
audience=("file_admin", "operator", "system_admin"),
order=54,
conditions=(
DocumentationCondition(
required_modules=("files",),
any_scopes=("files:file:admin", "system:settings:read"),
),
),
links=(
DocumentationLink(label="Files", href="/files", kind="runtime"),
DocumentationLink(label="Files handbook", href="govoplan-files/docs/FILES_HANDBOOK.md", kind="repository"),
),
related_modules=("ops", "campaigns"),
configuration_keys=(
"GOVOPLAN_STATE_PROFILE",
"GOVOPLAN_INSTALLATION_ID",
"FILE_STORAGE_BACKEND",
"FILE_STORAGE_LOCAL_ROOT",
"FILE_STORAGE_S3_ENDPOINT_URL",
"FILE_STORAGE_S3_ENDPOINT_TRUSTED",
"FILE_STORAGE_S3_DEPLOYMENT_MANAGED",
),
metadata={
"kind": "reference",
"route": "/ops",
"screen": "Storage and runtime posture",
"limitations": [
"Installer-managed Garage is single-node unless an external multi-node cluster is operated separately.",
"The application does not create or verify production PostgreSQL/object/key backups.",
],
"verification": "Run the Files storage round-trip check and a coordinated restore drill against the exact deployment topology.",
},
),
),
documentation_providers=(documentation_topics,),
migration_spec=MigrationSpec(
@@ -722,6 +825,33 @@ manifest = ModuleManifest(
cache_seconds=60,
),
),
external_providers=(REMOTE_STORAGE_PROVIDER,),
external_provider_state_providers=(
ExternalProviderStateProviderRegistration(
module_id="files",
provider_id=REMOTE_STORAGE_PROVIDER_ID,
provider=remote_storage_provider_states,
),
),
architecture=declared_module_architecture(
layer="content_records_evidence",
kind="domain",
maturity="vertical_slice",
documentation_ref="docs/FILES_HANDBOOK.md",
test_ref="tests/test_storage_backends.py",
known_limits=("Multi-node object-storage recovery evidence and every remote connector profile are not reference-ready.",),
supported_authority_modes=(
"native_authoritative",
"external_authoritative",
"external_mirror",
),
owned_concepts=("file asset", "file version", "folder", "share", "connector space"),
non_owned_concepts=("record disposition", "campaign attachment rule", "external storage object"),
target_tested_providers=(REMOTE_STORAGE_PROVIDER_ID,),
recovery_docs=("docs/FILES_HANDBOOK.md",),
security_docs=("docs/CONNECTOR_BOUNDARY.md",),
operations_docs=("docs/FILES_HANDBOOK.md",),
),
)