111 lines
4.0 KiB
Python
111 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from buildledger.adapters import GitHubActionsAdapter
|
|
from buildledger.anchors import AnchorStore
|
|
from buildledger.ledger import SQLiteLedger
|
|
from buildledger.models import Artifact, BuildContract, BuildEnvironment, BuildLog, BuildObject, DependencyGraph, DependencyNode, ReproManifest
|
|
from buildledger.schemas import SchemaRegistry
|
|
from buildledger.sync import SyncCursor, apply_delta, prepare_delta
|
|
|
|
|
|
def make_contract() -> BuildContract:
|
|
build_object = BuildObject(
|
|
source_repo="https://example.com/repo.git",
|
|
commit="abc123",
|
|
builder="gha",
|
|
target="artifact.tar.gz",
|
|
build_tool="python",
|
|
flags=["--locked"],
|
|
)
|
|
environment = BuildEnvironment(
|
|
platform="linux",
|
|
operating_system="ubuntu-24.04",
|
|
architecture="x86_64",
|
|
toolchain={"python": "3.11.8"},
|
|
container_image="ghcr.io/example/build:1",
|
|
env_hash="f" * 64,
|
|
)
|
|
manifest = ReproManifest(
|
|
source_commit="abc123",
|
|
deterministic_inputs_hash="a" * 64,
|
|
toolchain_versions={"python": "3.11.8"},
|
|
env_hash="f" * 64,
|
|
reproducibility_score=1.0,
|
|
run_count=2,
|
|
matched_artifact_bytes=100,
|
|
total_artifact_bytes=100,
|
|
)
|
|
return BuildContract(
|
|
contract_id="contract-1",
|
|
build_object=build_object,
|
|
environment=environment,
|
|
dependency_graph=DependencyGraph(nodes=[DependencyNode(name="dep", version="1.0.0", digest="d" * 64)]),
|
|
artifacts=[Artifact(name="artifact", path="dist/artifact.tar.gz", sha256="b" * 64, size_bytes=100)],
|
|
logs=[BuildLog(stream="stdout", sha256="c" * 64, line_count=1, excerpt=["ok"])],
|
|
manifest=manifest,
|
|
)
|
|
|
|
|
|
def test_schema_registry_validates_contract() -> None:
|
|
registry = SchemaRegistry.with_defaults()
|
|
contract = make_contract()
|
|
loaded = registry.validate("BuildContract", "1.0", contract.model_dump(mode="python"))
|
|
assert loaded.contract_id == "contract-1"
|
|
assert registry.manifest()["BuildContract"] == ["1.0"]
|
|
|
|
|
|
def test_ledger_chain_and_anchor_round_trip(tmp_path: Path) -> None:
|
|
ledger = SQLiteLedger(tmp_path / "ledger.sqlite")
|
|
first = ledger.append("build.contract", make_contract().model_dump(mode="python"))
|
|
second = ledger.append("build.proof", {"status": "verified", "contract": first.entry_hash})
|
|
|
|
ok, issues = ledger.verify_chain()
|
|
assert ok
|
|
assert issues == []
|
|
assert second.sequence == 1
|
|
|
|
anchor = AnchorStore(ledger).record("cloud-anchor", "s3://bucket/buildledger")
|
|
assert anchor.anchored_hash == second.entry_hash
|
|
assert ledger.anchors()[0]["anchored_hash"] == second.entry_hash
|
|
|
|
|
|
def test_delta_sync_applies_to_fresh_ledger(tmp_path: Path) -> None:
|
|
source = SQLiteLedger(tmp_path / "source.sqlite")
|
|
source.append("build.contract", make_contract().model_dump(mode="python"))
|
|
source.append("build.proof", {"status": "verified"})
|
|
|
|
packet = prepare_delta(source, SyncCursor(sequence=-1, entry_hash="0" * 64))
|
|
target = SQLiteLedger(tmp_path / "target.sqlite")
|
|
cursor = apply_delta(target, packet)
|
|
|
|
assert cursor.sequence == 1
|
|
assert target.verify_chain()[0]
|
|
assert len(target.all_entries()) == 2
|
|
|
|
|
|
def test_ci_adapter_generates_contract() -> None:
|
|
context = {
|
|
"repo": "https://example.com/repo.git",
|
|
"commit": "abc123",
|
|
"builder": "gha",
|
|
"target": "artifact.tar.gz",
|
|
"build_tool": "python",
|
|
"platform": "github-actions",
|
|
"os": "ubuntu-24.04",
|
|
"arch": "x86_64",
|
|
"toolchain.python": "3.11.8",
|
|
"env.PYTHONHASHSEED": "0",
|
|
"flags": "--locked",
|
|
"run_count": "2",
|
|
"reproducibility_score": "1.0",
|
|
}
|
|
contract = GitHubActionsAdapter().contract_from_context(context)
|
|
assert contract.build_object.commit == "abc123"
|
|
assert contract.environment.variables["env.PYTHONHASHSEED"] == "0"
|
|
assert contract.manifest.run_count == 2
|