perf(observatory): pack camera epoch source transfer

This commit is contained in:
DCCONSTRUCTIONS
2026-08-31 17:59:18 +03:00
parent 1766c0bdb2
commit 4cd94b5805
5 changed files with 1164 additions and 7 deletions
@@ -4,6 +4,7 @@ import asyncio
import copy
import hashlib
import json
import tarfile
from dataclasses import dataclass
from pathlib import Path
from typing import cast
@@ -484,6 +485,51 @@ def test_source_member_rejects_tampering_and_stale_generation(tmp_path: Path) ->
)
def test_camera_epoch_archive_is_sealed_deterministic_and_cached(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
fixture = _fixture(tmp_path)
archive, archive_path = fixture.service.materialize_camera_epoch_archive(
job_id=fixture.job.job_id,
claim_token=fixture.claim_token,
claim_generation=fixture.job.claim_generation,
claimant_id="worker-006",
)
assert archive_path.name == archive.sha256
assert archive_path.stat().st_size == archive.byte_length
assert hashlib.sha256(archive_path.read_bytes()).hexdigest() == archive.sha256
with tarfile.open(archive_path, mode="r:") as packed:
members = packed.getmembers()
assert [member.name for member in members] == ["init.mp4", "segments/1.m4s"]
assert all(
member.type == tarfile.REGTYPE
and member.mode == 0o600
and member.mtime == 0
and member.uid == 0
and member.gid == 0
and member.uname == ""
and member.gname == ""
for member in members
)
def reject_rebuild(*_args: object, **_kwargs: object) -> object:
pytest.fail("immutable camera epoch archive must be reused")
monkeypatch.setattr(tarfile, "open", reject_rebuild)
repeated, repeated_path = fixture.service.materialize_camera_epoch_archive(
job_id=fixture.job.job_id,
claim_token=fixture.claim_token,
claim_generation=fixture.job.claim_generation,
claimant_id="worker-006",
)
assert repeated == archive
assert repeated_path == archive_path
def test_result_upload_is_atomic_resumable_and_required_before_success(
tmp_path: Path,
) -> None:
+245 -5
View File
@@ -1,7 +1,9 @@
from __future__ import annotations
import hashlib
import io
import json
import tarfile
from collections.abc import Callable
from pathlib import Path
@@ -9,9 +11,12 @@ import httpx
import pytest
from k1link.observatory.portable_artifact_transport import (
PORTABLE_CAMERA_EPOCH_ARCHIVE_ID_HEADER,
PORTABLE_CAMERA_EPOCH_ARCHIVE_MEDIA_TYPE,
PORTABLE_RESULT_UPLOAD_PLAN_SCHEMA,
PORTABLE_RESULT_UPLOAD_RECEIPT_SCHEMA,
PORTABLE_SOURCE_MATERIALIZATION_SCHEMA,
portable_camera_epoch_archive_id,
)
from k1link.observatory.portable_result_contract import (
OBSERVATION_ONLY_AUTHORITY,
@@ -29,6 +34,8 @@ from k1link.observatory.worker_agent import (
SealedObservatoryRecordedJob,
)
from k1link.observatory.worker_http_transport import (
WORKER_HTTP_CAMERA_ARCHIVE_READ_TIMEOUT_SECONDS,
WORKER_HTTP_DEFAULT_TIMEOUT_SECONDS,
ObservatoryWorkerHttpError,
ObservatoryWorkerHttpGateway,
)
@@ -138,7 +145,10 @@ def _source_contract(
job: SealedObservatoryRecordedJob,
*,
inject_path: bool = False,
camera_segment_count: int = 1,
) -> tuple[dict[str, object], dict[str, bytes]]:
if camera_segment_count < 1:
raise ValueError("camera segment count must be positive")
rows = [
_source_member(
job,
@@ -175,16 +185,23 @@ def _source_contract(
camera_epoch=1,
media_type='video/mp4; codecs="avc1.641028"',
),
]
rows.extend(
_source_member(
job,
kind="camera-segment",
payload=b"sealed-camera-segment",
payload=(
b"sealed-camera-segment"
if sequence == 1
else f"sealed-camera-segment-{sequence}".encode("ascii")
),
artifact_id="recorded-camera-right",
camera_epoch=1,
camera_sequence=1,
camera_sequence=sequence,
media_type="video/iso.segment",
),
]
)
for sequence in range(1, camera_segment_count + 1)
)
members = [row for row, _payload in rows]
members.sort(key=lambda row: str(row["member_id"]))
if inject_path:
@@ -210,6 +227,86 @@ def _source_contract(
)
def _camera_archive_response(
job: SealedObservatoryRecordedJob,
manifest: dict[str, object],
payloads: dict[str, bytes],
*,
mutation: str | None = None,
) -> tuple[bytes, dict[str, str]]:
rows = manifest["members"]
assert isinstance(rows, list)
camera_rows = [
row
for row in rows
if isinstance(row, dict)
and row.get("kind") in {"camera-init", "camera-segment"}
]
camera_rows.sort(
key=lambda row: (
0 if row["kind"] == "camera-init" else 1,
int(row["camera_sequence"] or 0),
)
)
packed = io.BytesIO()
with tarfile.open(
fileobj=packed,
mode="w",
format=tarfile.USTAR_FORMAT,
) as archive:
for index, row in enumerate(camera_rows):
sequence = row["camera_sequence"]
name = (
"init.mp4"
if row["kind"] == "camera-init"
else f"segments/{sequence}.m4s"
)
if mutation == "traversal" and index == len(camera_rows) - 1:
name = "../../operator-secret"
member_id = str(row["member_id"])
payload = payloads[member_id]
info = tarfile.TarInfo(name)
info.mode = 0o600
info.mtime = 0
info.uid = 0
info.gid = 0
info.uname = ""
info.gname = ""
if mutation == "symlink" and index == len(camera_rows) - 1:
info.type = tarfile.SYMTYPE
info.linkname = "../../operator-secret"
info.size = 0
archive.addfile(info)
else:
info.size = len(payload)
archive.addfile(info, io.BytesIO(payload))
archive_payload = packed.getvalue()
sha256 = hashlib.sha256(archive_payload).hexdigest()
init = camera_rows[0]
archive_id = portable_camera_epoch_archive_id(
job_identity_sha256=job.identity_sha256,
source_bundle_sha256=job.source_bundle_sha256,
artifact_id=str(init["artifact_id"]),
camera_epoch=int(init["camera_epoch"]),
member_ids=tuple(str(row["member_id"]) for row in camera_rows),
byte_length=len(archive_payload),
sha256=sha256,
)
headers = {
"Content-Type": PORTABLE_CAMERA_EPOCH_ARCHIVE_MEDIA_TYPE,
"Content-Length": str(len(archive_payload)),
"X-Mission-Core-Content-Sha256": sha256,
PORTABLE_CAMERA_EPOCH_ARCHIVE_ID_HEADER: archive_id,
}
if mutation == "corruption":
changed = bytearray(archive_payload)
offset = archive_payload.find(b"sealed-camera-init")
assert offset >= 0
changed[offset] ^= 1
archive_payload = bytes(changed)
return archive_payload, headers
def test_http_gateway_materializes_only_exact_claim_bound_members(
tmp_path: Path,
) -> None:
@@ -232,6 +329,8 @@ def test_http_gateway_materializes_only_exact_claim_bound_members(
artifact_requests.append(request)
if request.url.path.endswith("/source-materialization"):
return httpx.Response(200, json=manifest)
if request.url.path.endswith("/source-camera-epoch-archive"):
return httpx.Response(404)
member_id = request.url.path.rsplit("/", 1)[-1]
payload = payloads[member_id]
return httpx.Response(
@@ -266,7 +365,148 @@ def test_http_gateway_materializes_only_exact_claim_bound_members(
)
assert persisted == manifest
assert "path" not in json.dumps(persisted, sort_keys=True)
assert len(artifact_requests) == 1 + len(payloads)
assert len(artifact_requests) == 2 + len(payloads)
def test_http_gateway_packed_camera_epoch_bounds_requests_and_header_timeout(
tmp_path: Path,
) -> None:
job = _job(
bundle_sha256=hashlib.sha256(b"source-bundle").hexdigest(),
capability_sha256=hashlib.sha256(b"source-capability").hexdigest(),
)
manifest, payloads = _source_contract(job, camera_segment_count=101)
archive_payload, archive_headers = _camera_archive_response(
job,
manifest,
payloads,
)
artifact_requests: list[httpx.Request] = []
camera_member_requests: list[str] = []
archive_read_timeouts: list[float] = []
rows = manifest["members"]
assert isinstance(rows, list)
camera_member_ids = {
str(row["member_id"])
for row in rows
if isinstance(row, dict)
and row.get("kind") in {"camera-init", "camera-segment"}
}
def handler(request: httpx.Request) -> httpx.Response:
if request.url.path.endswith("/claims"):
return _claim_response()
artifact_requests.append(request)
if request.url.path.endswith("/source-materialization"):
return httpx.Response(200, json=manifest)
if request.url.path.endswith("/source-camera-epoch-archive"):
timeout = request.extensions.get("timeout")
assert isinstance(timeout, dict)
read_timeout = timeout.get("read")
assert isinstance(read_timeout, float)
assert read_timeout > WORKER_HTTP_DEFAULT_TIMEOUT_SECONDS
archive_read_timeouts.append(read_timeout)
return httpx.Response(
200,
content=archive_payload,
headers=archive_headers,
)
member_id = request.url.path.rsplit("/", 1)[-1]
if member_id in camera_member_ids:
camera_member_requests.append(member_id)
payload = payloads[member_id]
return httpx.Response(
200,
content=payload,
headers={
"X-Mission-Core-Content-Sha256": hashlib.sha256(
payload
).hexdigest()
},
)
with ObservatoryWorkerHttpGateway(
base_url="http://127.0.0.1:18080",
bearer_token=BEARER_TOKEN,
work_root=tmp_path / "worker",
transport=httpx.MockTransport(handler),
) as gateway:
_cache_claim(gateway)
stage = gateway.materialize(job)
assert archive_read_timeouts == [
WORKER_HTTP_CAMERA_ARCHIVE_READ_TIMEOUT_SECONDS
]
assert camera_member_requests == []
assert len(artifact_requests) == 6
assert (
stage.root / "camera/epoch-1/segments/101.m4s"
).read_bytes() == b"sealed-camera-segment-101"
expected_files = {
"source-bundle.json",
"source-capability.json",
"mqtt.raw.k1mqtt",
"mqtt.metadata.jsonl",
"materialization-manifest.json",
"camera/epoch-1/init.mp4",
*(f"camera/epoch-1/segments/{sequence}.m4s" for sequence in range(1, 102)),
}
assert {
path.relative_to(stage.root).as_posix()
for path in stage.root.rglob("*")
if path.is_file()
} == expected_files
@pytest.mark.parametrize(
("mutation", "message"),
[
("corruption", "content differs"),
("traversal", "unsafe member"),
("symlink", "unsafe member"),
],
)
def test_http_gateway_rejects_corrupt_or_unsafe_camera_archive(
tmp_path: Path,
mutation: str,
message: str,
) -> None:
job = _job(
bundle_sha256=hashlib.sha256(b"source-bundle").hexdigest(),
capability_sha256=hashlib.sha256(b"source-capability").hexdigest(),
)
manifest, payloads = _source_contract(job)
archive_payload, archive_headers = _camera_archive_response(
job,
manifest,
payloads,
mutation=mutation,
)
def handler(request: httpx.Request) -> httpx.Response:
if request.url.path.endswith("/claims"):
return _claim_response()
if request.url.path.endswith("/source-materialization"):
return httpx.Response(200, json=manifest)
if request.url.path.endswith("/source-camera-epoch-archive"):
return httpx.Response(
200,
content=archive_payload,
headers=archive_headers,
)
pytest.fail("unsafe camera archive must fail before member fallback")
with ObservatoryWorkerHttpGateway(
base_url="http://127.0.0.1:18080",
bearer_token=BEARER_TOKEN,
work_root=tmp_path / "worker",
transport=httpx.MockTransport(handler),
) as gateway:
_cache_claim(gateway)
with pytest.raises(ObservatoryWorkerHttpError, match=message):
gateway.materialize(job)
assert not list(tmp_path.rglob("operator-secret"))
def test_http_gateway_rejects_server_selected_source_path(tmp_path: Path) -> None: