From 8d5747f5ce1d57e525ce89f08f4cafb0eeefd555 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 11 Aug 2026 17:36:14 +0900 Subject: [PATCH 1/2] fix(reliability): bound release evidence Git metadata lookup Fail closed when git rev-parse hangs during release evidence indexing. --- ...8-release-evidence-git-metadata-timeout.md | 5 +++ scripts/build_release_evidence_index.py | 7 ++++ ...t_release_evidence_git_metadata_timeout.py | 40 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 docs/changelog.d/708-release-evidence-git-metadata-timeout.md create mode 100644 tests/test_release_evidence_git_metadata_timeout.py diff --git a/docs/changelog.d/708-release-evidence-git-metadata-timeout.md b/docs/changelog.d/708-release-evidence-git-metadata-timeout.md new file mode 100644 index 000000000..4d61f6041 --- /dev/null +++ b/docs/changelog.d/708-release-evidence-git-metadata-timeout.md @@ -0,0 +1,5 @@ +# Release evidence Git metadata timeout + +### Fixed + +- Bound `git rev-parse` in the release evidence index builder with a fail-closed timeout. diff --git a/scripts/build_release_evidence_index.py b/scripts/build_release_evidence_index.py index 6547a2c4e..e4aef6804 100644 --- a/scripts/build_release_evidence_index.py +++ b/scripts/build_release_evidence_index.py @@ -18,6 +18,9 @@ from _bounded_json import read_json_object +GIT_METADATA_TIMEOUT_SECONDS = 5 + + REQUIRED_COVERAGE = { "acceptance_summary", "sales_readiness_manifest", @@ -45,6 +48,7 @@ def _sha256(path: Path) -> str: def _source_commit(repo_root: Path) -> str: + """Return HEAD SHA, failing closed when Git metadata lookup times out.""" try: completed = subprocess.run( ["git", "rev-parse", "HEAD"], @@ -52,7 +56,10 @@ def _source_commit(repo_root: Path) -> str: capture_output=True, text=True, check=True, + timeout=GIT_METADATA_TIMEOUT_SECONDS, ) + except subprocess.TimeoutExpired as exc: + raise RuntimeError("source commit lookup timed out") from exc except Exception: return "unknown" return completed.stdout.strip() or "unknown" diff --git a/tests/test_release_evidence_git_metadata_timeout.py b/tests/test_release_evidence_git_metadata_timeout.py new file mode 100644 index 000000000..639d8754f --- /dev/null +++ b/tests/test_release_evidence_git_metadata_timeout.py @@ -0,0 +1,40 @@ +"""Fail-first reliability contracts for release evidence Git metadata reads.""" + +from __future__ import annotations + +import importlib.util +import subprocess +from pathlib import Path + +import pytest + + +def _load_release_index(): + """Load the release evidence index builder for boundary tests.""" + script = Path(__file__).resolve().parents[1] / "scripts" / "build_release_evidence_index.py" + spec = importlib.util.spec_from_file_location("build_release_evidence_index", script) + assert spec is not None + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + spec.loader.exec_module(module) + return module + + +def test_source_commit_bounds_git_metadata_lookup(monkeypatch, tmp_path: Path) -> None: + """A hung ``git rev-parse`` must fail closed under a package-owned deadline.""" + module = _load_release_index() + observed_timeouts: list[object] = [] + + def timeout_run(*args, **kwargs): + observed_timeouts.append(kwargs.get("timeout")) + raise subprocess.TimeoutExpired( + cmd=args[0] if args else kwargs.get("args", ["git", "rev-parse", "HEAD"]), + timeout=kwargs.get("timeout"), + ) + + monkeypatch.setattr(module.subprocess, "run", timeout_run) + + with pytest.raises(RuntimeError, match="source commit lookup timed out"): + module._source_commit(tmp_path) + + assert observed_timeouts == [module.GIT_METADATA_TIMEOUT_SECONDS] From 9c2f96559a86af4dd2dd91bb5ba686420d376500 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 11 Aug 2026 18:04:32 +0900 Subject: [PATCH 2/2] docs(changelog): use H2 section headings for fragment contract --- docs/changelog.d/708-release-evidence-git-metadata-timeout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.d/708-release-evidence-git-metadata-timeout.md b/docs/changelog.d/708-release-evidence-git-metadata-timeout.md index 4d61f6041..de75454cf 100644 --- a/docs/changelog.d/708-release-evidence-git-metadata-timeout.md +++ b/docs/changelog.d/708-release-evidence-git-metadata-timeout.md @@ -1,5 +1,5 @@ # Release evidence Git metadata timeout -### Fixed +## Fixed - Bound `git rev-parse` in the release evidence index builder with a fail-closed timeout.