mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-19 02:28:59 +00:00
Prepare v6.1.1 emergency patch release
This commit is contained in:
parent
d2c268c0e5
commit
781e168e34
22 changed files with 335 additions and 126 deletions
4
.github/workflows/create-release.yml
vendored
4
.github/workflows/create-release.yml
vendored
|
|
@ -38,12 +38,12 @@ on:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
unsigned_windows_exception:
|
unsigned_windows_exception:
|
||||||
description: 'v6.1.0 only: publish Windows agents without Authenticode under the recorded owner exception'
|
description: 'v6.1.0 or v6.1.1 only: publish Windows agents without Authenticode under a recorded owner exception'
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
unsigned_windows_reason:
|
unsigned_windows_reason:
|
||||||
description: 'v6.1.0 only: owner reason for the unsigned Windows exception'
|
description: 'v6.1.0 or v6.1.1 only: owner reason for the unsigned Windows exception'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
historical_asset_backfill_only:
|
historical_asset_backfill_only:
|
||||||
|
|
|
||||||
6
.github/workflows/release-dry-run.yml
vendored
6
.github/workflows/release-dry-run.yml
vendored
|
|
@ -43,12 +43,12 @@ on:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
unsigned_windows_exception:
|
unsigned_windows_exception:
|
||||||
description: 'v6.1.0 only: rehearse Windows agents without Authenticode under the recorded owner exception'
|
description: 'v6.1.0 or v6.1.1 only: rehearse Windows agents without Authenticode under a recorded owner exception'
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
unsigned_windows_reason:
|
unsigned_windows_reason:
|
||||||
description: 'v6.1.0 only: owner reason for the unsigned Windows exception'
|
description: 'v6.1.0 or v6.1.1 only: owner reason for the unsigned Windows exception'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
note:
|
note:
|
||||||
|
|
@ -79,7 +79,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version }}
|
version: ${{ inputs.version }}
|
||||||
require_macos_signing: true
|
require_macos_signing: true
|
||||||
require_windows_signing: ${{ !contains(inputs.version, '-') && !(inputs.version == '6.1.0' && inputs.unsigned_windows_exception) }}
|
require_windows_signing: ${{ !contains(inputs.version, '-') && !((inputs.version == '6.1.0' || inputs.version == '6.1.1') && inputs.unsigned_windows_exception) }}
|
||||||
windows_signing_backend: signpath
|
windows_signing_backend: signpath
|
||||||
|
|
||||||
dry-run:
|
dry-run:
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
6.1.0
|
6.1.1
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ apiVersion: v2
|
||||||
name: pulse
|
name: pulse
|
||||||
description: Helm chart for deploying the Pulse hub and optional Docker monitoring agent.
|
description: Helm chart for deploying the Pulse hub and optional Docker monitoring agent.
|
||||||
type: application
|
type: application
|
||||||
version: 6.1.0
|
version: 6.1.1
|
||||||
appVersion: "6.1.0"
|
appVersion: "6.1.1"
|
||||||
icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.1.0/docs/images/pulse-logo.svg
|
icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.1.1/docs/images/pulse-logo.svg
|
||||||
keywords:
|
keywords:
|
||||||
- monitoring
|
- monitoring
|
||||||
- proxmox
|
- proxmox
|
||||||
|
|
@ -32,7 +32,7 @@ annotations:
|
||||||
description: Smoke tests with kind cluster deployment
|
description: Smoke tests with kind cluster deployment
|
||||||
artifacthub.io/links: |
|
artifacthub.io/links: |
|
||||||
- name: Documentation
|
- name: Documentation
|
||||||
url: https://github.com/rcourtman/Pulse/blob/v6.1.0/docs/KUBERNETES.md
|
url: https://github.com/rcourtman/Pulse/blob/v6.1.1/docs/KUBERNETES.md
|
||||||
- name: Support
|
- name: Support
|
||||||
url: https://github.com/rcourtman/Pulse/discussions
|
url: https://github.com/rcourtman/Pulse/discussions
|
||||||
artifacthub.io/maintainers: |
|
artifacthub.io/maintainers: |
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# pulse
|
# pulse
|
||||||
|
|
||||||
  
|
  
