mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 02:55:51 +00:00
5e30bbb346
Keep convergence recoverable after short-lived Actions artifacts expire by preserving the exact digest-bound package already verified from GHCR. Change-source: pulse-maintainer
150 lines
5.2 KiB
Python
150 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tempfile
|
|
import textwrap
|
|
import unittest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
SCRIPT = ROOT / "scripts" / "verify-release-helm-chart.sh"
|
|
SOURCE_SHA = "a" * 40
|
|
DIGEST = "sha256:" + "b" * 64
|
|
|
|
|
|
class VerifyReleaseHelmChartTests(unittest.TestCase):
|
|
def run_verifier(
|
|
self,
|
|
*,
|
|
digest: str = DIGEST,
|
|
expected_digest: str = "",
|
|
gh_exit: int = 0,
|
|
gh_version: str = "2.97.0",
|
|
output_chart: bool = False,
|
|
source_sha: str = SOURCE_SHA,
|
|
) -> tuple[subprocess.CompletedProcess[str], str, bool]:
|
|
with tempfile.TemporaryDirectory() as temp:
|
|
temp_path = Path(temp)
|
|
bin_path = temp_path / "bin"
|
|
bin_path.mkdir()
|
|
gh_log = temp_path / "gh.log"
|
|
(bin_path / "helm").write_text(
|
|
textwrap.dedent(
|
|
"""\
|
|
#!/bin/sh
|
|
printf 'Pulled: ghcr.io/rcourtman/pulse-chart/pulse:6.4.1\n'
|
|
printf 'Digest: %s\n' "$CHART_DIGEST"
|
|
: > "$6/pulse-6.4.1.tgz"
|
|
"""
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
(bin_path / "gh").write_text(
|
|
textwrap.dedent(
|
|
"""\
|
|
#!/bin/sh
|
|
if [ "$1" = version ]; then
|
|
printf 'gh version %s (test)\n' "$GH_VERSION"
|
|
exit 0
|
|
fi
|
|
printf '%s\n' "$*" >> "$GH_LOG"
|
|
exit "$GH_EXIT"
|
|
"""
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
for command in (bin_path / "helm", bin_path / "gh"):
|
|
command.chmod(0o755)
|
|
|
|
env = os.environ.copy()
|
|
env.update(
|
|
{
|
|
"PATH": f"{bin_path}:{env['PATH']}",
|
|
"CHART_DIGEST": digest,
|
|
"GH_LOG": str(gh_log),
|
|
"GH_EXIT": str(gh_exit),
|
|
"GH_VERSION": gh_version,
|
|
}
|
|
)
|
|
args = [str(SCRIPT), "v6.4.1", source_sha, "rcourtman/Pulse"]
|
|
if expected_digest or output_chart:
|
|
args.append(expected_digest)
|
|
output_path = temp_path / "recovered.tgz"
|
|
if output_chart:
|
|
args.append(str(output_path))
|
|
result = subprocess.run(
|
|
args,
|
|
cwd=ROOT,
|
|
env=env,
|
|
text=True,
|
|
capture_output=True,
|
|
check=False,
|
|
)
|
|
return (
|
|
result,
|
|
gh_log.read_text(encoding="utf-8") if gh_log.exists() else "",
|
|
output_path.is_file(),
|
|
)
|
|
|
|
def test_emits_digest_after_exact_hosted_provenance_verification(self) -> None:
|
|
result, calls, _ = self.run_verifier()
|
|
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(result.stdout.strip(), f"chart_digest={DIGEST}")
|
|
self.assertIn(f"oci://ghcr.io/rcourtman/pulse-chart/pulse@{DIGEST}", calls)
|
|
self.assertIn("--repo rcourtman/Pulse", calls)
|
|
self.assertIn("--bundle-from-oci", calls)
|
|
self.assertIn(
|
|
"--signer-workflow github.com/rcourtman/Pulse/.github/workflows/publish-helm-chart.yml",
|
|
calls,
|
|
)
|
|
self.assertIn(f"--source-digest {SOURCE_SHA}", calls)
|
|
self.assertIn("--deny-self-hosted-runners", calls)
|
|
self.assertIn("--predicate-type https://slsa.dev/provenance/v1", calls)
|
|
|
|
def test_rejects_a_chart_that_moved_after_activation(self) -> None:
|
|
expected = "sha256:" + "c" * 64
|
|
result, calls, _ = self.run_verifier(expected_digest=expected)
|
|
|
|
self.assertNotEqual(result.returncode, 0)
|
|
self.assertIn("Exact-version Helm chart moved", result.stderr)
|
|
self.assertEqual(calls, "")
|
|
|
|
def test_rejects_missing_or_malformed_registry_digest(self) -> None:
|
|
result, calls, _ = self.run_verifier(digest="unknown")
|
|
|
|
self.assertNotEqual(result.returncode, 0)
|
|
self.assertIn("did not report one exact OCI digest", result.stderr)
|
|
self.assertEqual(calls, "")
|
|
|
|
def test_rejects_unsafe_github_cli_before_registry_resolution(self) -> None:
|
|
result, calls, _ = self.run_verifier(gh_version="2.96.1")
|
|
|
|
self.assertNotEqual(result.returncode, 0)
|
|
self.assertIn("too old for release attestation policy enforcement", result.stderr)
|
|
self.assertEqual(calls, "")
|
|
|
|
def test_rejects_invalid_source_identity(self) -> None:
|
|
result, calls, _ = self.run_verifier(source_sha="main")
|
|
|
|
self.assertNotEqual(result.returncode, 0)
|
|
self.assertIn("Invalid release source SHA", result.stderr)
|
|
self.assertEqual(calls, "")
|
|
|
|
def test_preserves_the_verified_oci_package_for_promotion(self) -> None:
|
|
result, _, output_exists = self.run_verifier(
|
|
expected_digest=DIGEST,
|
|
output_chart=True,
|
|
)
|
|
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertTrue(output_exists)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|