feat: prepare ARR for controlled public deployment
This commit is contained in:
90
arr_ingestion/artifacts.py
Normal file
90
arr_ingestion/artifacts.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""Artifact materialization boundaries used by ARR delivery validation."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from typing import Protocol
|
||||
|
||||
from arr_ingestion.contracts import IngestionError
|
||||
|
||||
|
||||
class ArtifactStore(Protocol):
|
||||
def materialize(self, object_key: str, destination: Path, max_bytes: int) -> None:
|
||||
"""Copy one immutable object to a new private local file."""
|
||||
|
||||
|
||||
class LocalObjectStore:
|
||||
"""Controlled local implementation for tests and offline vertical slices."""
|
||||
|
||||
def __init__(self, root: Path) -> None:
|
||||
self._root = root.resolve()
|
||||
if not self._root.is_dir():
|
||||
raise ValueError("object store root must be an existing directory")
|
||||
|
||||
def materialize(self, object_key: str, destination: Path, max_bytes: int) -> None:
|
||||
source = self._root.joinpath(*object_key.split("/"))
|
||||
try:
|
||||
resolved = source.resolve(strict=True)
|
||||
resolved.relative_to(self._root)
|
||||
except (FileNotFoundError, OSError, ValueError):
|
||||
raise IngestionError("ARTIFACT_NOT_FOUND", "delivery artifact is unavailable") from None
|
||||
if source.is_symlink() or not resolved.is_file():
|
||||
raise IngestionError("ARTIFACT_NOT_FOUND", "delivery artifact is unavailable")
|
||||
destination.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
||||
descriptor = os.open(destination, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
||||
copied = 0
|
||||
try:
|
||||
with resolved.open("rb") as source_handle, os.fdopen(descriptor, "wb") as target:
|
||||
descriptor = -1
|
||||
while True:
|
||||
chunk = source_handle.read(1024 * 1024)
|
||||
if not chunk:
|
||||
break
|
||||
copied += len(chunk)
|
||||
if copied > max_bytes:
|
||||
raise IngestionError(
|
||||
"ARTIFACT_TOO_LARGE", "delivery artifact exceeds its size limit"
|
||||
)
|
||||
target.write(chunk)
|
||||
target.flush()
|
||||
os.fsync(target.fileno())
|
||||
except Exception:
|
||||
destination.unlink(missing_ok=True)
|
||||
raise
|
||||
finally:
|
||||
if descriptor >= 0:
|
||||
os.close(descriptor)
|
||||
|
||||
|
||||
class DirectoryArtifactPublisher:
|
||||
"""Small helper for synthetic/local flows; production uses the OSS adapter."""
|
||||
|
||||
def __init__(self, root: Path) -> None:
|
||||
self._root = root.resolve()
|
||||
self._root.mkdir(parents=True, exist_ok=True, mode=0o700)
|
||||
|
||||
def put_file(self, source: Path, object_key: str) -> Path:
|
||||
destination = self._root.joinpath(*object_key.split("/"))
|
||||
try:
|
||||
destination.resolve().relative_to(self._root)
|
||||
except ValueError:
|
||||
raise IngestionError("ARTIFACT_REFERENCE_INVALID", "object key is invalid") from None
|
||||
destination.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
||||
if destination.exists():
|
||||
raise IngestionError("ARTIFACT_CONFLICT", "object key already exists")
|
||||
descriptor = os.open(destination, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
||||
try:
|
||||
with source.open("rb") as source_handle, os.fdopen(descriptor, "wb") as target:
|
||||
descriptor = -1
|
||||
shutil.copyfileobj(source_handle, target, length=1024 * 1024)
|
||||
target.flush()
|
||||
os.fsync(target.fileno())
|
||||
except Exception:
|
||||
destination.unlink(missing_ok=True)
|
||||
raise
|
||||
finally:
|
||||
if descriptor >= 0:
|
||||
os.close(descriptor)
|
||||
return destination
|
||||
Reference in New Issue
Block a user