Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions tools/ci/nightly.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,12 @@ def installers_ready():
raise RuntimeError(
f"cannot verify deployed installer {url}: {error}"
) from error
if len(data) > 1024 * 1024 or hashlib.sha256(data).hexdigest() != expected:
raise ValueError(f"reviewed latest-only installer is not deployed: {url}")
actual = hashlib.sha256(data).hexdigest()
if len(data) > 1024 * 1024 or actual != expected:
raise ValueError(
f"reviewed installer is not deployed: {url} "
f"(expected SHA-256 {expected}, received {actual})"
)


def file_record(path):
Expand Down
4 changes: 2 additions & 2 deletions tools/ci/nightly_installers.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"https://wave-lang.dev/install.sh": "861356ad9822868ed3e5aa25438c2158ca503c62012639ea24b68c54ff274921",
"https://wave-lang.dev/install.ps1": "2dc19d0e8cfe9907d11b1a204e1812e0e53955ffc755774b4936e9eb21106995"
"https://wave-lang.dev/install.sh": "f6f38509dfa3b7d0172bf79b6eef8ed589d5261c82c09cd781b1f90d600b4b3f",
"https://wave-lang.dev/install.ps1": "5f01fb3fcae0ee9804107afe5df2d8945f2244c8acb385ed3afea10bc10d562e"
}
35 changes: 35 additions & 0 deletions tools/test_nightly.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,41 @@ def test_gate_reports_installer_url_and_exports_nothing_on_network_failure(self)
self.assertIn(str(error), stderr.getvalue())
self.assertFalse(output.exists())

def test_gate_blocks_each_unapproved_installer_without_exporting_identity(self):
identity = dict(source_sha=A, compiler_version=self.version, ci_run_id=10)
approved = b"reviewed pinned installer"
urls = list(json.loads(nightly.INSTALLERS_FILE.read_text()))
expected = hashlib.sha256(approved).hexdigest()
pins = self.root / "pins.json"
pins.write_text(json.dumps({url: expected for url in urls}))
for index, url in enumerate(urls):
for unapproved in (b"previous latest-only installer", b"changed pinned installer"):
with self.subTest(url=url, data=unapproved):
output = self.root / "mismatched-outputs"
stderr = io.StringIO()
responses = [io.BytesIO(approved) for _ in range(index)]
responses.append(io.BytesIO(unapproved))
with patch.dict(
os.environ,
{
"GITHUB_REPOSITORY": nightly.REPO,
"GITHUB_OUTPUT": str(output),
},
), patch.object(
nightly, "eligible", return_value=identity
), patch.object(
nightly, "urlopen", side_effect=responses
), patch.object(nightly, "INSTALLERS_FILE", pins), patch(
"sys.stderr", stderr
):
self.assertEqual(nightly.main(["--stage", "gate"]), 1)
self.assertIn(
f"reviewed installer is not deployed: {url}", stderr.getvalue()
)
self.assertIn(f"expected SHA-256 {expected}", stderr.getvalue())
self.assertIn(hashlib.sha256(unapproved).hexdigest(), stderr.getvalue())
self.assertFalse(output.exists())

def test_publication_is_opt_in_and_versioned_rules_remain_strict(self):
with patch.dict(os.environ, {"GITHUB_REPOSITORY": "fork/Wave"}), patch.object(
nightly, "GitHub"
Expand Down
Loading