feat: declare governed external provider state
This commit is contained in:
@@ -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",),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user