idea33-buildledger-verifiab.../buildledger/adapters.py

71 lines
2.7 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from .models import BuildContract, BuildEnvironment, BuildObject, ReproManifest, sha256_text, canonical_json
@dataclass(frozen=True)
class RegistryCoordinate:
registry: str
name: str
version: str
def canonical(self) -> str:
return f"{self.registry}/{self.name}@{self.version}"
class _CIAdapter:
provider: str
def manifest_from_context(self, context: dict[str, str]) -> ReproManifest:
source_commit = context["commit"]
env_hash = sha256_text(canonical_json(context.get("environment", {})))
inputs_hash = sha256_text(canonical_json({k: context[k] for k in sorted(context) if k != "entropy_seed"}))
score = float(context.get("reproducibility_score", "1.0"))
return ReproManifest(
source_commit=source_commit,
deterministic_inputs_hash=inputs_hash,
toolchain_versions={"ci": self.provider},
env_hash=env_hash,
entropy_seed=context.get("entropy_seed"),
reproducibility_score=score,
run_count=int(context.get("run_count", "1")),
matched_artifact_bytes=int(context.get("matched_artifact_bytes", "0")),
total_artifact_bytes=int(context.get("total_artifact_bytes", "0")),
)
def contract_from_context(self, context: dict[str, str]) -> BuildContract:
manifest = self.manifest_from_context(context)
build_object = BuildObject(
source_repo=context["repo"],
commit=context["commit"],
builder=context.get("builder", self.provider),
target=context.get("target", context["repo"]),
build_tool=context.get("build_tool", self.provider),
flags=[flag for flag in context.get("flags", "").split() if flag],
)
environment = BuildEnvironment(
platform=context.get("platform", self.provider),
operating_system=context.get("os", "unknown"),
architecture=context.get("arch", "unknown"),
toolchain={k: v for k, v in context.items() if k.startswith("toolchain.")},
container_image=context.get("container_image"),
env_hash=manifest.env_hash,
variables={k: v for k, v in context.items() if k.startswith("env.")},
)
contract_id = sha256_text(canonical_json({"provider": self.provider, "repo": context["repo"], "commit": context["commit"]}))
return BuildContract(contract_id=contract_id, build_object=build_object, environment=environment, manifest=manifest)
class GitHubActionsAdapter(_CIAdapter):
provider = "github-actions"
class GitLabCIAdapter(_CIAdapter):
provider = "gitlab-ci"
class CircleCIAdapter(_CIAdapter):
provider = "circleci"