test(infra): bind historical evidence to its original snapshot
Build and Test Quality Gate / Contract Web typecheck and build (push) Successful in 6m0s
Build and Test Quality Gate / Isolated Alibaba and Tencent KMS gateway (push) Failing after 1m7s
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (push) Failing after 11m20s
Build and Test Quality Gate / Python tests and Contract API migration (push) Failing after 41m48s
Build and Test Quality Gate / Contract Web typecheck and build (push) Successful in 6m0s
Build and Test Quality Gate / Isolated Alibaba and Tencent KMS gateway (push) Failing after 1m7s
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (push) Failing after 11m20s
Build and Test Quality Gate / Python tests and Contract API migration (push) Failing after 41m48s
Keep historical RC03 hashes independent of later source changes while verifying every current manifest item against its committed blob.
This commit is contained in:
@@ -42,9 +42,9 @@ def _git(repo: Path, *args: str) -> str:
|
||||
return completed.stdout.strip()
|
||||
|
||||
|
||||
def _git_blob(repo: Path, path: str) -> bytes:
|
||||
def _git_blob(repo: Path, path: str, revision: str = "HEAD") -> bytes:
|
||||
completed = subprocess.run(
|
||||
["git", "-C", str(repo), "cat-file", "blob", f"HEAD:{path}"],
|
||||
["git", "-C", str(repo), "cat-file", "blob", f"{revision}:{path}"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
)
|
||||
@@ -411,53 +411,6 @@ def test_manifest_is_deterministic_and_summarizes_complete_committed_graph(tmp_p
|
||||
"**/*.sqlite3",
|
||||
} <= dockerignore_rules
|
||||
|
||||
current_index = json.loads(
|
||||
(
|
||||
REPO_ROOT
|
||||
/ "docs/qa/multiscene-closeout-20260910/rc03-current-candidate-evidence-index-v3.json"
|
||||
).read_text(encoding="utf-8")
|
||||
)
|
||||
assert current_index["validation"]["self_contained"] is True
|
||||
assert current_index["validation"]["predecessor_required_for_interpretation"] is False
|
||||
assert current_index["validation"]["listed_file_count"] == 54
|
||||
assert current_index["validation"]["accepted_current_evidence_count"] == 50
|
||||
assert current_index["validation"]["excluded_invalid_lineage_count"] == 4
|
||||
assert all(item["normative_for_v3"] is False for item in current_index["lineage"])
|
||||
indexed_paths = [item["path"] for item in current_index["files"]]
|
||||
assert len(indexed_paths) == len(set(indexed_paths)) == 54
|
||||
for item in current_index["files"]:
|
||||
evidence = REPO_ROOT / item["path"]
|
||||
category, _, _ = ownership.classify_path(item["path"], size=item["size_bytes"])
|
||||
if category == "generated_evidence_retain_exclude":
|
||||
# Raw and invalid-lineage QA outputs are intentionally retained outside
|
||||
# the immutable source candidate. When they remain in a development
|
||||
# workspace, still verify that the compact index recorded their bytes
|
||||
# correctly; a clean release checkout must not require them to exist.
|
||||
if not evidence.exists():
|
||||
continue
|
||||
evidence_bytes = evidence.read_bytes()
|
||||
else:
|
||||
assert category in {"release_source_include", "release_test_include"}
|
||||
assert evidence.is_file()
|
||||
# Verify the immutable Git bytes instead of checkout bytes: Windows may
|
||||
# materialize text files with CRLF. The RC-03 index was created from
|
||||
# worktree bytes, so accept only an exact LF/CRLF rendering of the same
|
||||
# immutable blob; the candidate manifest/archive bind the raw blob.
|
||||
evidence_bytes = _git_blob(REPO_ROOT, item["path"])
|
||||
variants = _text_eol_variants(evidence_bytes)
|
||||
assert any(
|
||||
len(candidate) == item["size_bytes"]
|
||||
and hashlib.sha256(candidate).hexdigest() == item["sha256"]
|
||||
for candidate in variants
|
||||
)
|
||||
if item["path"].endswith(".json"):
|
||||
json.loads(evidence_bytes)
|
||||
continue
|
||||
assert len(evidence_bytes) == item["size_bytes"]
|
||||
assert hashlib.sha256(evidence_bytes).hexdigest() == item["sha256"]
|
||||
if item["path"].endswith(".json"):
|
||||
json.loads(evidence_bytes)
|
||||
|
||||
repo, commit = _candidate_repo(tmp_path)
|
||||
output = tmp_path / "manifest.json"
|
||||
|
||||
@@ -474,6 +427,10 @@ def test_manifest_is_deterministic_and_summarizes_complete_committed_graph(tmp_p
|
||||
assert first["summaries"]["migrations"][0]["heads"] == ["contract-head"]
|
||||
assert first["summaries"]["migrations"][1]["heads"] == ["ai-head"]
|
||||
recorded_paths = {item["path"] for item in first["files"]["items"]}
|
||||
for item in first["files"]["items"]:
|
||||
content = _git_blob(repo, item["path"], commit)
|
||||
assert item["size"] == len(content)
|
||||
assert item["sha256"] == hashlib.sha256(content).hexdigest()
|
||||
assert set(manifest.RELEASE_CONTROL_PATHS) <= recorded_paths
|
||||
configuration_paths = {item["path"] for item in first["summaries"]["configuration"]}
|
||||
assert set(manifest.RELEASE_CONTROL_PATHS) <= configuration_paths
|
||||
@@ -490,6 +447,49 @@ def test_manifest_is_deterministic_and_summarizes_complete_committed_graph(tmp_p
|
||||
assert "No image was built or assigned a digest" in first["claims_not_made"][0]
|
||||
|
||||
|
||||
def test_historical_rc03_index_matches_original_committed_snapshot() -> None:
|
||||
if _git(REPO_ROOT, "rev-parse", "--is-shallow-repository") == "true":
|
||||
pytest.skip("historical RC03 byte verification requires complete Git history")
|
||||
index_path = "docs/qa/multiscene-closeout-20260910/rc03-current-candidate-evidence-index-v3.json"
|
||||
index_commit = _git(REPO_ROOT, "log", "-1", "--diff-filter=A", "--format=%H", "--", index_path)
|
||||
assert index_commit
|
||||
historical_index = json.loads((REPO_ROOT / index_path).read_text(encoding="utf-8"))
|
||||
assert historical_index == json.loads(_git_blob(REPO_ROOT, index_path, index_commit))
|
||||
assert historical_index["release_claim"] is False
|
||||
assert historical_index["validation"]["self_contained"] is True
|
||||
assert historical_index["validation"]["predecessor_required_for_interpretation"] is False
|
||||
assert historical_index["validation"]["listed_file_count"] == 54
|
||||
assert historical_index["validation"]["accepted_current_evidence_count"] == 50
|
||||
assert historical_index["validation"]["excluded_invalid_lineage_count"] == 4
|
||||
assert all(item["normative_for_v3"] is False for item in historical_index["lineage"])
|
||||
indexed_paths = [item["path"] for item in historical_index["files"]]
|
||||
assert len(indexed_paths) == len(set(indexed_paths)) == 54
|
||||
for item in historical_index["files"]:
|
||||
evidence = REPO_ROOT / item["path"]
|
||||
category, _, _ = ownership.classify_path(item["path"], size=item["size_bytes"])
|
||||
if category == "generated_evidence_retain_exclude":
|
||||
if not evidence.exists():
|
||||
continue
|
||||
evidence_bytes = evidence.read_bytes()
|
||||
else:
|
||||
assert category in {"release_source_include", "release_test_include"}
|
||||
evidence_bytes = _git_blob(REPO_ROOT, item["path"], index_commit)
|
||||
# The historical index recorded worktree bytes; bind its own source snapshot, not today's HEAD.
|
||||
variants = _text_eol_variants(evidence_bytes)
|
||||
assert any(
|
||||
len(candidate) == item["size_bytes"]
|
||||
and hashlib.sha256(candidate).hexdigest() == item["sha256"]
|
||||
for candidate in variants
|
||||
)
|
||||
if item["path"].endswith(".json"):
|
||||
json.loads(evidence_bytes)
|
||||
continue
|
||||
assert len(evidence_bytes) == item["size_bytes"]
|
||||
assert hashlib.sha256(evidence_bytes).hexdigest() == item["sha256"]
|
||||
if item["path"].endswith(".json"):
|
||||
json.loads(evidence_bytes)
|
||||
|
||||
|
||||
def test_manifest_refuses_ambiguous_dirty_missing_and_secret_candidates(tmp_path: Path) -> None:
|
||||
repo, commit = _candidate_repo(tmp_path)
|
||||
external_output = tmp_path / "manifest.json"
|
||||
|
||||
Reference in New Issue
Block a user