mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
Keep server rollback guidance executable
This commit is contained in:
+2
-2
@@ -260,7 +260,7 @@ Yes. Keep a rollback path available while you evaluate v6. The final release
|
||||
on the v5 line is 5.1.36, so the stable rollback command is:
|
||||
|
||||
```bash
|
||||
./scripts/install.sh --version v5.1.36
|
||||
sudo /bin/update --version v5.1.36
|
||||
```
|
||||
|
||||
### Why did my v5 install upgrade itself to v6?
|
||||
@@ -273,7 +273,7 @@ your data and configuration carry over; run through the Post-Upgrade
|
||||
Checklist above to confirm everything still works. To return to v5, run:
|
||||
|
||||
```bash
|
||||
./scripts/install.sh --version v5.1.36
|
||||
sudo /bin/update --version v5.1.36
|
||||
```
|
||||
|
||||
## Migration Notes (v6)
|
||||
|
||||
@@ -100,6 +100,16 @@ upgrade must recover those values from both split and `--key=value` service
|
||||
arguments and reproduce them in the generated systemd command without
|
||||
discarding existing explicit disk exclusions.
|
||||
|
||||
Published exact-version install and rollback guidance must preserve the server
|
||||
and Unified Agent installer boundary. Supported systemd and Proxmox LXC
|
||||
deployments use the signed `/bin/update --version vX.Y.Z` server helper;
|
||||
`/opt/pulse/scripts/install.sh` and release archives' `scripts/install.sh` are
|
||||
Unified Agent installers and must never be presented as server rollback
|
||||
commands. Docker guidance instead pins the target image and recreates the
|
||||
container. The promotion resolver, manual release trigger, rendered release
|
||||
body, current release packet, and shipped upgrade guide must agree on those
|
||||
deployment-specific paths.
|
||||
|
||||
The accelerated exact-SHA release worker must preserve release-gate fidelity
|
||||
under its own resource envelope. Bounded frontend static checks and integration
|
||||
image preparation may overlap, but the full frontend test suite and the
|
||||
@@ -1740,6 +1750,11 @@ artifact-selection behaviour.
|
||||
`frontend-modern/public/docs/UPGRADE_v6.md` byte-synchronized. The shipped
|
||||
copy is part of every release packet, and `docsLinks.test.ts` must fail when
|
||||
release preparation changes only one side.
|
||||
16. Keep generated install and rollback instructions deployment-specific.
|
||||
`scripts/installtests/build_release_assets_test.go` must reject a release
|
||||
trigger, promotion resolver, rendered release body, current upgrade guide,
|
||||
or current release packet that routes systemd/LXC rollback through the
|
||||
Unified Agent installer, and must retain explicit Docker image guidance.
|
||||
|
||||
## Current State
|
||||
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
- Existing configurations remain valid. Alert identity and history migrations run automatically, with no manual data migration required.
|
||||
- Pulse Mobile iOS build 12 and Android versionCode 9 remain compatible. The new `alert_fired` push uses the existing `view_alert` action, so no companion mobile release is required.
|
||||
- Windows Unified Agent binaries are not Authenticode-signed while SignPath remains unavailable and may show an Unknown Publisher warning. Verify downloads with the published checksums and detached signatures.
|
||||
- The rollback target is stable `v6.3.2`. Use `./scripts/install.sh --version v6.3.2` if you need to return to the previous stable release.
|
||||
- The rollback target is stable `v6.3.2`. On systemd and Proxmox LXC installs, use `sudo /bin/update --version v6.3.2` if you need to return to the previous stable release. For Docker Compose, pin the image to `rcourtman/pulse:6.3.2` and recreate the container.
|
||||
|
||||
@@ -60,7 +60,7 @@ This changelog describes the complete stable release train since `v6.3.2`.
|
||||
- Promoted prerelease: `v6.4.0-rc.12`
|
||||
- Runtime content cutoff: `18b22d1ebbfe542484652e419320fc7643a792f0`
|
||||
- Rollback target: `v6.3.2`
|
||||
- Rollback command: `./scripts/install.sh --version v6.3.2`
|
||||
- Rollback command: `sudo /bin/update --version v6.3.2`
|
||||
- Promotion path: owner-approved expedited exact-SHA stable cutoff from `main`
|
||||
- Promotion decision: the release owner accepted a shortened soak to deliver bounded fixes for active monitoring correctness and collection-load harm. This is version-bound risk acceptance, not soak evidence or a standing exception.
|
||||
- Windows signing decision: the standing SignPath-unavailable policy applies. Windows agents are not Authenticode-signed, may show an Unknown Publisher warning, and retain exact-SHA checksums, detached signatures, immutable-manifest verification, and published-digest verification.
|
||||
|
||||
@@ -260,7 +260,7 @@ Yes. Keep a rollback path available while you evaluate v6. The final release
|
||||
on the v5 line is 5.1.36, so the stable rollback command is:
|
||||
|
||||
```bash
|
||||
./scripts/install.sh --version v5.1.36
|
||||
sudo /bin/update --version v5.1.36
|
||||
```
|
||||
|
||||
### Why did my v5 install upgrade itself to v6?
|
||||
@@ -273,7 +273,7 @@ your data and configuration carry over; run through the Post-Upgrade
|
||||
Checklist above to confirm everything still works. To return to v5, run:
|
||||
|
||||
```bash
|
||||
./scripts/install.sh --version v5.1.36
|
||||
sudo /bin/update --version v5.1.36
|
||||
```
|
||||
|
||||
## Migration Notes (v6)
|
||||
|
||||
@@ -3270,6 +3270,38 @@ func TestReleaseTriggersReevaluateVisualsInsteadOfTrustingSidecars(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseRollbackGuidanceUsesServerUpdateHelper(t *testing.T) {
|
||||
for _, path := range []string{
|
||||
repoFile("scripts", "trigger-release.sh"),
|
||||
repoFile("scripts", "release_control", "resolve_release_promotion.py"),
|
||||
repoFile("scripts", "release_control", "render_release_body.py"),
|
||||
repoFile("docs", "UPGRADE_v6.md"),
|
||||
repoFile("frontend-modern", "public", "docs", "UPGRADE_v6.md"),
|
||||
repoFile("docs", "releases", "RELEASE_NOTES_v6.4.0.md"),
|
||||
repoFile("docs", "releases", "V6_CHANGELOG_v6.4.0.md"),
|
||||
} {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read %s: %v", path, err)
|
||||
}
|
||||
text := string(content)
|
||||
if !strings.Contains(text, "/bin/update --version") {
|
||||
t.Fatalf("%s must route systemd/LXC exact-version changes through the server update helper", path)
|
||||
}
|
||||
if strings.Contains(text, "./scripts/install.sh --version") {
|
||||
t.Fatalf("%s routes server rollback through the Unified Agent installer", path)
|
||||
}
|
||||
}
|
||||
|
||||
renderer, err := os.ReadFile(repoFile("scripts", "release_control", "render_release_body.py"))
|
||||
if err != nil {
|
||||
t.Fatalf("read release body renderer: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(renderer), "For Docker Compose, set the Pulse image to the rollback target") {
|
||||
t.Fatal("release body renderer must retain deployment-specific Docker rollback guidance")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommittedReleaseVisualSidecarsCarrySelectionEvidence(t *testing.T) {
|
||||
paths, err := filepath.Glob(repoFile("docs", "releases", "*.visuals.json"))
|
||||
if err != nil {
|
||||
|
||||
@@ -24,7 +24,7 @@ SUMMARY = """# Prerelease-to-GA Rehearsal Summary
|
||||
- Promotion channel: stable
|
||||
- Promoted prerelease tag: v6.0.0-rc.1
|
||||
- Rollback target: v5.1.23
|
||||
- Rollback command: `./scripts/install.sh --version v5.1.23`
|
||||
- Rollback command: `sudo /bin/update --version v5.1.23`
|
||||
- Prerelease soak hours at rehearsal time: 96
|
||||
- Planned GA date: 2026-03-15
|
||||
- Planned v5 end-of-support date: 2026-06-11
|
||||
@@ -43,7 +43,7 @@ class RecordRcToGaRehearsalTest(unittest.TestCase):
|
||||
self.assertEqual(parsed["tag"], "v6.0.0")
|
||||
self.assertEqual(parsed["channel_under_rehearsal"], "stable")
|
||||
self.assertEqual(parsed["promoted_from_rc"], "v6.0.0-rc.1")
|
||||
self.assertEqual(parsed["rollback_command"], "`./scripts/install.sh --version v5.1.23`")
|
||||
self.assertEqual(parsed["rollback_command"], "`sudo /bin/update --version v5.1.23`")
|
||||
self.assertEqual(parsed["planned_ga_date"], "2026-03-15")
|
||||
self.assertEqual(parsed["planned_v5_eos_date"], "2026-06-11")
|
||||
self.assertEqual(parsed["windows_authenticode_required"], "false")
|
||||
@@ -53,7 +53,7 @@ class RecordRcToGaRehearsalTest(unittest.TestCase):
|
||||
rendered = mod.render_record(
|
||||
record_date="2026-03-12",
|
||||
result="pass",
|
||||
rollback_command="./scripts/install.sh --version v5.1.23",
|
||||
rollback_command="sudo /bin/update --version v5.1.23",
|
||||
run_metadata={"headSha": "abc123", "url": "https://github.com/rcourtman/Pulse/actions/runs/12345"},
|
||||
summary_metadata=mod.parse_summary_markdown(SUMMARY),
|
||||
summary_source="/tmp/rc-to-ga-rehearsal-summary.md",
|
||||
@@ -67,7 +67,7 @@ class RecordRcToGaRehearsalTest(unittest.TestCase):
|
||||
self.assertIn("Candidate stable tag: v6.0.0", rendered)
|
||||
self.assertIn("Promotion channel: stable", rendered)
|
||||
self.assertIn("Promoted prerelease tag: v6.0.0-rc.1", rendered)
|
||||
self.assertIn("Exact rollback or reinstall command: `./scripts/install.sh --version v5.1.23`", rendered)
|
||||
self.assertIn("Exact rollback or reinstall command: `sudo /bin/update --version v5.1.23`", rendered)
|
||||
self.assertIn("Exact GA date to publish: 2026-03-15", rendered)
|
||||
self.assertIn("Exact v5 end-of-support date to publish: 2026-06-13", rendered)
|
||||
self.assertIn("Windows Authenticode required: false", rendered)
|
||||
@@ -98,7 +98,7 @@ class RecordRcToGaRehearsalTest(unittest.TestCase):
|
||||
self.assertIn("v6.0.0-rc.1", content)
|
||||
self.assertIn("Promotion channel: stable", content)
|
||||
self.assertIn("2026-03-15", content)
|
||||
self.assertIn("Exact rollback or reinstall command: `./scripts/install.sh --version v5.1.23`", content)
|
||||
self.assertIn("Exact rollback or reinstall command: `sudo /bin/update --version v5.1.23`", content)
|
||||
|
||||
def test_main_defaults_output_to_canonical_record_path(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
@@ -231,7 +231,7 @@ class RecordRcToGaRehearsalTest(unittest.TestCase):
|
||||
|
||||
def test_main_requires_rollback_command_when_summary_omits_it(self) -> None:
|
||||
summary_without_command = SUMMARY.replace(
|
||||
"- Rollback command: `./scripts/install.sh --version v5.1.23`\n", ""
|
||||
"- Rollback command: `sudo /bin/update --version v5.1.23`\n", ""
|
||||
)
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
tmp_path = Path(tmp)
|
||||
@@ -306,7 +306,7 @@ class RecordRcToGaRehearsalTest(unittest.TestCase):
|
||||
"--v5-eos-date",
|
||||
"2026-06-11",
|
||||
"--rollback-command",
|
||||
"./scripts/install.sh --version v5.1.23",
|
||||
"sudo /bin/update --version v5.1.23",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ def resolve_metadata(
|
||||
)
|
||||
if not tag_exists_fn(rollback_tag):
|
||||
raise ValueError(f"rollback_version {rollback_tag} does not exist as a repository tag.")
|
||||
rollback_command = f"./scripts/install.sh --version {rollback_tag}"
|
||||
rollback_command = f"sudo /bin/update --version {rollback_tag}"
|
||||
|
||||
promoted_from_tag = ""
|
||||
soak_hours = ""
|
||||
|
||||
@@ -38,7 +38,7 @@ class ResolveReleasePromotionTest(unittest.TestCase):
|
||||
tag_exists_fn=lambda tag: tag == "v5.1.14",
|
||||
)
|
||||
self.assertEqual(metadata["rollback_tag"], "v5.1.14")
|
||||
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v5.1.14")
|
||||
self.assertEqual(metadata["rollback_command"], "sudo /bin/update --version v5.1.14")
|
||||
self.assertEqual(metadata["promoted_from_tag"], "")
|
||||
self.assertEqual(metadata["soak_hours"], "")
|
||||
|
||||
@@ -97,7 +97,7 @@ class ResolveReleasePromotionTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(metadata["promoted_from_tag"], "")
|
||||
self.assertEqual(metadata["rollback_tag"], "v6.0.0")
|
||||
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v6.0.0")
|
||||
self.assertEqual(metadata["rollback_command"], "sudo /bin/update --version v6.0.0")
|
||||
self.assertEqual(metadata["hotfix_exception"], "true")
|
||||
self.assertEqual(
|
||||
metadata["hotfix_reason"],
|
||||
|
||||
@@ -177,7 +177,7 @@ class ReleaseNoteVisualPlanTest(unittest.TestCase):
|
||||
(),
|
||||
{
|
||||
"rollback_target": "v6.3.2",
|
||||
"rollback_command": "./scripts/install.sh --version v6.3.2",
|
||||
"rollback_command": "sudo /bin/update --version v6.3.2",
|
||||
},
|
||||
)()
|
||||
)
|
||||
|
||||
@@ -1667,7 +1667,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||
self.assertNotIn("secrets.", docker_build)
|
||||
self.assertNotIn("provenance: false", content)
|
||||
self.assertIn("Derived rollback command:", helper)
|
||||
self.assertIn("./scripts/install.sh --version", helper)
|
||||
self.assertIn("sudo /bin/update --version", helper)
|
||||
self.assertIn("v6 GA date to publish with GA", helper)
|
||||
self.assertIn("--arg ga_date \"$GA_DATE\"", helper)
|
||||
self.assertIn("ga_date", resolver)
|
||||
|
||||
@@ -486,6 +486,14 @@ def build_installation_section(version: str) -> str:
|
||||
[
|
||||
"## Install",
|
||||
"",
|
||||
"For systemd and Proxmox LXC installs, use **Settings → System → Updates** or:",
|
||||
"",
|
||||
"```bash",
|
||||
f"sudo /bin/update --version v{version}",
|
||||
"```",
|
||||
"",
|
||||
"For Docker:",
|
||||
"",
|
||||
"```bash",
|
||||
f"docker pull rcourtman/pulse:{version}",
|
||||
"```",
|
||||
@@ -509,6 +517,8 @@ def build_rollback_section(args: argparse.Namespace) -> str:
|
||||
"```bash",
|
||||
args.rollback_command,
|
||||
"```",
|
||||
"",
|
||||
"For Docker Compose, set the Pulse image to the rollback target and recreate the container.",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -499,7 +499,7 @@ Old metadata section.
|
||||
"candidate_tag": "v6.0.0-rc.2",
|
||||
"promoted_prerelease_tag": "",
|
||||
"rollback_target": "v5.1.28",
|
||||
"rollback_command": "./scripts/install.sh --version v5.1.28",
|
||||
"rollback_command": "sudo /bin/update --version v5.1.28",
|
||||
"planned_ga_date": "",
|
||||
"planned_v5_eos_date": "",
|
||||
"hotfix_exception": "false",
|
||||
@@ -523,10 +523,15 @@ Old metadata section.
|
||||
self.assertEqual(body.count("## Install"), 1)
|
||||
self.assertEqual(body.count("## Roll back"), 1)
|
||||
self.assertNotIn("## Promotion Metadata", body)
|
||||
self.assertIn("sudo /bin/update --version v6.0.0-rc.2", body)
|
||||
self.assertIn("docker pull rcourtman/pulse:6.0.0-rc.2", body)
|
||||
self.assertIn("https://pulserelay.pro/download.html", body)
|
||||
self.assertIn("The rollback target is `v5.1.28`", body)
|
||||
self.assertIn("./scripts/install.sh --version v5.1.28", body)
|
||||
self.assertIn("sudo /bin/update --version v5.1.28", body)
|
||||
self.assertIn(
|
||||
"For Docker Compose, set the Pulse image to the rollback target",
|
||||
body,
|
||||
)
|
||||
render_release_body.validate_release_body_shape(body, "6.0.0-rc.2")
|
||||
|
||||
def test_release_body_accepts_visual_evidence_before_installation(self) -> None:
|
||||
@@ -553,7 +558,7 @@ Controls remain readable without horizontal scrolling.
|
||||
(),
|
||||
{
|
||||
"rollback_target": "v6.3.2",
|
||||
"rollback_command": "./scripts/install.sh --version v6.3.2",
|
||||
"rollback_command": "sudo /bin/update --version v6.3.2",
|
||||
},
|
||||
)()
|
||||
body = "\n\n".join(
|
||||
|
||||
@@ -360,7 +360,10 @@ def resolve_metadata(
|
||||
)
|
||||
if not tag_exists_fn(rollback_tag):
|
||||
raise ValueError(f"rollback_version {rollback_tag} does not exist as a repository tag.")
|
||||
rollback_command = f"./scripts/install.sh --version {rollback_tag}"
|
||||
# Supported systemd and Proxmox LXC installs expose the signed server
|
||||
# installer through /bin/update. The archive's scripts/install.sh is the
|
||||
# Unified Agent installer and deliberately does not accept --version.
|
||||
rollback_command = f"sudo /bin/update --version {rollback_tag}"
|
||||
|
||||
promoted_from_tag = ""
|
||||
soak_hours = ""
|
||||
|
||||
@@ -41,7 +41,7 @@ class ResolveReleasePromotionTest(unittest.TestCase):
|
||||
tag_exists_fn=lambda tag: tag == "v5.1.14",
|
||||
)
|
||||
self.assertEqual(metadata["rollback_tag"], "v5.1.14")
|
||||
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v5.1.14")
|
||||
self.assertEqual(metadata["rollback_command"], "sudo /bin/update --version v5.1.14")
|
||||
self.assertEqual(metadata["promoted_from_tag"], "")
|
||||
self.assertEqual(metadata["soak_hours"], "")
|
||||
|
||||
@@ -158,7 +158,7 @@ class ResolveReleasePromotionTest(unittest.TestCase):
|
||||
tag_exists_fn=lambda tag: True,
|
||||
)
|
||||
self.assertEqual(metadata["rollback_tag"], "v6.0.4")
|
||||
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v6.0.4")
|
||||
self.assertEqual(metadata["rollback_command"], "sudo /bin/update --version v6.0.4")
|
||||
|
||||
def test_explicit_rollback_input_wins_over_derivation(self) -> None:
|
||||
metadata = resolver.resolve_metadata(
|
||||
@@ -572,7 +572,7 @@ class ResolveReleasePromotionTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(metadata["promoted_from_tag"], "v6.0.0-rc.7")
|
||||
self.assertEqual(metadata["rollback_tag"], "v5.1.35")
|
||||
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v5.1.35")
|
||||
self.assertEqual(metadata["rollback_command"], "sudo /bin/update --version v5.1.35")
|
||||
self.assertEqual(metadata["ga_date"], "2026-07-04")
|
||||
self.assertEqual(metadata["v5_eos_date"], "2026-10-02")
|
||||
|
||||
@@ -596,7 +596,7 @@ class ResolveReleasePromotionTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(metadata["promoted_from_tag"], "")
|
||||
self.assertEqual(metadata["rollback_tag"], "v6.0.1")
|
||||
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v6.0.1")
|
||||
self.assertEqual(metadata["rollback_command"], "sudo /bin/update --version v6.0.1")
|
||||
self.assertEqual(metadata["hotfix_exception"], "true")
|
||||
self.assertEqual(
|
||||
metadata["hotfix_reason"],
|
||||
|
||||
@@ -242,9 +242,9 @@ if [ -z "$ROLLBACK_VERSION" ]; then
|
||||
fi
|
||||
|
||||
if [[ "$ROLLBACK_VERSION" == v* ]]; then
|
||||
ROLLBACK_COMMAND="./scripts/install.sh --version ${ROLLBACK_VERSION}"
|
||||
ROLLBACK_COMMAND="sudo /bin/update --version ${ROLLBACK_VERSION}"
|
||||
else
|
||||
ROLLBACK_COMMAND="./scripts/install.sh --version v${ROLLBACK_VERSION}"
|
||||
ROLLBACK_COMMAND="sudo /bin/update --version v${ROLLBACK_VERSION}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user