mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
fix(delivery): verify public Helm package against qualified bytes
Readable chart metadata does not prove that the public index serves the OCI-qualified package. Pull through the consumer repository and compare exact bytes before reporting convergence, with offline regression coverage for mismatched, missing and unavailable downloads. Activation and publication authority remain unchanged. Change-source: pulse-maintainer
This commit is contained in:
@@ -275,6 +275,10 @@ jobs:
|
||||
set -euo pipefail
|
||||
public_repo="https://rcourtman.github.io/Pulse"
|
||||
public_ready=false
|
||||
public_work="$(mktemp -d)"
|
||||
trap 'rm -rf "${public_work}"' EXIT
|
||||
qualified_chart="dist/pulse-${VERSION}.tgz"
|
||||
test -f "${qualified_chart}"
|
||||
for attempt in $(seq 1 30); do
|
||||
public_index="$(mktemp)"
|
||||
if curl -fsSL --retry 2 --retry-delay 1 --retry-all-errors \
|
||||
@@ -283,7 +287,17 @@ jobs:
|
||||
helm repo remove pulse-public >/dev/null 2>&1 || true
|
||||
helm repo add pulse-public "${public_repo}" --force-update
|
||||
helm repo update pulse-public
|
||||
if helm show chart pulse-public/pulse --version "${VERSION}" >/dev/null; then
|
||||
# Metadata readability is not an exact-artifact receipt. Pull via
|
||||
# the consumer index and compare with the OCI-qualified package,
|
||||
# not the OCI manifest digest (which hashes a different object).
|
||||
rm -f "${public_work}/pulse-${VERSION}.tgz"
|
||||
if helm pull pulse-public/pulse --version "${VERSION}" --destination "${public_work}" && \
|
||||
helm show chart "${public_work}/pulse-${VERSION}.tgz" >/dev/null; then
|
||||
if ! cmp -s "${qualified_chart}" "${public_work}/pulse-${VERSION}.tgz"; then
|
||||
echo "::error::Public Helm chart bytes differ from the qualified package; refusing a successful convergence receipt."
|
||||
rm -f "${public_index}"
|
||||
exit 1
|
||||
fi
|
||||
public_ready=true
|
||||
rm -f "${public_index}"
|
||||
break
|
||||
@@ -297,4 +311,4 @@ jobs:
|
||||
echo "::error::Public Helm repository did not expose chart ${VERSION}."
|
||||
exit 1
|
||||
fi
|
||||
echo "[OK] Public Helm repository serves pulse ${VERSION}."
|
||||
echo "[OK] Public Helm repository serves the exact qualified pulse ${VERSION} package."
|
||||
|
||||
@@ -15,6 +15,22 @@
|
||||
|
||||
## Purpose
|
||||
|
||||
### Public Helm exact-package receipt
|
||||
|
||||
The post-activation public Pages verification in `.github/workflows/helm-pages.yml`
|
||||
must pull the requested chart version through the consumer repository and compare
|
||||
its archive bytes with the package already recovered through OCI qualification.
|
||||
Readable chart metadata alone is not a successful convergence receipt. The OCI
|
||||
manifest digest hashes a different object and must not be compared directly with
|
||||
the archive. A byte mismatch fails immediately; unavailable downloads retain the
|
||||
bounded retry, with previous downloaded files removed before each attempt.
|
||||
Activation bindings, publication authority and containment remain prerequisites.
|
||||
The executed-shell fixtures in `scripts/release_control/helm_pages_retry_test.py`
|
||||
cover matching, mismatched, missing and unavailable public packages without
|
||||
network or publication writes. They are not installed Helm qualification or proof
|
||||
that any historical published chart was wrong or has been repaired.
|
||||
|
||||
|
||||
The shell-owned multi-tenant integration suite uses a dedicated desktop-only
|
||||
Playwright configuration selecting the seven multi-tenant scenarios. It must
|
||||
reject any non-empty E2E tier identity rather than impersonating stable or
|
||||
|
||||
@@ -106,5 +106,56 @@ class HelmPagesRetryTests(unittest.TestCase):
|
||||
self.assertIn("--latest=false", calls[-1])
|
||||
|
||||
|
||||
class PublicReceiptTests(unittest.TestCase):
|
||||
def receipt(self, mode):
|
||||
workflow = (ROOT / '.github/workflows/helm-pages.yml').read_text()
|
||||
step = workflow.split(' - name: Verify public Pages chart\n', 1)[1]
|
||||
script = textwrap.dedent(step.split(' run: |\n', 1)[1])
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
root = Path(temp)
|
||||
(root / 'dist').mkdir()
|
||||
(root / 'dist/pulse-6.4.3.tgz').write_bytes(b'qualified')
|
||||
programs = {
|
||||
'curl': '''#!/usr/bin/env python3
|
||||
import pathlib, sys
|
||||
pathlib.Path(sys.argv[sys.argv.index('-o')+1]).write_text('version: 6.4.3\\n')
|
||||
''',
|
||||
'helm': '''#!/usr/bin/env python3
|
||||
import os, pathlib, sys
|
||||
args = sys.argv[1:]
|
||||
if args[0] == 'pull':
|
||||
mode = os.environ['MODE']
|
||||
if mode == 'unavailable': sys.exit(1)
|
||||
if mode != 'missing':
|
||||
dest = pathlib.Path(args[args.index('--destination')+1])
|
||||
(dest / 'pulse-6.4.3.tgz').write_bytes(b'qualified' if mode == 'match' else b'wrong')
|
||||
''',
|
||||
'sleep': '#!/bin/sh\nexit 0\n',
|
||||
}
|
||||
for name, body in programs.items():
|
||||
path = root / name
|
||||
path.write_text(body)
|
||||
path.chmod(0o755)
|
||||
return subprocess.run(['bash', '-c', script], cwd=root,
|
||||
env={'PATH': f"{root}:{os.environ['PATH']}",
|
||||
'VERSION': '6.4.3', 'MODE': mode},
|
||||
capture_output=True, text=True)
|
||||
|
||||
def test_matching_public_package_passes(self):
|
||||
result = self.receipt('match')
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
|
||||
def test_same_version_wrong_bytes_fail(self):
|
||||
result = self.receipt('wrong')
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertNotIn('[OK]', result.stdout)
|
||||
|
||||
def test_missing_download_fails(self):
|
||||
self.assertNotEqual(self.receipt('missing').returncode, 0)
|
||||
|
||||
def test_unavailable_download_fails(self):
|
||||
self.assertNotEqual(self.receipt('unavailable').returncode, 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -2424,7 +2424,8 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||
self.assertIn('helm repo index "${index_work}"', helm_pages)
|
||||
self.assertIn('git -C gh-pages push origin HEAD:gh-pages', helm_pages)
|
||||
self.assertIn('grep -q "version: ${VERSION}"', helm_pages)
|
||||
self.assertIn('helm show chart pulse-public/pulse --version "${VERSION}"', helm_pages)
|
||||
self.assertIn('helm pull pulse-public/pulse --version "${VERSION}"', helm_pages)
|
||||
self.assertIn('cmp -s "${qualified_chart}" "${public_work}/pulse-${VERSION}.tgz"', helm_pages)
|
||||
self.assertNotIn("helm status pulse || true", helm_pages)
|
||||
self.assertNotIn("kubectl describe pods", helm_pages)
|
||||
self.assertIn("release-convergence.yml/dispatches", release_workflow)
|
||||
|
||||
Reference in New Issue
Block a user