idea33-buildledger-verifiab.../tests/test_buildledger.py

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