Merge commit '6998908d2a387f1ded356750c3ac9424f3beb04a'

Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-09-05 17:35:17 +01:00
3 changed files with 62 additions and 2 deletions
@@ -410,8 +410,8 @@ jobs:
INITIAL_STATE="${WORKFLOW_OUTPUT_1}"
if [ "$INITIAL_STATE" = "true" ]; then
HEADER_LINE="## ✅ Release Asset Validation: PASSED"
STATUS_LINE="**Status**: Ready for publication ✅"
INTRO_LINE="All release assets have been validated successfully!"
STATUS_LINE="**Status**: Release asset checks passed ✅"
INTRO_LINE="The required release asset checks passed."
else
HEADER_LINE="## ✅ Release Asset Validation (Post-Publish): PASSED"
STATUS_LINE="**Status**: Live release assets re-validated ✅"
@@ -450,6 +450,9 @@ jobs:
- Version strings correct ✓
- Binary architectures validated ✓
Asset validation alone does not establish installed-service health,
release convergence, clean soak or approval for stable publication.
<!-- VALIDATION_STATUS_END -->
EOF
@@ -449,6 +449,13 @@ may delete invalid assets and rewrite validation annotations only while a
release is still a draft. A post-publication edit is observation, not authority
to mutate or destroy an immutable release; failed revalidation records a
failing status and requires an explicit corrective release path.
Asset-validation banners report asset checks only, never publication readiness.
Both draft and post-publication banners must explicitly distinguish asset checks
from installed-service health, release convergence, clean soak and stable
publication approval, while retaining the individual check summary.
`scripts/release_control/render_release_body_test.py` executes the workflow
wording branch for both states and verifies these reporting limits; this local
proof does not qualify an installed service or authorise release mutation.
The activation marker is part of that complete draft packet: its stored digest
must be checked before publication, and customer convergence is forbidden until
GitHub reports the release immutable and its signed release attestation verifies.
@@ -4,6 +4,8 @@
from __future__ import annotations
import re
import subprocess
import textwrap
import tempfile
import unittest
from pathlib import Path
@@ -814,5 +816,53 @@ Rollback details.
self.assertIn("Push", blurb)
class AssetValidationWordingTest(unittest.TestCase):
def render_banner(self, draft: bool) -> str:
source = (_REPO_ROOT / ".github/workflows/validate-release-assets.yml").read_text(encoding="utf-8")
# Execute only the actual local wording branch and banner heredoc,
# never the workflow's GitHub reads/writes or release mutation code.
branch = source.split(' if [ "$INITIAL_STATE" = "true" ]; then\n', 1)[1]
branch = 'if [ "$INITIAL_STATE" = "true" ]; then\n' + branch.split(
"\n fi", 1
)[0] + "\nfi\n"
template = textwrap.dedent(source.split(
" read -r -d '' VALIDATION_BLOCK <<'EOF' || true\n", 1
)[1].split("\n EOF", 1)[0])
result = subprocess.run(
["bash", "-eu", "-c", 'INITIAL_STATE="$1"\n' + branch
+ "printf '%s\\n' \"$HEADER_LINE\" \"$INTRO_LINE\" \"$STATUS_LINE\"",
"wording-test", str(draft).lower()],
check=True, capture_output=True, text=True, timeout=5,
)
header, intro, status = result.stdout.splitlines()
return template.replace("HEADER_PLACEHOLDER", header).replace(
"INTRO_PLACEHOLDER", intro
).replace("STATUS_PLACEHOLDER", status)
def test_draft_reports_asset_checks_not_publication_readiness(self) -> None:
banner = self.render_banner(True)
self.assertIn("**Status**: Release asset checks passed", banner)
self.assertNotIn("Ready for publication", banner)
self.assertIn("## ✅ Release Asset Validation: PASSED", banner)
def test_published_release_still_reports_revalidation(self) -> None:
banner = self.render_banner(False)
self.assertIn("Release Asset Validation (Post-Publish): PASSED", banner)
self.assertIn("Live release assets re-validated", banner)
self.assertNotIn("Ready for publication", banner)
def test_both_banners_explain_limits_without_losing_check_summary(self) -> None:
for draft in (True, False):
with self.subTest(draft=draft):
banner = self.render_banner(draft)
self.assertIn("Asset validation alone does not establish installed-service health,", banner)
self.assertIn("release convergence, clean soak or approval for stable publication.", banner)
for check in ("All required assets present", "Checksums verified",
"Version strings correct", "Binary architectures validated"):
self.assertIn(check, banner)
self.assertIn("<!-- VALIDATION_STATUS_START -->", banner)
self.assertIn("<!-- VALIDATION_STATUS_END -->", banner)
if __name__ == "__main__":
unittest.main()