feat(records): govern lifecycle recovery and transfer evidence
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
from govoplan_core.core.records import (
|
||||
RecordArchiveProviderState,
|
||||
RecordArchiveReceipt,
|
||||
RecordArchiveTransferRequest,
|
||||
RecordContractError,
|
||||
)
|
||||
|
||||
|
||||
SIMULATION_PROVIDER_ID = "simulation"
|
||||
SIMULATION_PROFILE = "govoplan-simulation-v1"
|
||||
|
||||
|
||||
class SimulatedRecordArchiveProvider:
|
||||
"""Exercise the transfer boundary without claiming archival custody."""
|
||||
|
||||
provider_id = SIMULATION_PROVIDER_ID
|
||||
|
||||
def state(self) -> RecordArchiveProviderState:
|
||||
checked_at = datetime.now(UTC)
|
||||
return RecordArchiveProviderState(
|
||||
provider_id=self.provider_id,
|
||||
label="Records transfer simulation",
|
||||
profiles=(SIMULATION_PROFILE,),
|
||||
authority_modes=("linked_reference",),
|
||||
healthy=True,
|
||||
checked_at=checked_at,
|
||||
last_success_at=checked_at,
|
||||
freshness_seconds=0,
|
||||
limitations=(
|
||||
"Simulation validates package and receipt handling but does not transfer custody.",
|
||||
"It is not an xDOMEA or archival conformance profile.",
|
||||
),
|
||||
simulated=True,
|
||||
)
|
||||
|
||||
def dispatch(
|
||||
self,
|
||||
session: object,
|
||||
principal: object,
|
||||
*,
|
||||
request: RecordArchiveTransferRequest,
|
||||
) -> RecordArchiveReceipt:
|
||||
del session, principal
|
||||
if request.package.profile != SIMULATION_PROFILE:
|
||||
raise RecordContractError(
|
||||
"The simulation provider only accepts its declared profile."
|
||||
)
|
||||
observed_at = datetime.now(UTC)
|
||||
receipt_payload = {
|
||||
"provider_id": self.provider_id,
|
||||
"package_id": request.package.package_id,
|
||||
"manifest_sha256": request.package.manifest_sha256,
|
||||
"profile": request.package.profile,
|
||||
"outcome": "accepted",
|
||||
"simulated": True,
|
||||
}
|
||||
receipt_sha256 = hashlib.sha256(
|
||||
json.dumps(
|
||||
receipt_payload,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
).encode("utf-8")
|
||||
).hexdigest()
|
||||
return RecordArchiveReceipt(
|
||||
provider_id=self.provider_id,
|
||||
package_id=request.package.package_id,
|
||||
outcome="accepted",
|
||||
observed_at=observed_at,
|
||||
receipt_sha256=receipt_sha256,
|
||||
external_reference=f"simulation:{request.package.package_id}",
|
||||
retry_safe=True,
|
||||
simulated=True,
|
||||
metadata={
|
||||
"manifest_sha256": request.package.manifest_sha256,
|
||||
"profile": request.package.profile,
|
||||
"custody_transferred": False,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"SIMULATION_PROFILE",
|
||||
"SIMULATION_PROVIDER_ID",
|
||||
"SimulatedRecordArchiveProvider",
|
||||
]
|
||||
Reference in New Issue
Block a user