Historical-evidence pins (dfg_re100 / jet_circle_cv / refined_dfg manifests) now compare each recorded digest with the file at the recorded commit, read with git, instead of with today's working tree. Missing history (no git, shallow clone, installed copy) raises HistoryUnavailable and the test is reported as skipped with that reason, never passed. Receipt/plan logic tests take the selected manifest directly, so their assertions run again; the pinned modes' mismatch rejections stay as negative controls. V1 (run_jet_circle_cv) keeps its pinned mode and gains --current-checkout: it records HEAD, the src tree and per-file hashes labelled as current checkout, never as the frozen qualification, and requires a clean tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2.1 KiB
Python
51 lines
2.1 KiB
Python
"""Record runtime checkout identity separately from the reviewed source origin."""
|
|
|
|
import subprocess
|
|
|
|
|
|
def checkout_provenance(repo):
|
|
"""Require a Git checkout; never label changed-source runs as historical evidence."""
|
|
revision = subprocess.check_output(
|
|
["git", "-C", str(repo), "rev-parse", "HEAD"], text=True
|
|
).strip()
|
|
dirty = subprocess.check_output(
|
|
["git", "-C", str(repo), "status", "--porcelain", "--untracked-files=normal"],
|
|
text=True,
|
|
)
|
|
return dict(checkout_revision=revision, checkout_dirty=bool(dirty))
|
|
|
|
|
|
class HistoryUnavailable(RuntimeError):
|
|
"""The clone cannot show the recorded commit (no git, shallow clone, installed copy)."""
|
|
|
|
|
|
def historical_sha256(repo, commit, paths):
|
|
"""SHA-256 of each path as stored in `commit`, read with git, never from the working tree.
|
|
|
|
Raises HistoryUnavailable when git or the commit object is missing, so callers can
|
|
report an unchecked integrity record explicitly instead of passing or failing silently.
|
|
"""
|
|
import hashlib
|
|
git = ["git", "-C", str(repo)]
|
|
try:
|
|
subprocess.run([*git, "cat-file", "-e", f"{commit}^{{commit}}"], check=True,
|
|
capture_output=True)
|
|
except (OSError, subprocess.CalledProcessError) as error:
|
|
raise HistoryUnavailable(f"commit {commit} is not available in {repo}") from error
|
|
digests = {}
|
|
for path in paths:
|
|
try:
|
|
blob = subprocess.run([*git, "show", f"{commit}:{path}"], check=True,
|
|
capture_output=True).stdout
|
|
except subprocess.CalledProcessError as error:
|
|
raise ValueError(f"{path} is not part of {commit}") from error
|
|
digests[path] = hashlib.sha256(blob).hexdigest()
|
|
return digests
|
|
|
|
|
|
def historical_tree(repo, commit, prefix="src"):
|
|
"""Tracked file names under `prefix` at `commit` (HistoryUnavailable if missing)."""
|
|
historical_sha256(repo, commit, [])
|
|
return subprocess.check_output(["git", "-C", str(repo), "ls-tree", "-r", "--name-only",
|
|
commit, "--", prefix], text=True).splitlines()
|