Skip to content

Commit 5ea78f1

Browse files
Pigbibicodex
andcommitted
Close weekly lock acquisition preflight findings
Co-Authored-By: Codex <noreply@openai.com>
1 parent 6227d65 commit 5ea78f1

4 files changed

Lines changed: 43 additions & 14 deletions

File tree

.github/workflows/pert_weekly_period_lock_acquisition.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
name: PERT Weekly Period Lock Acquisition Preflight
22

33
on:
4-
pull_request:
5-
types: [opened, synchronize, reopened]
64
workflow_dispatch:
75

86
permissions:

docs/weekly_period_lock_acquisition_preflight.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ This isolated workflow is a test-only proof of same-run GitHub Actions artifact
44
acquisition. It is not the RSS/source production pipeline and does not publish
55
producer output.
66

7+
The workflow is intentionally `workflow_dispatch`-only. A maintainer must
8+
select the exact PR head for the initial run; this keeps `actions:read` away
9+
from untrusted `pull_request` code. The one allowed rerun remains the same
10+
workflow run and therefore retains the original `github.run_id`.
11+
712
- Attempt 1 builds one deterministic representative `pert.weekly.period_lock.v1`
813
lock and one immutable input snapshot. The period and snapshot are fixed
914
fixture values; no wall-clock fallback is allowed.

scripts/period_lock_acquisition_preflight.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,21 @@ def _fixture_snapshot(lock_payload: dict[str, object]) -> dict[str, object]:
104104
}
105105

106106

107+
def _fixture_manifest(run_id: str, artifact_name: str, lock_bytes: bytes, snapshot_bytes: bytes) -> dict[str, object]:
108+
return {
109+
"bundle_version": BUNDLE_VERSION,
110+
"artifact_name": artifact_name,
111+
"source_run_id": run_id,
112+
"source_attempt": 1,
113+
"lock_version": LOCK_VERSION,
114+
"snapshot_version": SNAPSHOT_VERSION,
115+
"files": [
116+
{"name": "input_snapshot.json", "sha256": _sha256(snapshot_bytes)},
117+
{"name": "period_lock.json", "sha256": _sha256(lock_bytes)},
118+
],
119+
}
120+
121+
107122
def _assert_empty_output_dir(output_dir: Path) -> None:
108123
if output_dir.is_symlink() or not output_dir.is_dir():
109124
raise ValueError("period_lock_output_dir_invalid")
@@ -126,18 +141,7 @@ def build_bundle(output_dir: Path, run_id: str, artifact_name: str | None = None
126141
lock_bytes = serialize_period_lock(lock)
127142
snapshot = _fixture_snapshot(lock_payload)
128143
snapshot_bytes = _canonical_json(snapshot, "period_lock_snapshot_invalid")
129-
manifest = {
130-
"bundle_version": BUNDLE_VERSION,
131-
"artifact_name": expected_name,
132-
"source_run_id": run_id,
133-
"source_attempt": 1,
134-
"lock_version": LOCK_VERSION,
135-
"snapshot_version": SNAPSHOT_VERSION,
136-
"files": [
137-
{"name": "input_snapshot.json", "sha256": _sha256(snapshot_bytes)},
138-
{"name": "period_lock.json", "sha256": _sha256(lock_bytes)},
139-
],
140-
}
144+
manifest = _fixture_manifest(run_id, expected_name, lock_bytes, snapshot_bytes)
141145
manifest_bytes = _canonical_json(manifest, "period_lock_manifest_invalid")
142146
payloads = {
143147
"period_lock.json": lock_bytes,
@@ -189,6 +193,12 @@ def verify_bundle(output_dir: Path, expected_run_id: str, expected_artifact: str
189193
expected_snapshot = _fixture_snapshot(_fixture_lock_payload(expected_run_id))
190194
if snapshot != expected_snapshot:
191195
raise ValueError("period_lock_snapshot_mismatch")
196+
expected_manifest_bytes = _canonical_json(
197+
_fixture_manifest(expected_run_id, expected_artifact, payloads["period_lock.json"], payloads["input_snapshot.json"]),
198+
"period_lock_manifest_invalid",
199+
)
200+
if payloads["bundle_manifest.json"] != expected_manifest_bytes:
201+
raise ValueError("period_lock_manifest_mismatch")
192202
manifest = _parse_canonical_json(payloads["bundle_manifest.json"], "period_lock_manifest_invalid")
193203
if set(manifest) != {"bundle_version", "artifact_name", "source_run_id", "source_attempt", "lock_version", "snapshot_version", "files"}:
194204
raise ValueError("period_lock_manifest_invalid")

tests/test_period_lock_acquisition_preflight.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,27 @@ def test_verify_rejects_missing_multiple_or_wrong_attempt(tmp_path: Path) -> Non
7474
verify_bundle(wrong_attempt_dir, "29399816773", expected_artifact_name("29399816773"))
7575

7676

77+
@pytest.mark.parametrize("mutation", ["reorder", "duplicate"])
78+
def test_verify_rejects_manifest_record_mutation(tmp_path: Path, mutation: str) -> None:
79+
build_bundle(tmp_path, "29399816773")
80+
manifest_path = tmp_path / "bundle_manifest.json"
81+
manifest = json.loads(manifest_path.read_bytes())
82+
if mutation == "reorder":
83+
manifest["files"] = list(reversed(manifest["files"]))
84+
else:
85+
manifest["files"].append(manifest["files"][0])
86+
manifest_path.write_bytes(json.dumps(manifest, sort_keys=True, separators=(",", ":")).encode())
87+
with pytest.raises(ValueError, match="period_lock_manifest_mismatch"):
88+
verify_bundle(tmp_path, "29399816773", expected_artifact_name("29399816773"))
89+
90+
7791
def test_workflow_isolated_and_minimally_permissioned() -> None:
7892
workflow = Path(".github/workflows/pert_weekly_period_lock_acquisition.yml").read_text(encoding="utf-8")
7993
assert "actions: read" in workflow
8094
assert "contents: read" in workflow
8195
assert "artifact-metadata: write" in workflow
96+
assert "workflow_dispatch:" in workflow
97+
assert "pull_request:" not in workflow
8298
assert "contents: write" not in workflow
8399
assert "id-token:" not in workflow
84100
assert "secrets." not in workflow

0 commit comments

Comments
 (0)