diff --git a/VERSION b/VERSION index 1aa5e414f..288b2cd9a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.4 +6.0.5 diff --git a/deploy/helm/pulse/Chart.yaml b/deploy/helm/pulse/Chart.yaml index c1c0f0758..a3c7d0c70 100644 --- a/deploy/helm/pulse/Chart.yaml +++ b/deploy/helm/pulse/Chart.yaml @@ -2,9 +2,9 @@ apiVersion: v2 name: pulse description: Helm chart for deploying the Pulse hub and optional Docker monitoring agent. type: application -version: 6.0.4 -appVersion: "6.0.4" -icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.0.4/docs/images/pulse-logo.svg +version: 6.0.5 +appVersion: "6.0.5" +icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.0.5/docs/images/pulse-logo.svg keywords: - monitoring - proxmox @@ -32,7 +32,7 @@ annotations: description: Smoke tests with kind cluster deployment artifacthub.io/links: | - name: Documentation - url: https://github.com/rcourtman/Pulse/blob/v6.0.4/docs/KUBERNETES.md + url: https://github.com/rcourtman/Pulse/blob/v6.0.5/docs/KUBERNETES.md - name: Support url: https://github.com/rcourtman/Pulse/discussions artifacthub.io/maintainers: | diff --git a/deploy/helm/pulse/README.md b/deploy/helm/pulse/README.md index add24ae67..ab7591a90 100644 --- a/deploy/helm/pulse/README.md +++ b/deploy/helm/pulse/README.md @@ -1,6 +1,6 @@ # pulse -![Version: 6.0.4](https://img.shields.io/badge/Version-6.0.4-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.0.4](https://img.shields.io/badge/AppVersion-6.0.4-informational?style=flat-square) +![Version: 6.0.5](https://img.shields.io/badge/Version-6.0.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.0.5](https://img.shields.io/badge/AppVersion-6.0.5-informational?style=flat-square) Helm chart for deploying the Pulse hub and optional Docker monitoring agent. diff --git a/docker-compose.yml b/docker-compose.yml index 67f7d9e14..4bf91e7b9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.8' services: pulse: - image: ${PULSE_IMAGE:-rcourtman/pulse:6.0.4} + image: ${PULSE_IMAGE:-rcourtman/pulse:6.0.5} container_name: pulse restart: unless-stopped logging: diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index 7724ecf03..4fc87641b 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -7,6 +7,8 @@ For historical v4 notes that previously lived in this repo, see: `docs/releases/RELEASE_NOTES_v4.md` For the current stable v6 patch packet, see: +- `docs/releases/RELEASE_NOTES_v6.0.5.md` +- `docs/releases/V6_CHANGELOG_v6.0.5.md` - `docs/releases/RELEASE_NOTES_v6.0.4.md` - `docs/releases/V6_CHANGELOG_v6.0.4.md` - `docs/releases/RELEASE_NOTES_v6.0.3.md` diff --git a/docs/UPGRADE_v6.md b/docs/UPGRADE_v6.md index e8dfcd415..8528bc6ad 100644 --- a/docs/UPGRADE_v6.md +++ b/docs/UPGRADE_v6.md @@ -4,6 +4,8 @@ This guide covers practical upgrade steps for existing Pulse installs moving to For the current stable v6 packet and rollout references, see: +- `docs/releases/RELEASE_NOTES_v6.0.5.md` +- `docs/releases/V6_CHANGELOG_v6.0.5.md` - `docs/releases/RELEASE_NOTES_v6.0.4.md` - `docs/releases/V6_CHANGELOG_v6.0.4.md` - `docs/releases/RELEASE_NOTES_v6.0.3.md` diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 67a1c07cd..b848a9bd3 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -807,15 +807,14 @@ TLS floor in the dynamic config. ## Current State -The active stable `v6.0.4` cut sets the repo-root `VERSION`, +The active stable `v6.0.5` cut sets the repo-root `VERSION`, repo-root `docker-compose.yml` image default, `scripts/install-docker.sh` -fallback, and Helm chart release metadata to the same `6.0.4` release version. -This patch release uses the stable hotfix path with `rollback_version=v6.0.3`, +fallback, and Helm chart release metadata to the same `6.0.5` release version. +This patch release uses the stable hotfix path with `rollback_version=v6.0.4`, `hotfix_exception=true`, a release-owner reason, and no fabricated same-version -RC tag. It advances the v6.0.3 stable line with customer-support fixes for -audit log timestamp compatibility, remembered-login persistence, platform and -agent metric normalization, PBS/recovery memory retention, OIDC provider -persistence, and Docker/Proxmox platform metadata. The initial GA promotion +RC tag. It advances the v6.0.4 stable line with customer-support fixes for +Gemini Patrol tool-call readiness and remembered-login submit persistence. +The initial GA promotion metadata remains `promoted_from_tag=v6.0.0-rc.7`, `rollback_version=v5.1.35`, `ga_date=2026-07-04`, and `v5_eos_date=2026-10-02` for the first stable @@ -868,8 +867,8 @@ compose image default, standalone installer fallback constant, and packaged Helm metadata. A draft release workflow failure caused by stale image or chart pins is a release-packet blocker until the defaults, tests, and evidence record are refreshed from the new branch head. -For the active stable `v6.0.4` cut, the repo-root compose default and -`scripts/install-docker.sh` fallback must both pin `6.0.4`. The stable +For the active stable `v6.0.5` cut, the repo-root compose default and +`scripts/install-docker.sh` fallback must both pin `6.0.5`. The stable promotion guard remains in force by rejecting leftover `-rc.` defaults when the governed `VERSION` is a stable release. The RC7 packet refresh records `fc10de9b5477613316473267b72b05b6b2b7aaff` diff --git a/docs/releases/RELEASE_NOTES_v6.0.5.md b/docs/releases/RELEASE_NOTES_v6.0.5.md new file mode 100644 index 000000000..d6be98874 --- /dev/null +++ b/docs/releases/RELEASE_NOTES_v6.0.5.md @@ -0,0 +1,22 @@ +# Pulse v6.0.5 Release Notes + +`v6.0.5` is a stable patch release for the Pulse v6 line. It follows +`v6.0.4` and bundles support fixes for Patrol Gemini model readiness and +remembered-login submit persistence. + +## Fixes + +- Fixed Patrol readiness checks for Gemini models so tool-call capability is + detected from Gemini candidate parts as well as top-level tool-call lists. +- Fixed the login form so enabling "remember me" during submit persists the + remembered username immediately. +- Refreshed Docker, Helm, installer, and release-helper metadata for the stable + patch line. + +## Upgrade Notes + +Use the normal v6 install or update flow for `v6.0.5`. The rollback target for +this patch release is `v6.0.4`. + +Paid Pulse Pro, Relay, and eligible legacy customers should continue to use the +private download page and private runtime image for paid runtime features. diff --git a/docs/releases/V6_CHANGELOG_v6.0.5.md b/docs/releases/V6_CHANGELOG_v6.0.5.md new file mode 100644 index 000000000..784816897 --- /dev/null +++ b/docs/releases/V6_CHANGELOG_v6.0.5.md @@ -0,0 +1,19 @@ +# Pulse v6.0.5 + +_This changelog describes the stable `v6.0.5` patch release compared with +`v6.0.4`._ + +## Fixed + +- Patrol readiness checks now detect Gemini tool-call capability from Gemini + candidate parts as well as top-level tool-call lists. +- Remembered-login state now persists the saved username when the checkbox is + enabled during submit. +- Docker, Helm, installer, and release-helper metadata now track the active + stable patch version. + +## Release Metadata + +- Version: `v6.0.5` +- Rollback target: `v6.0.4` +- Promotion path: stable patch hotfix from `main` diff --git a/frontend-modern/src/__tests__/useAppRuntimeState.test.ts b/frontend-modern/src/__tests__/useAppRuntimeState.test.ts index 4df421146..476c6e3ff 100644 --- a/frontend-modern/src/__tests__/useAppRuntimeState.test.ts +++ b/frontend-modern/src/__tests__/useAppRuntimeState.test.ts @@ -116,6 +116,8 @@ describe('useAppRuntimeState', () => { vi.doMock('@/utils/localStorage', () => ({ STORAGE_KEYS: { AUTH: 'auth', + AUTH_USER: 'pulse_auth_user', + REMEMBERED_LOGIN_USERNAME: 'pulse_remembered_login_username', ORG_ID: 'org_id', GUEST_METADATA: 'guest_metadata', DOCKER_METADATA: 'docker_metadata', diff --git a/scripts/install-docker.sh b/scripts/install-docker.sh index 79f8d8c6d..16735b0c5 100755 --- a/scripts/install-docker.sh +++ b/scripts/install-docker.sh @@ -6,7 +6,7 @@ set -euo pipefail SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" DOCKER_IMAGE_REPO="${DOCKER_IMAGE_REPO:-rcourtman/pulse}" -CANONICAL_DEFAULT_PULSE_VERSION="6.0.4" +CANONICAL_DEFAULT_PULSE_VERSION="6.0.5" resolve_default_pulse_version() { if [ -n "${PULSE_IMAGE_VERSION:-}" ]; then diff --git a/scripts/installtests/build_release_assets_test.go b/scripts/installtests/build_release_assets_test.go index a4d9adfa9..74d058cf6 100644 --- a/scripts/installtests/build_release_assets_test.go +++ b/scripts/installtests/build_release_assets_test.go @@ -261,12 +261,16 @@ func TestCurrentStablePatchReleasePacketTracksInstallMetadata(t *testing.T) { assertFileContainsAllNormalized(t, releaseNotesPath, "`v"+version+"` is a stable patch release", "`v"+previous+"`", + "Patrol Gemini model readiness", + "remembered-login submit persistence", "rollback target for this patch release is `v"+previous+"`", ) assertFileContainsAll(t, changelogPath, "Version: `v"+version+"`", "Rollback target: `v"+previous+"`", "Promotion path: stable patch hotfix from `"+releaseBranch+"`", + "Gemini tool-call capability", + "Remembered-login state now persists", ) assertFileContainsAll(t, repoFile("docs", "RELEASE_NOTES.md"), "docs/releases/RELEASE_NOTES_v"+version+".md", @@ -285,6 +289,7 @@ func TestCurrentStablePatchReleasePacketTracksInstallMetadata(t *testing.T) { assertFileContainsAll(t, repoFile("deploy", "helm", "pulse", "README.md"), "Version-"+version+"-informational", "AppVersion-"+version+"-informational", + "Autogenerated from chart metadata using [helm-docs v1.14.2]", ) assertFileContainsAll(t, repoFile("docker-compose.yml"), "image: ${PULSE_IMAGE:-rcourtman/pulse:"+version+"}", diff --git a/scripts/installtests/install_docker_sh_test.go b/scripts/installtests/install_docker_sh_test.go index a04cc7086..7ffd416c5 100644 --- a/scripts/installtests/install_docker_sh_test.go +++ b/scripts/installtests/install_docker_sh_test.go @@ -211,6 +211,7 @@ func TestInstallDockerProofTracksStablePatchReleaseContract(t *testing.T) { assertFileContainsAllNormalized(t, repoFile("docs", "release-control", "v6", "internal", "subsystems", "deployment-installability.md"), "The active stable `v"+version+"` cut sets the repo-root `VERSION`, repo-root `docker-compose.yml` image default, `scripts/install-docker.sh` fallback, and Helm chart release metadata to the same `"+version+"` release version.", "This patch release uses the stable hotfix path with `rollback_version=v"+previous+"`, `hotfix_exception=true`, a release-owner reason, and no fabricated same-version RC tag.", + "It advances the v"+previous+" stable line with customer-support fixes", "For the active stable `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"`", ) } diff --git a/scripts/release_control/release_promotion_policy_test.py b/scripts/release_control/release_promotion_policy_test.py index 00e90002a..cb4abb61a 100644 --- a/scripts/release_control/release_promotion_policy_test.py +++ b/scripts/release_control/release_promotion_policy_test.py @@ -477,6 +477,9 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertIn("release-dry-run.yml", dry_run_trigger) self.assertIn("gh workflow run release-dry-run.yml", dry_run_trigger) self.assertIn("Release Dry Run executes the selected remote ref", dry_run_trigger) + self.assertIn("Hotfix exception to bypass 72-hour prerelease soak? [y/N]", dry_run_trigger) + self.assertIn("blank only for approved hotfix", dry_run_trigger) + self.assertIn('if [ -z "$PROMOTED_FROM_TAG" ] && [ "$HOTFIX_EXCEPTION" != "true" ]; then', dry_run_trigger) self.assertNotIn("Continue anyway?", dry_run_trigger) self.assertIn('if [ "${REHEARSAL_CONCLUSION}" != "success" ]; then', workflow) self.assertIn("did not produce a valid promotion metadata envelope", workflow) @@ -506,6 +509,10 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertIn("https://pulserelay.pro/download.html", contract) self.assertIn("PULSE_IMAGE`-aware compose image line", normalize_ws(contract)) self.assertIn("hardcoded `image: rcourtman/pulse:...`", normalize_ws(contract)) + self.assertIn("Resolving governed promotion metadata...", helper) + self.assertIn("--release-notes-file \"$NOTES_FILE\"", helper) + self.assertIn("blank for hotfix with no RC lineage", helper) + self.assertIn('if [ -z "$PROMOTED_FROM_TAG" ] && [ "$HOTFIX_EXCEPTION" != "true" ]; then', helper) self.assertIn("control_plane.py --branch-for-version", content) self.assertIn('git fetch --prune origin main "${REQUIRED_BRANCH}" --tags', content) self.assertIn('REQUIRED_BRANCH: ${{ steps.branch_policy.outputs.required_branch }}', content) diff --git a/scripts/trigger-release-dry-run.sh b/scripts/trigger-release-dry-run.sh index f58d978b7..e86488706 100755 --- a/scripts/trigger-release-dry-run.sh +++ b/scripts/trigger-release-dry-run.sh @@ -100,19 +100,6 @@ if [ -z "$ROLLBACK_VERSION" ]; then fi if [ "$IS_PRERELEASE" != "true" ]; then - DEFAULT_PROMOTED_FROM_TAG=$(git tag -l "v${VERSION}-rc.*" --sort=-version:refname | head -1 || true) - echo "" - if [ -n "$DEFAULT_PROMOTED_FROM_TAG" ]; then - read -r -p "Promoted prerelease tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG - PROMOTED_FROM_TAG="${PROMOTED_FROM_TAG:-$DEFAULT_PROMOTED_FROM_TAG}" - else - read -r -p "Promoted prerelease tag (for example v${VERSION}-rc.2): " PROMOTED_FROM_TAG - fi - if [ -z "$PROMOTED_FROM_TAG" ]; then - echo "❌ Error: promoted prerelease tag is required for stable rehearsals" - exit 1 - fi - echo "" read -r -p "Hotfix exception to bypass 72-hour prerelease soak? [y/N] " HOTFIX_REPLY if [[ "$HOTFIX_REPLY" =~ ^[Yy]$ ]]; then @@ -124,6 +111,23 @@ if [ "$IS_PRERELEASE" != "true" ]; then fi fi + DEFAULT_PROMOTED_FROM_TAG=$(git tag -l "v${VERSION}-rc.*" --sort=-version:refname | head -1 || true) + echo "" + if [ -n "$DEFAULT_PROMOTED_FROM_TAG" ]; then + if [ "$HOTFIX_EXCEPTION" = "true" ]; then + read -r -p "Promoted prerelease tag, or blank for hotfix with no RC lineage [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG + else + read -r -p "Promoted prerelease tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG + PROMOTED_FROM_TAG="${PROMOTED_FROM_TAG:-$DEFAULT_PROMOTED_FROM_TAG}" + fi + else + read -r -p "Promoted prerelease tag (for example v${VERSION}-rc.2; blank only for approved hotfix): " PROMOTED_FROM_TAG + fi + if [ -z "$PROMOTED_FROM_TAG" ] && [ "$HOTFIX_EXCEPTION" != "true" ]; then + echo "❌ Error: promoted prerelease tag is required for stable rehearsals unless this is an approved hotfix" + exit 1 + fi + if [ "$VERSION" = "6.0.0" ]; then echo "" read -r -p "v6 GA date to publish with GA (YYYY-MM-DD): " GA_DATE diff --git a/scripts/trigger-release.sh b/scripts/trigger-release.sh index 05c1a14ab..3096781f3 100755 --- a/scripts/trigger-release.sh +++ b/scripts/trigger-release.sh @@ -184,19 +184,6 @@ echo "" echo "Derived rollback command: ${ROLLBACK_COMMAND}" if [ "$IS_PRERELEASE" != "true" ]; then - DEFAULT_PROMOTED_FROM_TAG=$(git tag -l "v${VERSION}-rc.*" --sort=-version:refname | head -1 || true) - echo "" - if [ -n "$DEFAULT_PROMOTED_FROM_TAG" ]; then - read -r -p "Promoted prerelease tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG - PROMOTED_FROM_TAG="${PROMOTED_FROM_TAG:-$DEFAULT_PROMOTED_FROM_TAG}" - else - read -r -p "Promoted prerelease tag (for example v${VERSION}-rc.2): " PROMOTED_FROM_TAG - fi - if [ -z "$PROMOTED_FROM_TAG" ]; then - echo "❌ Error: promoted prerelease tag is required for stable releases" - exit 1 - fi - echo "" read -r -p "Hotfix exception to bypass 72-hour prerelease soak? [y/N] " HOTFIX_REPLY if [[ "$HOTFIX_REPLY" =~ ^[Yy]$ ]]; then @@ -208,6 +195,23 @@ if [ "$IS_PRERELEASE" != "true" ]; then fi fi + DEFAULT_PROMOTED_FROM_TAG=$(git tag -l "v${VERSION}-rc.*" --sort=-version:refname | head -1 || true) + echo "" + if [ -n "$DEFAULT_PROMOTED_FROM_TAG" ]; then + if [ "$HOTFIX_EXCEPTION" = "true" ]; then + read -r -p "Promoted prerelease tag, or blank for hotfix with no RC lineage [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG + else + read -r -p "Promoted prerelease tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG + PROMOTED_FROM_TAG="${PROMOTED_FROM_TAG:-$DEFAULT_PROMOTED_FROM_TAG}" + fi + else + read -r -p "Promoted prerelease tag (for example v${VERSION}-rc.2; blank only for approved hotfix): " PROMOTED_FROM_TAG + fi + if [ -z "$PROMOTED_FROM_TAG" ] && [ "$HOTFIX_EXCEPTION" != "true" ]; then + echo "❌ Error: promoted prerelease tag is required for stable releases unless this is an approved hotfix" + exit 1 + fi + if [ "$VERSION" = "6.0.0" ]; then echo "" read -r -p "v6 GA date to publish with GA (YYYY-MM-DD): " GA_DATE @@ -226,6 +230,29 @@ if [ "$IS_PRERELEASE" != "true" ]; then fi # Trigger the workflow +echo "" +echo "Resolving governed promotion metadata..." +RESOLVER_ARGS=( + --version "$VERSION" + --rollback-version "$ROLLBACK_VERSION" + --hotfix-reason "$HOTFIX_REASON" + --release-notes-file "$NOTES_FILE" +) +if [ -n "$PROMOTED_FROM_TAG" ]; then + RESOLVER_ARGS+=(--promoted-from-tag "$PROMOTED_FROM_TAG") +fi +if [ -n "$GA_DATE" ]; then + RESOLVER_ARGS+=(--ga-date "$GA_DATE") +fi +if [ -n "$V5_EOS_DATE" ]; then + RESOLVER_ARGS+=(--v5-eos-date "$V5_EOS_DATE") +fi +if [ "$HOTFIX_EXCEPTION" = "true" ]; then + RESOLVER_ARGS+=(--hotfix-exception) +fi +python3 scripts/release_control/resolve_release_promotion.py "${RESOLVER_ARGS[@]}" >/tmp/pulse-release-metadata.out +cat /tmp/pulse-release-metadata.out + echo "" echo "Triggering release workflow..." if [ -n "$NOTES_FILE" ]; then