|
||||||
|
|
||||||
Helm chart for deploying the Pulse hub and optional Docker monitoring agent.
|
Helm chart for deploying the Pulse hub and optional Docker monitoring agent.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
pulse:
|
pulse:
|
||||||
image: ${PULSE_IMAGE:-rcourtman/pulse:6.1.0}
|
image: ${PULSE_IMAGE:-rcourtman/pulse:6.1.1}
|
||||||
container_name: pulse
|
container_name: pulse
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
logging:
|
logging:
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
Pulse release notes live on GitHub:
|
Pulse release notes live on GitHub:
|
||||||
<https://github.com/rcourtman/Pulse/releases>
|
<https://github.com/rcourtman/Pulse/releases>
|
||||||
|
|
||||||
For the next release disclosure draft (version assigned at release cut), see:
|
|
||||||
- `docs/releases/RELEASE_NOTES_NEXT_DRAFT.md`
|
|
||||||
|
|
||||||
For historical v4 notes that previously lived in this repo, see:
|
For historical v4 notes that previously lived in this repo, see:
|
||||||
`docs/releases/RELEASE_NOTES_v4.md`
|
`docs/releases/RELEASE_NOTES_v4.md`
|
||||||
|
|
||||||
For the current stable v6 packet, see:
|
For the current stable v6 packet, see:
|
||||||
|
- `docs/releases/RELEASE_NOTES_v6.1.1.md`
|
||||||
|
- `docs/releases/V6_CHANGELOG_v6.1.1.md`
|
||||||
|
|
||||||
|
For earlier stable v6.1 packets, see:
|
||||||
- `docs/releases/RELEASE_NOTES_v6.1.0.md`
|
- `docs/releases/RELEASE_NOTES_v6.1.0.md`
|
||||||
- `docs/releases/V6_CHANGELOG_v6.1.0.md`
|
- `docs/releases/V6_CHANGELOG_v6.1.0.md`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@ This guide covers practical upgrade steps for existing Pulse installs moving to
|
||||||
|
|
||||||
For the current stable v6 packet, see:
|
For the current stable v6 packet, see:
|
||||||
|
|
||||||
- `docs/releases/RELEASE_NOTES_v6.1.0.md`
|
- `docs/releases/RELEASE_NOTES_v6.1.1.md`
|
||||||
- `docs/releases/V6_CHANGELOG_v6.1.0.md`
|
- `docs/releases/V6_CHANGELOG_v6.1.1.md`
|
||||||
|
|
||||||
For earlier stable v6 packets and rollout references, see:
|
For earlier stable v6 packets and rollout references, see:
|
||||||
|
|
||||||
|
- `docs/releases/RELEASE_NOTES_v6.1.0.md`
|
||||||
|
- `docs/releases/V6_CHANGELOG_v6.1.0.md`
|
||||||
- `docs/releases/RELEASE_NOTES_v6.0.5.md`
|
- `docs/releases/RELEASE_NOTES_v6.0.5.md`
|
||||||
- `docs/releases/V6_CHANGELOG_v6.0.5.md`
|
- `docs/releases/V6_CHANGELOG_v6.0.5.md`
|
||||||
- `docs/releases/RELEASE_NOTES_v6.0.4.md`
|
- `docs/releases/RELEASE_NOTES_v6.0.4.md`
|
||||||
|
|
|
||||||
|
|
@ -1022,9 +1022,10 @@ Companion drill:
|
||||||
the public demo remains healthy on stable `6.0.5`.
|
the public demo remains healthy on stable `6.0.5`.
|
||||||
- Pass when:
|
- Pass when:
|
||||||
The external rehearsal proves the canonical exact-SHA candidate builder and
|
The external rehearsal proves the canonical exact-SHA candidate builder and
|
||||||
its version-specific native-signing policy. If the `v6.1.0` Windows exception
|
its version-specific native-signing policy. If a recorded `v6.1.0` or
|
||||||
is used, the rehearsal must preserve checksum, detached-signature, manifest,
|
`v6.1.1` Windows exception is used, the rehearsal must preserve checksum,
|
||||||
and digest controls and record the owner reason and public disclosure. Local
|
detached-signature, manifest, and digest controls and record the
|
||||||
|
version-bound owner reason and public disclosure. Local
|
||||||
tests pin candidate-only publication and GitHub digest validation, and the
|
tests pin candidate-only publication and GitHub digest validation, and the
|
||||||
static release DAG contains no duplicate release build,
|
static release DAG contains no duplicate release build,
|
||||||
backend-to-integration serialization, full-download standard validator, or
|
backend-to-integration serialization, full-download standard validator, or
|
||||||
|
|
@ -1037,7 +1038,8 @@ Companion drill:
|
||||||
release packet, independent post-release jobs are serialized, or the
|
release packet, independent post-release jobs are serialized, or the
|
||||||
definitive verdict can pass without all applicable downstream results. Also
|
definitive verdict can pass without all applicable downstream results. Also
|
||||||
block if an unsigned stable Windows exception can apply to any version other
|
block if an unsigned stable Windows exception can apply to any version other
|
||||||
than `v6.1.0` or can omit its owner reason and release-note disclosure.
|
than the recorded `v6.1.0` and `v6.1.1` decisions or can omit its owner
|
||||||
|
reason and release-note disclosure.
|
||||||
|
|
||||||
## Gate: `operational-trust-canonical-lifecycle`
|
## Gate: `operational-trust-canonical-lifecycle`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,8 +179,15 @@ Cloud, and self-hosted production users.
|
||||||
Windows Authenticode exception. The Windows artifacts must remain bound
|
Windows Authenticode exception. The Windows artifacts must remain bound
|
||||||
by the exact-SHA candidate manifest, checksums, detached `.sig`/`.sshsig`
|
by the exact-SHA candidate manifest, checksums, detached `.sig`/`.sshsig`
|
||||||
signatures, and published digests, and the public notes must disclose the
|
signatures, and published digests, and the public notes must disclose the
|
||||||
Unknown Publisher state. Later stable releases restore the Authenticode
|
Unknown Publisher state.
|
||||||
requirement; this flag cannot be reused for another version.
|
- On 2026-07-23, the release owner separately approved a `v6.1.1`-only
|
||||||
|
Windows Authenticode exception for the emergency patch addressing active
|
||||||
|
customer update harm. This is a new, version-bound decision rather than a
|
||||||
|
reuse of the `v6.1.0` exception. The same exact-SHA candidate, checksum,
|
||||||
|
detached-signature, manifest, published-digest, owner-reason, and public
|
||||||
|
Unknown Publisher disclosure controls remain mandatory. Stable `v6.1.2`
|
||||||
|
and later restore the Authenticode requirement unless another explicit
|
||||||
|
version-bound owner decision is recorded in policy.
|
||||||
- Unproved self-service commercial transitions remain unavailable and
|
- Unproved self-service commercial transitions remain unavailable and
|
||||||
unadvertised under the exposure-safety gate. This exception does not
|
unadvertised under the exposure-safety gate. This exception does not
|
||||||
authorize enabling that feature or running a production billing proof.
|
authorize enabling that feature or running a production billing proof.
|
||||||
|
|
@ -237,8 +244,11 @@ Cloud, and self-hosted production users.
|
||||||
onto the RC promotion path. The resolver enforces that boundary. Do not use
|
onto the RC promotion path. The resolver enforces that boundary. Do not use
|
||||||
the routine helper to relabel a risky patch as routine.
|
the routine helper to relabel a risky patch as routine.
|
||||||
4. `--emergency-hotfix-reason` is the narrow escape hatch for active customer
|
4. `--emergency-hotfix-reason` is the narrow escape hatch for active customer
|
||||||
harm. It does not remove the exact-SHA dry-run requirement, and the reason is
|
harm. It does not remove the integrated exact-SHA candidate and release
|
||||||
recorded in the release metadata.
|
checks, and the reason is recorded in the release metadata.
|
||||||
|
A version-bound unsigned Windows decision must additionally be supplied
|
||||||
|
through `--unsigned-windows-exception-reason`; it never follows implicitly
|
||||||
|
from emergency patch status.
|
||||||
5. The release workflow must await Docker publication, stable demo deployment,
|
5. The release workflow must await Docker publication, stable demo deployment,
|
||||||
public health/browser verification, install smoke, Helm publication,
|
public health/browser verification, install smoke, Helm publication,
|
||||||
floating-tag promotion, and private Pro promotion where applicable. The
|
floating-tag promotion, and private Pro promotion where applicable. The
|
||||||
|
|
|
||||||
|
|
@ -9176,7 +9176,21 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"work_claims": [],
|
"work_claims": [
|
||||||
|
{
|
||||||
|
"id": "codex-release-gate-stable-patch-unattended-release-path",
|
||||||
|
"agent_id": "codex",
|
||||||
|
"summary": "Prepare and publish v6.1.1 emergency stable patch with owner-approved unsigned Windows exception",
|
||||||
|
"target_id": "v6-product-lane-expansion",
|
||||||
|
"claimed_at": "2026-07-23T12:19:02Z",
|
||||||
|
"heartbeat_at": "2026-07-23T12:19:02Z",
|
||||||
|
"expires_at": "2026-07-23T16:19:02Z",
|
||||||
|
"work_item": {
|
||||||
|
"kind": "release-gate",
|
||||||
|
"id": "stable-patch-unattended-release-path"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"open_decisions": [],
|
"open_decisions": [],
|
||||||
"source_of_truth_file": "docs/release-control/v6/internal/SOURCE_OF_TRUTH.md",
|
"source_of_truth_file": "docs/release-control/v6/internal/SOURCE_OF_TRUTH.md",
|
||||||
"resolved_decisions": [
|
"resolved_decisions": [
|
||||||
|
|
|
||||||
|
|
@ -379,12 +379,14 @@ TLS floor in the dynamic config.
|
||||||
apply the same channel-specific native-signing policy as a publish run.
|
apply the same channel-specific native-signing policy as a publish run.
|
||||||
macOS notarization remains mandatory for both prerelease and stable
|
macOS notarization remains mandatory for both prerelease and stable
|
||||||
candidates. Windows Authenticode remains mandatory for stable candidates
|
candidates. Windows Authenticode remains mandatory for stable candidates
|
||||||
except for the explicitly version-bound `v6.1.0` owner exception;
|
except for the explicitly version-bound `v6.1.0` and `v6.1.1` owner
|
||||||
prerelease candidates and that one stable exception may retain checksum and
|
exceptions; prerelease candidates and those two stable exceptions may
|
||||||
detached-signature verification without Authenticode while the release
|
retain checksum and detached-signature verification without Authenticode
|
||||||
packet explicitly discloses the unknown-publisher warning. Prerelease promotion remains
|
while the release packet explicitly discloses the unknown-publisher warning.
|
||||||
blocked on the normal stable signing requirement, and every stable version
|
Prerelease promotion remains blocked on the normal stable signing
|
||||||
after `v6.1.0` restores it automatically. A cheap signing-configuration job
|
requirement, and stable `v6.1.2` and later restore it automatically unless
|
||||||
|
policy records a new version-bound owner decision. A cheap
|
||||||
|
signing-configuration job
|
||||||
must report every missing secret for the platforms required by that
|
must report every missing secret for the platforms required by that
|
||||||
candidate before either platform runner is allocated. Stable Windows signing must use SignPath's GitHub
|
candidate before either platform runner is allocated. Stable Windows signing must use SignPath's GitHub
|
||||||
trusted-build-system action by default, submit an immutable GitHub artifact
|
trusted-build-system action by default, submit an immutable GitHub artifact
|
||||||
|
|
@ -1055,9 +1057,12 @@ evidence beside the candidate manifest. Release Dry Run now has a terminal
|
||||||
verdict covering the exact-SHA candidate and no-mutation demo lane. Stable
|
verdict covering the exact-SHA candidate and no-mutation demo lane. Stable
|
||||||
rehearsal `29927692302` confirmed that the external SignPath project was not
|
rehearsal `29927692302` confirmed that the external SignPath project was not
|
||||||
configured and stopped without creating a public release. The release owner
|
configured and stopped without creating a public release. The release owner
|
||||||
subsequently approved a `v6.1.0`-only unsigned-Windows exception; the gate stays
|
subsequently approved and exercised a `v6.1.0`-only unsigned-Windows exception.
|
||||||
blocked until a new exact-`main` rehearsal proves that exception and the
|
On 2026-07-23 the owner separately approved a `v6.1.1`-only exception for the
|
||||||
remaining candidate controls.
|
emergency patch addressing active customer update harm. The new decision must
|
||||||
|
flow through the normal exact-SHA candidate, checksum, detached-signature,
|
||||||
|
manifest, published-digest, and definitive-verdict controls with an explicit
|
||||||
|
owner reason and public Unknown Publisher disclosure.
|
||||||
Every caller of the reusable release-candidate builder must delegate
|
Every caller of the reusable release-candidate builder must delegate
|
||||||
`actions: read` alongside `contents: read`; the Windows signing job reads the
|
`actions: read` alongside `contents: read`; the Windows signing job reads the
|
||||||
exact uploaded artifact through the GitHub Actions API, and GitHub validates
|
exact uploaded artifact through the GitHub Actions API, and GitHub validates
|
||||||
|
|
@ -1068,11 +1073,35 @@ host-local redirect contract as runtime token minting and exchange. Proof input
|
||||||
must reject absolute, scheme-relative, backslash-authority, encoded-separator,
|
must reject absolute, scheme-relative, backslash-authority, encoded-separator,
|
||||||
and control-character targets before constructing the handoff request.
|
and control-character targets before constructing the handoff request.
|
||||||
|
|
||||||
The active stable `v6.1.0` cut sets the repo-root `VERSION`,
|
The active stable `v6.1.1` cut sets the repo-root `VERSION`, repo-root
|
||||||
repo-root `docker-compose.yml` image default, `scripts/install-docker.sh`
|
`docker-compose.yml` image default, `scripts/install-docker.sh` fallback, and
|
||||||
fallback, and Helm chart release metadata to the same `6.1.0` release version.
|
Helm chart release metadata to the same `6.1.1` release version. This patch
|
||||||
This stable minor release uses `promoted_from_tag=v6.1.0-rc.4`,
|
release uses the stable hotfix path with `rollback_version=v6.1.0`,
|
||||||
`rollback_version=v6.0.5`, and the one-version release-owner cutoff exception
|
`hotfix_exception=true`, a release-owner reason, and no fabricated
|
||||||
|
same-version RC tag. It fixes manual Unified Agent updates that received a
|
||||||
|
distribution identifier instead of the canonical Linux platform family and
|
||||||
|
durable Docker update actions that could remain stuck after a terminal
|
||||||
|
digest-drift preflight refusal. The exact stable `main` SHA must pass the
|
||||||
|
integrated release checks and immutable-candidate build before the single-build
|
||||||
|
workflow crosses its public mutation boundary. The same workflow must finish
|
||||||
|
Docker, Helm, stable demo, install-smoke, public-health, floating-tag,
|
||||||
|
paid-runtime, and definitive-verdict lanes before the cut is complete.
|
||||||
|
The `v6.1.1` release is `existing-mobile-build-compatible`: no production
|
||||||
|
relay or mobile trust contract changed from `v6.1.0`, the matched mobile-facing
|
||||||
|
path is test-only expiry branch coverage, and Pulse Mobile `1.0.0` iOS build
|
||||||
|
`11` and Android versionCode `9` remain the compatible candidate builds without
|
||||||
|
a companion upload or public store rollout.
|
||||||
|
The release owner separately approved a `v6.1.1`-only unsigned-Windows
|
||||||
|
exception because SignPath configuration remains unavailable. Windows assets
|
||||||
|
must remain exact-SHA and manifest-bound with checksums, detached
|
||||||
|
`.sig`/`.sshsig` signatures, and published-digest verification; the release
|
||||||
|
notes must disclose the Unknown Publisher state. Stable `v6.1.2` and later
|
||||||
|
restore Authenticode unless policy records another explicit version-bound
|
||||||
|
decision.
|
||||||
|
|
||||||
|
The preceding stable `v6.1.0` cut used
|
||||||
|
`promoted_from_tag=v6.1.0-rc.4`, `rollback_version=v6.0.5`, and the
|
||||||
|
one-version release-owner cutoff exception
|
||||||
recorded on 2026-07-22. The workflow input `hotfix_exception=true` carries that
|
recorded on 2026-07-22. The workflow input `hotfix_exception=true` carries that
|
||||||
approved soak bypass through the existing promotion resolver; it does not
|
approved soak bypass through the existing promotion resolver; it does not
|
||||||
reclassify the release as a patch hotfix. The exact stable `main` SHA must pass
|
reclassify the release as a patch hotfix. The exact stable `main` SHA must pass
|
||||||
|
|
@ -1112,8 +1141,10 @@ explicitly waived Authenticode after the first stable rehearsal exposed
|
||||||
unavailable external SignPath configuration. The unsigned Windows binaries
|
unavailable external SignPath configuration. The unsigned Windows binaries
|
||||||
remain exact-SHA and manifest-bound with checksum, detached `.sig`/`.sshsig`,
|
remain exact-SHA and manifest-bound with checksum, detached `.sig`/`.sshsig`,
|
||||||
and published-digest verification, and the release notes disclose the Unknown
|
and published-digest verification, and the release notes disclose the Unknown
|
||||||
Publisher state. This exception cannot apply to a later stable version.
|
Publisher state. That `v6.1.0` decision does not itself authorize another
|
||||||
The stable server cut is classified `existing-mobile-build-compatible`. Pulse
|
version.
|
||||||
|
The `v6.1.0` stable server cut was classified
|
||||||
|
`existing-mobile-build-compatible`. Pulse
|
||||||
Mobile `1.0.0` iOS build `11` and Android versionCode `9` remain the existing
|
Mobile `1.0.0` iOS build `11` and Android versionCode `9` remain the existing
|
||||||
candidate builds; the canonical core/mobile contract proves that `v6.1.0`
|
candidate builds; the canonical core/mobile contract proves that `v6.1.0`
|
||||||
serves their route, scope, payload, pairing, and push requirements, including
|
serves their route, scope, payload, pairing, and push requirements, including
|
||||||
|
|
@ -1180,8 +1211,8 @@ compose image default, standalone installer fallback constant, and packaged
|
||||||
Helm metadata. A draft release workflow failure caused by stale image or chart
|
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
|
pins is a release-packet blocker until the defaults, tests, and evidence
|
||||||
record are refreshed from the new branch head.
|
record are refreshed from the new branch head.
|
||||||
For the active stable `v6.1.0` cut, the repo-root compose default and
|
For the active stable `v6.1.1` cut, the repo-root compose default and
|
||||||
`scripts/install-docker.sh` fallback must both pin `6.1.0` until the next
|
`scripts/install-docker.sh` fallback must both pin `6.1.1` until the next
|
||||||
governed stable cut moves them forward. The stable promotion guard remains in
|
governed stable cut moves them forward. The stable promotion guard remains in
|
||||||
force and rejects leftover `-rc.` defaults.
|
force and rejects leftover `-rc.` defaults.
|
||||||
The RC7 packet refresh records `fc10de9b5477613316473267b72b05b6b2b7aaff`
|
The RC7 packet refresh records `fc10de9b5477613316473267b72b05b6b2b7aaff`
|
||||||
|
|
@ -2496,8 +2527,9 @@ discloses the unsigned Windows publisher state and the Windows binaries retain
|
||||||
the exact-SHA candidate, checksum, detached-signature, and post-publication
|
the exact-SHA candidate, checksum, detached-signature, and post-publication
|
||||||
digest controls. Stable publication and the stable-path dry-run must continue
|
digest controls. Stable publication and the stable-path dry-run must continue
|
||||||
to require both native signing lanes except for the recorded, version-bound
|
to require both native signing lanes except for the recorded, version-bound
|
||||||
`v6.1.0` Windows exception; every subsequent stable release restores both
|
`v6.1.0` and `v6.1.1` Windows exceptions; stable `v6.1.2` and later restore
|
||||||
requirements. `scripts/build-release.sh` must replace
|
both requirements unless policy records a new explicit version-bound owner
|
||||||
|
decision. `scripts/build-release.sh` must replace
|
||||||
only the native targets required by those independent inputs and must fail
|
only the native targets required by those independent inputs and must fail
|
||||||
closed when a required native-binary directory or target is absent.
|
closed when a required native-binary directory or target is absent.
|
||||||
Historical published-release repair must flow through
|
Historical published-release repair must flow through
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
# Next Pulse Release — Disclosure Draft
|
|
||||||
|
|
||||||
This draft records customer-visible disclosures that must be carried into the
|
|
||||||
next Pulse release packet. The release version is assigned only when that
|
|
||||||
packet is cut.
|
|
||||||
|
|
||||||
## Outbound usage telemetry schema v2
|
|
||||||
|
|
||||||
This release updates Pulse's legacy unversioned outbound usage telemetry
|
|
||||||
payload to schema v2. Telemetry remains enabled by default unless an operator
|
|
||||||
has disabled it; an existing enabled or disabled choice is preserved on
|
|
||||||
upgrade. The purpose remains aggregate product and release understanding, and
|
|
||||||
the payload remains pseudonymous rather than tied to a Pulse account or
|
|
||||||
person.
|
|
||||||
|
|
||||||
Schema v2 adds these deliberately coarse signal categories:
|
|
||||||
|
|
||||||
- closed deployment-method, known-install-age, activation-stage,
|
|
||||||
time-to-first-monitored-resource, and estate-size buckets;
|
|
||||||
- authentication-configured and monitoring-active booleans, plus an aggregate
|
|
||||||
configured-connection count;
|
|
||||||
- aggregate alert fired, acknowledged, and resolved counts from the existing
|
|
||||||
30-day local window;
|
|
||||||
- aggregate notification attempt, delivery, and failure counts from the
|
|
||||||
existing seven-day local window; and
|
|
||||||
- a boolean indicating whether an operational outcome was observed in the
|
|
||||||
existing 30-day local window.
|
|
||||||
|
|
||||||
The payload does not include names, email addresses, account IDs, hostnames,
|
|
||||||
credentials, infrastructure or resource identifiers, IP addresses, URLs,
|
|
||||||
paths, locale, recipients, notification endpoints, alert or notification
|
|
||||||
content, prompts, chat messages, command text, action output, token values,
|
|
||||||
browser events, or an event-level journey or clickstream. The rotating
|
|
||||||
pseudonymous installation ID continues to rotate every 30 days. Telemetry rows
|
|
||||||
are retained server-side for up to 90 days; request IP addresses are used only
|
|
||||||
transiently for rate limiting and are not stored in telemetry rows.
|
|
||||||
|
|
||||||
Existing installations receive a one-time, non-blocking
|
|
||||||
**Telemetry payload updated** notice after upgrade. It links directly to the
|
|
||||||
exact payload preview, the disable action, and the full privacy disclosure.
|
|
||||||
Fresh installations do not receive a duplicate banner because the current
|
|
||||||
payload and controls are already disclosed during setup.
|
|
||||||
|
|
||||||
## Terminology correction
|
|
||||||
|
|
||||||
Earlier public website copy used an anonymity label that was too strong for a
|
|
||||||
payload containing a rotating installation identifier. The accurate term is
|
|
||||||
**pseudonymous**. The website wording was corrected in July 2026, before
|
|
||||||
schema v2 reached a public Pulse release; the shipped privacy documentation
|
|
||||||
and in-product control identify the rotating pseudonymous ID and the concrete
|
|
||||||
data categories excluded from the payload.
|
|
||||||
97
docs/releases/RELEASE_NOTES_v6.1.1.md
Normal file
97
docs/releases/RELEASE_NOTES_v6.1.1.md
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Pulse v6.1.1 Release Notes
|
||||||
|
|
||||||
|
`v6.1.1` is a stable patch release following `v6.1.0`. It takes the governed
|
||||||
|
emergency stable-patch path to resolve active customer harm in the manual
|
||||||
|
Unified Agent update flow and durable Docker update recovery. It also carries
|
||||||
|
the reliability, infrastructure, and privacy-disclosure improvements already
|
||||||
|
completed on `main` after the `v6.1.0` cutoff.
|
||||||
|
|
||||||
|
## Highlights
|
||||||
|
|
||||||
|
- Manual Unified Agent updates now use the canonical operating-system family,
|
||||||
|
so Mageia and other supported Linux distributions receive the Linux update
|
||||||
|
path instead of being rejected by a distribution-specific platform value.
|
||||||
|
- Docker update actions recover their durable terminal receipt by immutable
|
||||||
|
action and operation identity. A failed or no-effect digest-drift preflight
|
||||||
|
no longer leaves an update stuck after the live capability disappears.
|
||||||
|
- Outbound usage telemetry moves to a documented schema v2 with coarse,
|
||||||
|
pseudonymous operational signals, an exact payload preview, and a one-time
|
||||||
|
non-blocking upgrade notice.
|
||||||
|
- Infrastructure pages retain navigation through stream reconnects, proxy and
|
||||||
|
SSO bootstrap is more reliable, node edits use the correct update endpoint,
|
||||||
|
and PBS datastore alert overrides appear on the thresholds page.
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Agent runtime platform reporting is normalized to the canonical Go operating
|
||||||
|
system family while preserving the original operating-system identity for
|
||||||
|
diagnostics. Unsupported platforms still fail closed.
|
||||||
|
- Outbound usage telemetry remains enabled by default unless an operator has
|
||||||
|
disabled it, and an existing enabled or disabled preference is preserved on
|
||||||
|
upgrade. The rotating pseudonymous installation ID continues to rotate every
|
||||||
|
30 days.
|
||||||
|
- Telemetry schema v2 adds deliberately coarse deployment-method, install-age,
|
||||||
|
activation-stage, time-to-first-monitored-resource, and estate-size buckets;
|
||||||
|
authentication-configured and monitoring-active booleans; configured
|
||||||
|
connection count; aggregate alert outcome counts; aggregate notification
|
||||||
|
attempt, delivery, and failure counts; and an operational-outcome boolean.
|
||||||
|
- Existing installations receive one non-blocking **Telemetry payload
|
||||||
|
updated** notice with direct links to the exact payload preview, disable
|
||||||
|
action, and privacy disclosure. Fresh installations do not receive a
|
||||||
|
duplicate notice.
|
||||||
|
- Public privacy terminology now describes this rotating-identifier payload as
|
||||||
|
**pseudonymous**, not anonymous.
|
||||||
|
|
||||||
|
Telemetry does not include identities, account details, hostnames, credentials,
|
||||||
|
resource identifiers, IP addresses, URLs, paths, locale, recipients,
|
||||||
|
notification endpoints, alert or notification content, prompts, chat
|
||||||
|
messages, command text or output, token values, browser events, or an
|
||||||
|
event-level journey or clickstream. Telemetry rows are retained server-side for
|
||||||
|
up to 90 days; request IP addresses are used transiently for rate limiting and
|
||||||
|
are not stored in telemetry rows.
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Manual Unified Agent updates on Mageia and other supported Linux
|
||||||
|
distributions no longer fail because the update planner receives a distro
|
||||||
|
identifier instead of the Linux platform family (#1607).
|
||||||
|
- Docker update actions that reach a terminal digest-drift preflight refusal
|
||||||
|
now recover as failed or no-effect without redispatch, even when the live
|
||||||
|
update capability is no longer advertised (#1608).
|
||||||
|
- Node state aggregation keeps clusters separate when they reuse the same node
|
||||||
|
names.
|
||||||
|
- Missing Patrol verdicts are swept with bounded follow-up instead of remaining
|
||||||
|
indefinitely unresolved.
|
||||||
|
- Platform navigation survives stream reconnects, and authenticated bootstrap
|
||||||
|
works correctly through proxy and SSO configurations.
|
||||||
|
- Infrastructure node edits route to the update endpoint.
|
||||||
|
- PBS datastore alert overrides are projected onto the thresholds page.
|
||||||
|
- The Proxmox VE setup script avoids an `awk` variable name that conflicts with
|
||||||
|
implementations where `exp` is reserved.
|
||||||
|
|
||||||
|
## Upgrade Notes
|
||||||
|
|
||||||
|
Use the normal v6 install or update flow for `v6.1.1`.
|
||||||
|
|
||||||
|
Windows Unified Agent binaries in `v6.1.1` are not Authenticode-signed and may
|
||||||
|
show an Unknown Publisher warning. Verify published checksums and detached
|
||||||
|
`.sig` or `.sshsig` signatures before installation. This is a `v6.1.1`-only
|
||||||
|
release-owner exception; later stable releases restore the Windows
|
||||||
|
Authenticode requirement.
|
||||||
|
|
||||||
|
The rollback target for this patch release is `v6.1.0`. The exact rollback
|
||||||
|
reinstall command is:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/install.sh --version v6.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
The server/mobile decision is `existing-mobile-build-compatible`. Pulse Mobile
|
||||||
|
`1.0.0` iOS build `11` and Android versionCode `9` remain the compatible
|
||||||
|
candidate builds. No production relay or mobile trust contract changed after
|
||||||
|
`v6.1.0`; the matched mobile-facing path is test-only branch coverage. This
|
||||||
|
release does not upload a companion build or start a public mobile-store
|
||||||
|
rollout.
|
||||||
|
|
||||||
|
Paid Pulse Pro, Relay, and eligible legacy customers should continue to use the
|
||||||
|
private download page and private runtime image for paid runtime features.
|
||||||
45
docs/releases/V6_CHANGELOG_v6.1.1.md
Normal file
45
docs/releases/V6_CHANGELOG_v6.1.1.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Pulse v6.1.1
|
||||||
|
|
||||||
|
_This changelog describes stable `v6.1.1` compared with stable `v6.1.0`._
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Unified Agent operating-system reporting now provides the canonical runtime
|
||||||
|
platform family to the update planner while retaining detailed OS identity
|
||||||
|
for diagnostics.
|
||||||
|
- Outbound usage telemetry uses schema v2 with rotating pseudonymous identity,
|
||||||
|
bounded aggregate operational signals, preserved operator preference, exact
|
||||||
|
payload preview, and a one-time non-blocking upgrade disclosure.
|
||||||
|
- Privacy copy uses the accurate term **pseudonymous** and explicitly lists the
|
||||||
|
identity, infrastructure, content, command, and clickstream categories
|
||||||
|
excluded from telemetry.
|
||||||
|
- Infrastructure navigation, authenticated proxy/SSO bootstrap, node-edit
|
||||||
|
routing, and PBS alert-threshold projection are more consistent.
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Linux manual agent updates no longer misclassify Mageia or other supported
|
||||||
|
distributions as an unsupported update platform (#1607).
|
||||||
|
- Durable Docker update receipt recovery uses immutable action and operation
|
||||||
|
binding, terminalizes digest-drift preflight refusals after capability loss,
|
||||||
|
and never redispatches the rejected operation (#1608).
|
||||||
|
- Cluster node aggregation no longer conflates separate clusters that reuse a
|
||||||
|
node name.
|
||||||
|
- Missing Patrol verdicts retain bounded follow-up.
|
||||||
|
- The Proxmox VE setup script avoids an `awk` identifier collision.
|
||||||
|
|
||||||
|
## Release Metadata
|
||||||
|
|
||||||
|
- Version: `v6.1.1`
|
||||||
|
- Previous stable: `v6.1.0`
|
||||||
|
- Rollback target: `v6.1.0`
|
||||||
|
- Rollback command: `./scripts/install.sh --version v6.1.0`
|
||||||
|
- Promotion path: stable patch hotfix from `main`, with an owner-recorded reason
|
||||||
|
for active customer update harm and no fabricated same-version RC tag
|
||||||
|
- Windows signing decision: `v6.1.1`-only release-owner exception; Windows
|
||||||
|
Unified Agent binaries are not Authenticode-signed and may show an Unknown
|
||||||
|
Publisher warning, while exact-SHA candidate binding, checksums, detached
|
||||||
|
`.sig`/`.sshsig` signatures, manifests, and published digests remain required
|
||||||
|
- Mobile decision: `existing-mobile-build-compatible`; Pulse Mobile `1.0.0`
|
||||||
|
iOS build `11` and Android versionCode `9` require no companion upload, and
|
||||||
|
no public store rollout is part of this server release
|
||||||
|
|
@ -6,7 +6,7 @@ set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
DOCKER_IMAGE_REPO="${DOCKER_IMAGE_REPO:-rcourtman/pulse}"
|
DOCKER_IMAGE_REPO="${DOCKER_IMAGE_REPO:-rcourtman/pulse}"
|
||||||
CANONICAL_DEFAULT_PULSE_VERSION="6.1.0"
|
CANONICAL_DEFAULT_PULSE_VERSION="6.1.1"
|
||||||
|
|
||||||
resolve_default_pulse_version() {
|
resolve_default_pulse_version() {
|
||||||
if [ -n "${PULSE_IMAGE_VERSION:-}" ]; then
|
if [ -n "${PULSE_IMAGE_VERSION:-}" ]; then
|
||||||
|
|
|
||||||
|
|
@ -269,25 +269,23 @@ func TestCurrentStablePatchReleasePacketTracksInstallMetadata(t *testing.T) {
|
||||||
assertFileContainsAllNormalized(t, releaseNotesPath,
|
assertFileContainsAllNormalized(t, releaseNotesPath,
|
||||||
"`v"+version+"` is a stable patch release",
|
"`v"+version+"` is a stable patch release",
|
||||||
"`v"+previous+"`",
|
"`v"+previous+"`",
|
||||||
"Patrol Gemini model readiness",
|
"Manual Unified Agent updates now use the canonical operating-system family",
|
||||||
"remembered-login submit persistence",
|
"Docker update actions recover their durable terminal receipt",
|
||||||
"Proxmox SMART temperature fallback",
|
"Outbound usage telemetry moves to a documented schema v2",
|
||||||
"direct SATA/SAT disks",
|
"clusters separate when they reuse the same node names",
|
||||||
"paid-runtime activation continuity",
|
"not Authenticode-signed",
|
||||||
"license-period status fixes",
|
"`existing-mobile-build-compatible`",
|
||||||
"rollback target for this patch release is `v"+previous+"`",
|
"rollback target for this patch release is `v"+previous+"`",
|
||||||
)
|
)
|
||||||
assertFileContainsAll(t, changelogPath,
|
assertFileContainsAll(t, changelogPath,
|
||||||
"Version: `v"+version+"`",
|
"Version: `v"+version+"`",
|
||||||
"Rollback target: `v"+previous+"`",
|
"Rollback target: `v"+previous+"`",
|
||||||
"Promotion path: stable patch hotfix from `"+releaseBranch+"`",
|
"Promotion path: stable patch hotfix from `"+releaseBranch+"`",
|
||||||
"Gemini tool-call capability",
|
"canonical runtime",
|
||||||
"Remembered-login state now persists",
|
"telemetry uses schema v2",
|
||||||
"Proxmox SMART temperature collection",
|
"Durable Docker update receipt recovery",
|
||||||
"explicit SAT probe",
|
"`v6.1.1`-only release-owner exception",
|
||||||
"Paid runtime activation now writes and reuses a durable installation fingerprint",
|
"Mobile decision: `existing-mobile-build-compatible`",
|
||||||
"License grants now include the billing `current_period_end`",
|
|
||||||
"Server installer execution now rejects unsafe piped invocation",
|
|
||||||
)
|
)
|
||||||
assertFileContainsAll(t, repoFile("docs", "RELEASE_NOTES.md"),
|
assertFileContainsAll(t, repoFile("docs", "RELEASE_NOTES.md"),
|
||||||
"docs/releases/RELEASE_NOTES_v"+version+".md",
|
"docs/releases/RELEASE_NOTES_v"+version+".md",
|
||||||
|
|
@ -385,7 +383,7 @@ func TestCurrentStableMinorReleasePacketTracksInstallMetadata(t *testing.T) {
|
||||||
"`rollback_version=v"+previous+"`",
|
"`rollback_version=v"+previous+"`",
|
||||||
"The exact stable `main` SHA must pass the no-publication dry run before the same SHA is dispatched through the single-build publish workflow.",
|
"The exact stable `main` SHA must pass the no-publication dry run before the same SHA is dispatched through the single-build publish workflow.",
|
||||||
"The stable server cut is classified `existing-mobile-build-compatible`.",
|
"The stable server cut is classified `existing-mobile-build-compatible`.",
|
||||||
"This exception cannot apply to a later stable version",
|
"explicit version-bound decision",
|
||||||
"For the active stable `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"`",
|
"For the active stable `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"`",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -849,12 +847,12 @@ func TestReleaseCandidateRequiresPlatformNativeAgentSigning(t *testing.T) {
|
||||||
)
|
)
|
||||||
assertFileContainsAll(t, repoFile(".github", "workflows", "release-dry-run.yml"),
|
assertFileContainsAll(t, repoFile(".github", "workflows", "release-dry-run.yml"),
|
||||||
`Definitive Dry-Run Verdict`,
|
`Definitive Dry-Run Verdict`,
|
||||||
`require_windows_signing: ${{ !contains(inputs.version, '-') && !(inputs.version == '6.1.0' && inputs.unsigned_windows_exception) }}`,
|
`require_windows_signing: ${{ !contains(inputs.version, '-') && !((inputs.version == '6.1.0' || inputs.version == '6.1.1') && inputs.unsigned_windows_exception) }}`,
|
||||||
`require_result "exact-SHA release candidate" "$CANDIDATE_RESULT" success`,
|
`require_result "exact-SHA release candidate" "$CANDIDATE_RESULT" success`,
|
||||||
`require_result "stable demo no-mutation verification" "$DEMO_RESULT" success`,
|
`require_result "stable demo no-mutation verification" "$DEMO_RESULT" success`,
|
||||||
)
|
)
|
||||||
assertFileContainsAll(t, repoFile("scripts", "release_control", "resolve_release_promotion.py"),
|
assertFileContainsAll(t, repoFile("scripts", "release_control", "resolve_release_promotion.py"),
|
||||||
`version != "6.1.0"`,
|
`version not in {"6.1.0", "6.1.1"}`,
|
||||||
`unsigned_windows_reason is required`,
|
`unsigned_windows_reason is required`,
|
||||||
`not Authenticode-signed`,
|
`not Authenticode-signed`,
|
||||||
`require_windows_signing = not is_prerelease and not unsigned_windows_exception`,
|
`require_windows_signing = not is_prerelease and not unsigned_windows_exception`,
|
||||||
|
|
|
||||||
|
|
@ -288,9 +288,10 @@ func TestInstallDockerProofTracksStablePatchReleaseContract(t *testing.T) {
|
||||||
assertFileContainsAllNormalized(t, repoFile("docs", "release-control", "v6", "internal", "subsystems", "deployment-installability.md"),
|
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.",
|
"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.",
|
"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",
|
"manual Unified Agent updates",
|
||||||
"paid-runtime activation fingerprint reuse",
|
"durable Docker update actions",
|
||||||
"pinned installer execution hardening",
|
"`existing-mobile-build-compatible`",
|
||||||
|
"`v"+version+"`-only unsigned-Windows exception",
|
||||||
"For the active stable `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"`",
|
"For the active stable `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"`",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -488,7 +488,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||||
self.assertIn("if: ${{ inputs.version != '' }}", workflow)
|
self.assertIn("if: ${{ inputs.version != '' }}", workflow)
|
||||||
self.assertIn("require_macos_signing: true", workflow)
|
self.assertIn("require_macos_signing: true", workflow)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
"require_windows_signing: ${{ !contains(inputs.version, '-') && !(inputs.version == '6.1.0' && inputs.unsigned_windows_exception) }}",
|
"require_windows_signing: ${{ !contains(inputs.version, '-') && !((inputs.version == '6.1.0' || inputs.version == '6.1.1') && inputs.unsigned_windows_exception) }}",
|
||||||
workflow,
|
workflow,
|
||||||
)
|
)
|
||||||
self.assertIn("unsigned_windows_exception:", workflow)
|
self.assertIn("unsigned_windows_exception:", workflow)
|
||||||
|
|
@ -669,7 +669,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||||
self.assertIn("require_windows_signing: ${{ needs.prepare.outputs.require_windows_signing == 'true' }}", content)
|
self.assertIn("require_windows_signing: ${{ needs.prepare.outputs.require_windows_signing == 'true' }}", content)
|
||||||
self.assertIn("unsigned_windows_exception:", content)
|
self.assertIn("unsigned_windows_exception:", content)
|
||||||
self.assertIn("unsigned_windows_reason:", content)
|
self.assertIn("unsigned_windows_reason:", content)
|
||||||
self.assertIn('version != "6.1.0"', resolver)
|
self.assertIn('version not in {"6.1.0", "6.1.1"}', resolver)
|
||||||
self.assertIn("not Authenticode-signed", resolver)
|
self.assertIn("not Authenticode-signed", resolver)
|
||||||
self.assertIn("windows_signing_backend: signpath", content)
|
self.assertIn("windows_signing_backend: signpath", content)
|
||||||
self.assertIn('if [[ "$REQUIRE_WINDOWS_SIGNING" == "true" ]]', candidate_workflow)
|
self.assertIn('if [[ "$REQUIRE_WINDOWS_SIGNING" == "true" ]]', candidate_workflow)
|
||||||
|
|
@ -1124,6 +1124,10 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||||
self.assertNotIn(".createdAt >= $cutoff", helper)
|
self.assertNotIn(".createdAt >= $cutoff", helper)
|
||||||
self.assertIn("gh workflow run create-release.yml", helper)
|
self.assertIn("gh workflow run create-release.yml", helper)
|
||||||
self.assertIn("gh workflow run \"$WORKFLOW\"", helper)
|
self.assertIn("gh workflow run \"$WORKFLOW\"", helper)
|
||||||
|
self.assertIn("--unsigned-windows-exception-reason", helper)
|
||||||
|
self.assertIn("--unsigned-windows-exception", helper)
|
||||||
|
self.assertIn("unsigned_windows_exception", helper)
|
||||||
|
self.assertIn("unsigned_windows_reason", helper)
|
||||||
self.assertIn("Single-Build Release Path", policy)
|
self.assertIn("Single-Build Release Path", policy)
|
||||||
self.assertIn("Routine Stable Patch Path", policy)
|
self.assertIn("Routine Stable Patch Path", policy)
|
||||||
self.assertIn("single publish workflow performs the exact-SHA preflight", normalize_ws(policy))
|
self.assertIn("single publish workflow performs the exact-SHA preflight", normalize_ws(policy))
|
||||||
|
|
|
||||||
|
|
@ -245,10 +245,10 @@ def resolve_metadata(
|
||||||
promotion_mode = "prerelease" if is_prerelease else "stable-rc-promotion"
|
promotion_mode = "prerelease" if is_prerelease else "stable-rc-promotion"
|
||||||
|
|
||||||
if unsigned_windows_exception:
|
if unsigned_windows_exception:
|
||||||
if version != "6.1.0":
|
if version not in {"6.1.0", "6.1.1"}:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"unsigned_windows_exception is approved only for stable v6.1.0. "
|
"unsigned_windows_exception is approved only for stable v6.1.0 or v6.1.1. "
|
||||||
"Later stable releases must restore Windows Authenticode signing."
|
"Stable v6.1.2 and later must restore Windows Authenticode signing."
|
||||||
)
|
)
|
||||||
if not unsigned_windows_reason:
|
if not unsigned_windows_reason:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
|
@ -256,7 +256,7 @@ def resolve_metadata(
|
||||||
)
|
)
|
||||||
if release_notes and "not authenticode-signed" not in release_notes.lower():
|
if release_notes and "not authenticode-signed" not in release_notes.lower():
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Stable v6.1.0 release_notes must disclose that Windows binaries are not Authenticode-signed."
|
f"Stable v{version} release_notes must disclose that Windows binaries are not Authenticode-signed."
|
||||||
)
|
)
|
||||||
elif unsigned_windows_reason:
|
elif unsigned_windows_reason:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
|
|
||||||
|
|
@ -171,12 +171,41 @@ class ResolveReleasePromotionTest(unittest.TestCase):
|
||||||
"Release owner accepted the Windows unknown-publisher warning for v6.1.0.",
|
"Release owner accepted the Windows unknown-publisher warning for v6.1.0.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_v611_owner_exception_allows_disclosed_emergency_patch(self) -> None:
|
||||||
|
metadata = resolver.resolve_metadata(
|
||||||
|
version="6.1.1",
|
||||||
|
promoted_from_tag_input="",
|
||||||
|
rollback_version_input="v6.1.0",
|
||||||
|
ga_date_input="",
|
||||||
|
v5_eos_date_input="",
|
||||||
|
hotfix_exception=True,
|
||||||
|
hotfix_reason_input="Active customer update harm.",
|
||||||
|
release_notes_input=(
|
||||||
|
"Windows Unified Agent binaries are not Authenticode-signed for v6.1.1."
|
||||||
|
),
|
||||||
|
unsigned_windows_exception=True,
|
||||||
|
unsigned_windows_reason_input=(
|
||||||
|
"Release owner accepted the Windows unknown-publisher warning for v6.1.1."
|
||||||
|
),
|
||||||
|
list_stable_tags_fn=lambda: ["v6.1.0", "v6.0.5"],
|
||||||
|
list_same_version_rc_tags_fn=lambda version: [],
|
||||||
|
changed_paths_fn=lambda tag: ["install.sh"],
|
||||||
|
tag_exists_fn=lambda tag: tag == "v6.1.0",
|
||||||
|
tag_commit_fn=lambda tag: "v610-commit",
|
||||||
|
head_descends_from_fn=lambda commit: commit == "v610-commit",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(metadata["promotion_mode"], "emergency-stable-patch")
|
||||||
|
self.assertEqual(metadata["rollback_tag"], "v6.1.0")
|
||||||
|
self.assertEqual(metadata["require_windows_signing"], "false")
|
||||||
|
self.assertEqual(metadata["unsigned_windows_exception"], "true")
|
||||||
|
|
||||||
def test_unsigned_windows_exception_is_rejected_for_other_stable_versions(self) -> None:
|
def test_unsigned_windows_exception_is_rejected_for_other_stable_versions(self) -> None:
|
||||||
with self.assertRaisesRegex(ValueError, "approved only for stable v6.1.0"):
|
with self.assertRaisesRegex(ValueError, "approved only for stable v6.1.0 or v6.1.1"):
|
||||||
resolver.resolve_metadata(
|
resolver.resolve_metadata(
|
||||||
version="6.1.1",
|
version="6.1.2",
|
||||||
promoted_from_tag_input="",
|
promoted_from_tag_input="",
|
||||||
rollback_version_input="v6.1.0",
|
rollback_version_input="v6.1.1",
|
||||||
ga_date_input="",
|
ga_date_input="",
|
||||||
v5_eos_date_input="",
|
v5_eos_date_input="",
|
||||||
hotfix_exception=True,
|
hotfix_exception=True,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ VERSION=""
|
||||||
MOBILE_RELEASE_DECISION=""
|
MOBILE_RELEASE_DECISION=""
|
||||||
MOBILE_RELEASE_EVIDENCE=""
|
MOBILE_RELEASE_EVIDENCE=""
|
||||||
HOTFIX_REASON=""
|
HOTFIX_REASON=""
|
||||||
|
UNSIGNED_WINDOWS_REASON=""
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
|
|
@ -20,6 +21,8 @@ Options:
|
||||||
--mobile-release-decision VALUE Override the inferred mobile decision.
|
--mobile-release-decision VALUE Override the inferred mobile decision.
|
||||||
--mobile-release-evidence VALUE Evidence for a mobile compatibility decision.
|
--mobile-release-evidence VALUE Evidence for a mobile compatibility decision.
|
||||||
--emergency-hotfix-reason VALUE Bypass an RC-required risk with an explicit reason.
|
--emergency-hotfix-reason VALUE Bypass an RC-required risk with an explicit reason.
|
||||||
|
--unsigned-windows-exception-reason VALUE
|
||||||
|
Use an approved version-bound unsigned Windows exception.
|
||||||
-h, --help Show this help.
|
-h, --help Show this help.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
@ -42,6 +45,10 @@ while [ "$#" -gt 0 ]; do
|
||||||
HOTFIX_REASON="${2:?--emergency-hotfix-reason requires a value}"
|
HOTFIX_REASON="${2:?--emergency-hotfix-reason requires a value}"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--unsigned-windows-exception-reason)
|
||||||
|
UNSIGNED_WINDOWS_REASON="${2:?--unsigned-windows-exception-reason requires a value}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
usage
|
usage
|
||||||
exit 0
|
exit 0
|
||||||
|
|
@ -111,6 +118,14 @@ if [ -n "$HOTFIX_REASON" ]; then
|
||||||
HOTFIX_EXCEPTION="true"
|
HOTFIX_EXCEPTION="true"
|
||||||
RESOLVER_ARGS+=(--hotfix-exception --hotfix-reason "$HOTFIX_REASON")
|
RESOLVER_ARGS+=(--hotfix-exception --hotfix-reason "$HOTFIX_REASON")
|
||||||
fi
|
fi
|
||||||
|
UNSIGNED_WINDOWS_EXCEPTION="false"
|
||||||
|
if [ -n "$UNSIGNED_WINDOWS_REASON" ]; then
|
||||||
|
UNSIGNED_WINDOWS_EXCEPTION="true"
|
||||||
|
RESOLVER_ARGS+=(
|
||||||
|
--unsigned-windows-exception
|
||||||
|
--unsigned-windows-reason "$UNSIGNED_WINDOWS_REASON"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
PROMOTION_METADATA="$(python3 scripts/release_control/resolve_release_promotion.py "${RESOLVER_ARGS[@]}")"
|
PROMOTION_METADATA="$(python3 scripts/release_control/resolve_release_promotion.py "${RESOLVER_ARGS[@]}")"
|
||||||
ROLLBACK_TAG="$(awk -F= '$1 == "rollback_tag" {print $2}' <<<"$PROMOTION_METADATA")"
|
ROLLBACK_TAG="$(awk -F= '$1 == "rollback_tag" {print $2}' <<<"$PROMOTION_METADATA")"
|
||||||
|
|
@ -150,6 +165,8 @@ if [ "$MODE" = "dry-run" ]; then
|
||||||
--require v5_eos_date \
|
--require v5_eos_date \
|
||||||
--require hotfix_exception \
|
--require hotfix_exception \
|
||||||
--require hotfix_reason \
|
--require hotfix_reason \
|
||||||
|
--require unsigned_windows_exception \
|
||||||
|
--require unsigned_windows_reason \
|
||||||
--require note \
|
--require note \
|
||||||
--require mobile_release_decision \
|
--require mobile_release_decision \
|
||||||
--require mobile_release_evidence
|
--require mobile_release_evidence
|
||||||
|
|
@ -163,6 +180,8 @@ if [ "$MODE" = "dry-run" ]; then
|
||||||
-f v5_eos_date="" \
|
-f v5_eos_date="" \
|
||||||
-f hotfix_exception="$HOTFIX_EXCEPTION" \
|
-f hotfix_exception="$HOTFIX_EXCEPTION" \
|
||||||
-f hotfix_reason="$HOTFIX_REASON" \
|
-f hotfix_reason="$HOTFIX_REASON" \
|
||||||
|
-f unsigned_windows_exception="$UNSIGNED_WINDOWS_EXCEPTION" \
|
||||||
|
-f unsigned_windows_reason="$UNSIGNED_WINDOWS_REASON" \
|
||||||
-f note="Stable patch preflight for ${VERSION} at ${LOCAL_SHA}" \
|
-f note="Stable patch preflight for ${VERSION} at ${LOCAL_SHA}" \
|
||||||
-f mobile_release_decision="$MOBILE_RELEASE_DECISION" \
|
-f mobile_release_decision="$MOBILE_RELEASE_DECISION" \
|
||||||
-f mobile_release_evidence="$MOBILE_RELEASE_EVIDENCE"
|
-f mobile_release_evidence="$MOBILE_RELEASE_EVIDENCE"
|
||||||
|
|
@ -182,6 +201,8 @@ else
|
||||||
--require v5_eos_date \
|
--require v5_eos_date \
|
||||||
--require hotfix_exception \
|
--require hotfix_exception \
|
||||||
--require hotfix_reason \
|
--require hotfix_reason \
|
||||||
|
--require unsigned_windows_exception \
|
||||||
|
--require unsigned_windows_reason \
|
||||||
--require draft_only \
|
--require draft_only \
|
||||||
--require mobile_release_decision \
|
--require mobile_release_decision \
|
||||||
--require mobile_release_evidence
|
--require mobile_release_evidence
|
||||||
|
|
@ -195,6 +216,8 @@ else
|
||||||
--arg v5_eos_date "" \
|
--arg v5_eos_date "" \
|
||||||
--argjson hotfix_exception "$HOTFIX_EXCEPTION" \
|
--argjson hotfix_exception "$HOTFIX_EXCEPTION" \
|
||||||
--arg hotfix_reason "$HOTFIX_REASON" \
|
--arg hotfix_reason "$HOTFIX_REASON" \
|
||||||
|
--argjson unsigned_windows_exception "$UNSIGNED_WINDOWS_EXCEPTION" \
|
||||||
|
--arg unsigned_windows_reason "$UNSIGNED_WINDOWS_REASON" \
|
||||||
--argjson draft_only false \
|
--argjson draft_only false \
|
||||||
--arg mobile_release_decision "$MOBILE_RELEASE_DECISION" \
|
--arg mobile_release_decision "$MOBILE_RELEASE_DECISION" \
|
||||||
--arg mobile_release_evidence "$MOBILE_RELEASE_EVIDENCE" \
|
--arg mobile_release_evidence "$MOBILE_RELEASE_EVIDENCE" \
|
||||||
|
|
@ -207,6 +230,8 @@ else
|
||||||
v5_eos_date: $v5_eos_date,
|
v5_eos_date: $v5_eos_date,
|
||||||
hotfix_exception: $hotfix_exception,
|
hotfix_exception: $hotfix_exception,
|
||||||
hotfix_reason: $hotfix_reason,
|
hotfix_reason: $hotfix_reason,
|
||||||
|
unsigned_windows_exception: $unsigned_windows_exception,
|
||||||
|
unsigned_windows_reason: $unsigned_windows_reason,
|
||||||
draft_only: $draft_only,
|
draft_only: $draft_only,
|
||||||
mobile_release_decision: $mobile_release_decision,
|
mobile_release_decision: $mobile_release_decision,
|
||||||
mobile_release_evidence: $mobile_release_evidence
|
mobile_release_evidence: $mobile_release_evidence
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue