diff --git a/VERSION b/VERSION index 4c77920fd..a4c853ea2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.4.1 +6.4.2 diff --git a/deploy/helm/pulse/Chart.yaml b/deploy/helm/pulse/Chart.yaml index 55c64b725..95d84e26e 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, Kubernetes, or OpenShift monitoring agent. type: application -version: 6.4.1 -appVersion: "6.4.1" -icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.4.1/docs/images/pulse-logo.svg +version: 6.4.2 +appVersion: "6.4.2" +icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.4.2/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.4.1/docs/KUBERNETES.md + url: https://github.com/rcourtman/Pulse/blob/v6.4.2/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 92cfed850..6191c03bc 100644 --- a/deploy/helm/pulse/README.md +++ b/deploy/helm/pulse/README.md @@ -1,6 +1,6 @@ # pulse -![Version: 6.4.1](https://img.shields.io/badge/Version-6.4.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.4.1](https://img.shields.io/badge/AppVersion-6.4.1-informational?style=flat-square) +![Version: 6.4.2](https://img.shields.io/badge/Version-6.4.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.4.2](https://img.shields.io/badge/AppVersion-6.4.2-informational?style=flat-square) Helm chart for deploying the Pulse hub and optional Docker, Kubernetes, or OpenShift monitoring agent. diff --git a/docker-compose.yml b/docker-compose.yml index 0da9ffb16..82068da8b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.8' services: pulse: - image: ${PULSE_IMAGE:-rcourtman/pulse:6.4.1} + image: ${PULSE_IMAGE:-rcourtman/pulse:6.4.2} container_name: pulse restart: unless-stopped logging: diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index 392bade3f..450fb505b 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -7,10 +7,14 @@ For historical v4 notes that previously lived in this repo, see: `docs/releases/RELEASE_NOTES_v4.md` For the current stable v6 packet, see: +- `docs/releases/RELEASE_NOTES_v6.4.2.md` +- `docs/releases/V6_CHANGELOG_v6.4.2.md` + +For the preceding stable v6 packet, see: - `docs/releases/RELEASE_NOTES_v6.4.1.md` - `docs/releases/V6_CHANGELOG_v6.4.1.md` -For the preceding stable v6 packet, see: +For the earlier stable v6 packet, see: - `docs/releases/RELEASE_NOTES_v6.4.0.md` - `docs/releases/V6_CHANGELOG_v6.4.0.md` diff --git a/docs/UPGRADE_v6.md b/docs/UPGRADE_v6.md index c60a2acab..89bf62ce4 100644 --- a/docs/UPGRADE_v6.md +++ b/docs/UPGRADE_v6.md @@ -4,10 +4,15 @@ This guide covers practical upgrade steps for existing Pulse installs moving to For the current stable v6 packet, see: +- `docs/releases/RELEASE_NOTES_v6.4.2.md` +- `docs/releases/V6_CHANGELOG_v6.4.2.md` + +For the preceding stable v6 packet, see: + - `docs/releases/RELEASE_NOTES_v6.4.1.md` - `docs/releases/V6_CHANGELOG_v6.4.1.md` -For the preceding stable v6 packet, see: +For the earlier stable v6 packet, see: - `docs/releases/RELEASE_NOTES_v6.4.0.md` - `docs/releases/V6_CHANGELOG_v6.4.0.md` diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 0b8d71dc3..c1a8e3a3d 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -2302,7 +2302,22 @@ version. It opened the `v6.4.0` candidate line from `main` with `rollback_version=v6.3.1` and did not move stable/latest install pointers or stable semver aliases. -The active stable `v6.4.1` cut sets the repo-root `VERSION`, repo-root +The active stable `v6.4.2` 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.4.2` release version. This patch +release uses the stable hotfix path with `rollback_version=v6.4.1`, +`hotfix_exception=true`, a release-owner reason, and no fabricated same-version +RC tag. The governed branch is `main`. The active customer harm is two stable +authorization failures: authenticated non-administrator organization members +can reach infrastructure action control, and SSO-only deployments can treat +every authenticated IdP user as an instance administrator without an explicit +grant. The exact pushed `main` SHA must pass the integrated candidate checks +before publication. No governed mobile-facing path changed from `v6.4.1`, so +the release decision is `no-mobile-impact`. The standing +SignPath-unavailable policy from `v6.3.2` onward still applies, with public +Unknown Publisher disclosure and the existing signed integrity controls. + +The preceding stable `v6.4.1` 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.4.1` release version. This patch release uses the stable hotfix path with `rollback_version=v6.4.0`, @@ -2740,13 +2755,15 @@ For the active stable `v6.1.2` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `6.1.2` whenever the governed `VERSION` is that stable cut. The stable promotion guard remains in force and rejects leftover `-rc.` defaults. -For the active stable `v6.4.1` cut, the repo-root compose default and -`scripts/install-docker.sh` fallback must both pin `6.4.1` until the next +For the active stable `v6.4.2` cut, the repo-root compose default and +`scripts/install-docker.sh` fallback must both pin `6.4.2` until the next governed release moves them forward. The stable promotion guard remains in force and rejects leftover `-rc.` defaults. Each new release moves these two pins together with the repo-root `VERSION` and the Helm chart metadata in the same commit; a cut that leaves any of the four on a superseded value is a release-packet blocker. +For the preceding stable `v6.4.1` cut, the repo-root compose default and +`scripts/install-docker.sh` fallback both pinned `6.4.1`. For the preceding stable `v6.4.0` cut, the repo-root compose default and `scripts/install-docker.sh` fallback both pinned `6.4.0`. For the preceding stable `v6.3.2` cut, the repo-root compose default and diff --git a/docs/releases/RELEASE_NOTES_v6.4.2.md b/docs/releases/RELEASE_NOTES_v6.4.2.md new file mode 100644 index 000000000..9d977c535 --- /dev/null +++ b/docs/releases/RELEASE_NOTES_v6.4.2.md @@ -0,0 +1,20 @@ +# Pulse v6.4.2 Release Notes + +`v6.4.2` is a stable patch release for the Pulse v6 line. It follows stable +`v6.4.1` and restores explicit administrator boundaries for infrastructure +actions and SSO-only deployments. + +## What's improved + +- **Infrastructure actions honor role boundaries** - Browser and proxy users must now be administrators or hold an explicit action permission before they can plan, approve, view, or execute infrastructure actions. +- **SSO access no longer implies administrator access** - An authenticated SSO user now needs an effective RBAC `admin` grant for administrator routes. Unassigned, `operator`, and `viewer` users remain non-administrative even when no local administrator exists. +- **SAML allowlists fail closed** - A configured domain or email allowlist now rejects a SAML assertion that omits the email claim instead of bypassing the allowlist. + +## Before you upgrade + +- Upgrade promptly when Pulse has organization members, proxy-authenticated users, or SSO users who should not administer the instance or control infrastructure. +- On an SSO-only deployment, map at least one trusted IdP group to the built-in `admin` role before upgrading so an intended administrator retains access. +- Existing configured local administrators, explicitly authorized RBAC roles, and action-scoped API tokens remain supported. +- Pulse Mobile remains compatible. This patch does not require a companion mobile release. +- 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.4.1`. On systemd and Proxmox LXC installs, use `sudo /bin/update --version v6.4.1` to return to the previous stable release. For Docker Compose, pin `rcourtman/pulse:6.4.1` and recreate the container. diff --git a/docs/releases/V6_CHANGELOG_v6.4.2.md b/docs/releases/V6_CHANGELOG_v6.4.2.md new file mode 100644 index 000000000..54b7ec658 --- /dev/null +++ b/docs/releases/V6_CHANGELOG_v6.4.2.md @@ -0,0 +1,50 @@ +# Pulse v6.4.2 + +_This changelog describes stable `v6.4.2` compared with stable `v6.4.1`._ + +## Fixed + +- The OSS default authorizer no longer treats ordinary authenticated + organization membership as permission to use the infrastructure action + control plane. Browser and proxy sessions must satisfy the canonical + administrator boundary, while explicitly scoped API tokens and real RBAC + action grants retain their governed paths. +- Route and lifecycle guardrails cover planning, review, approval, execution, + refresh, and recovery action surfaces so the permission check cannot be + bypassed through a sibling action endpoint. +- SSO authentication no longer becomes instance-administrator authority when + no local administrator is configured. SSO browser sessions must carry an + effective RBAC `admin` grant on `*` before they can use administrator-only + settings, discovery, configuration transfer, platform, or infrastructure + action routes. +- SAML domain and email allowlists now reject assertions without an email + claim when either allowlist is configured. + +## Upgrade requirement + +- An SSO-only installation must map at least one trusted IdP group to the + built-in `admin` role before upgrading. Sessions mapped only to `operator`, + `viewer`, or no role intentionally lose the administrator access that older + versions granted implicitly. + +## Release Metadata + +- Version: `v6.4.2` +- Previous stable: `v6.4.1` +- Rollback target: `v6.4.1` +- Rollback command: `sudo /bin/update --version v6.4.1` +- Promotion path: emergency stable patch from `main`, using the single-build + release workflow after exact-SHA qualification +- Emergency reason: current stable releases contain two authorization + boundary failures. A non-administrator organization member may reach the + infrastructure action control plane, and every authenticated IdP user on an + SSO-only instance may inherit instance-administrator authority without an + explicit grant +- Windows signing decision: the standing SignPath-unavailable policy publishes + unsigned Windows Unified Agent binaries. They may display an Unknown + Publisher warning while exact-SHA candidate binding, checksums, detached + signatures, immutable-manifest verification, and published-digest + verification remain mandatory +- Mobile decision: `no-mobile-impact`. The patch changes no governed mobile + route, payload, Relay, pairing, approval, push, or onboarding contract, so no + companion mobile build or store rollout is required. diff --git a/frontend-modern/public/docs/UPGRADE_v6.md b/frontend-modern/public/docs/UPGRADE_v6.md index c60a2acab..89bf62ce4 100644 --- a/frontend-modern/public/docs/UPGRADE_v6.md +++ b/frontend-modern/public/docs/UPGRADE_v6.md @@ -4,10 +4,15 @@ This guide covers practical upgrade steps for existing Pulse installs moving to For the current stable v6 packet, see: +- `docs/releases/RELEASE_NOTES_v6.4.2.md` +- `docs/releases/V6_CHANGELOG_v6.4.2.md` + +For the preceding stable v6 packet, see: + - `docs/releases/RELEASE_NOTES_v6.4.1.md` - `docs/releases/V6_CHANGELOG_v6.4.1.md` -For the preceding stable v6 packet, see: +For the earlier stable v6 packet, see: - `docs/releases/RELEASE_NOTES_v6.4.0.md` - `docs/releases/V6_CHANGELOG_v6.4.0.md` diff --git a/scripts/install-docker.sh b/scripts/install-docker.sh index 66bf9d39c..30a75a155 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.4.1" +CANONICAL_DEFAULT_PULSE_VERSION="6.4.2" 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 ad6b191b0..25502ff4f 100644 --- a/scripts/installtests/build_release_assets_test.go +++ b/scripts/installtests/build_release_assets_test.go @@ -2045,6 +2045,39 @@ func TestDeploymentDefaultsPinVersionedImagesAndHelmDocsChecksum(t *testing.T) { } } +func TestV642SecurityPacketCoversBothAdministratorBoundaryFixes(t *testing.T) { + notesBytes, err := os.ReadFile(repoFile("docs", "releases", "RELEASE_NOTES_v6.4.2.md")) + if err != nil { + t.Fatalf("read v6.4.2 release notes: %v", err) + } + changelogBytes, err := os.ReadFile(repoFile("docs", "releases", "V6_CHANGELOG_v6.4.2.md")) + if err != nil { + t.Fatalf("read v6.4.2 changelog: %v", err) + } + notes := string(notesBytes) + changelog := string(changelogBytes) + for _, required := range []string{ + "Infrastructure actions honor role boundaries", + "SSO access no longer implies administrator access", + "map at least one trusted IdP group to the built-in `admin` role before upgrading", + "The rollback target is stable `v6.4.1`", + } { + if !strings.Contains(notes, required) { + t.Fatalf("v6.4.2 release notes missing %q", required) + } + } + for _, required := range []string{ + "effective RBAC `admin` grant on `*`", + "SSO-only installation must map at least one trusted IdP group", + "Promotion path: emergency stable patch from `main`", + "Mobile decision: `no-mobile-impact`", + } { + if !strings.Contains(changelog, required) { + t.Fatalf("v6.4.2 changelog missing %q", required) + } + } +} + func TestHelmChartDoesNotPublishRetiredExplorePrepassMonitoring(t *testing.T) { chartDir := repoFile("deploy", "helm", "pulse") err := filepath.WalkDir(chartDir, func(path string, d os.DirEntry, walkErr error) error { diff --git a/scripts/installtests/install_docker_sh_test.go b/scripts/installtests/install_docker_sh_test.go index 18239ada2..6de9fee82 100644 --- a/scripts/installtests/install_docker_sh_test.go +++ b/scripts/installtests/install_docker_sh_test.go @@ -329,6 +329,13 @@ func TestInstallDockerProofTracksStablePatchReleaseContract(t *testing.T) { "Public Unknown Publisher disclosure", ) } + if version == "6.4.2" { + assertFileContainsAllNormalized(t, repoFile("docs", "release-control", "v6", "internal", "subsystems", "deployment-installability.md"), + "The governed branch is `main`", + "authenticated non-administrator organization members can reach infrastructure action control", + "SSO-only deployments can treat every authenticated IdP user as an instance administrator without an explicit grant", + ) + } } func TestInstallDockerProofTracksStableMinorContract(t *testing.T) { diff --git a/scripts/release_control/render_release_body_test.py b/scripts/release_control/render_release_body_test.py index 2e1ca7302..7f7bec47c 100644 --- a/scripts/release_control/render_release_body_test.py +++ b/scripts/release_control/render_release_body_test.py @@ -29,6 +29,21 @@ def _discover_rc_draft_packet_paths() -> tuple[str, ...]: class RenderReleaseBodyTest(unittest.TestCase): + def test_v642_security_packet_keeps_both_admin_boundaries_visible(self) -> None: + notes = ( + _REPO_ROOT / "docs" / "releases" / "RELEASE_NOTES_v6.4.2.md" + ).read_text(encoding="utf-8") + + for expected in ( + "Infrastructure actions honor role boundaries", + "SSO access no longer implies administrator access", + "map at least one trusted IdP group to the built-in `admin` role before upgrading", + "The rollback target is stable `v6.4.1`", + ): + self.assertIn(expected, notes) + self.assertNotIn("## Fixes", notes) + render_release_body.validate_release_notes_shape(notes, "6.4.2") + def test_v640_stable_packet_keeps_release_boundaries_visible(self) -> None: notes = ( _REPO_ROOT / "docs" / "releases" / "RELEASE_NOTES_v6.4.0.md"