Release Checklist

Use this checklist before and after cutting a release from main.

Known recurring papercut: release-please’s PR needs a manual Cargo.lock sync

release-please’s Rust workspace plugin bumps Cargo.toml’s workspace.package.version and version.txt, but it does not run cargo update — every workspace member’s version entry in Cargo.lock still shows the old version, and CI’s --locked --frozen --offline gates (Rust Build + Tests, Dependency Scan) correctly refuse to drift the lockfile silently and fail closed with cannot update the lock file ... because --frozen was passed.

Before merging a release-please PR, always run on that branch:

cargo update --workspace

Confirm the diff touches only the in-workspace package version entries (no external dependency version changes) before committing — a plain cargo update without --workspace scoping could otherwise pull in unrelated upstream bumps that don’t belong in a version-bump-only PR. Push the fix directly onto the release-please branch (it exists to be amended pre-merge); do not open a competing PR against it.

Note: release-please can force-push/regenerate this branch from scratch at any point while the PR stays open (observed: it did so once after another PR merged into main, then did not on a later main merge — the exact trigger isn’t “every push,” just “whenever it decides its release PR is out of date”), which drops any manually-pushed fixup commits (including this exact fix and this exact note). Re-verify both are still present immediately before merging — don’t assume a fix applied earlier in the PR’s life is still there just because it survived one prior push to main.

Before Tagging

  1. Confirm main branch protection matches the Rust-native required checks.

    make verify-branch-protection
    
  2. Run the local merge-equivalent gates.

    make verify-assurance
    make ci
    
  3. Exercise the checked-in release packaging path.

    make smoke-release
    make release-emulate
    
  4. Confirm the docs/download surface still builds and link-checks cleanly.

    make docs-check
    
  5. Confirm the security assurance report can be generated for the candidate.

    python3 scripts/security_assurance_gate.py \
      --json-out dist/security-assurance-report.json \
      --markdown-out dist/security-assurance-report.md
    
  6. If you are validating an already-published tag, verify the public release surface directly.

    make verify-published-release TAG=paranoid-passwd-v3.8.0
    

After Publishing

  1. Verify that the release workflow produced every expected CLI and GUI artifact plus checksums.txt, including Linux .deb packages, macOS GUI .dmg images, and the Windows GUI .msi.

  2. Verify that payload-layout validation passed for every archive, .dmg, Debian package, and MSI package, not just the host-runnable smoke artifacts.

  3. Verify there are no stale browser-era or otherwise unexpected assets attached to the release.

  4. Verify GitHub attestation for at least one downloaded artifact from each packaging family you ship.

  5. Confirm the release download verification matrix ran the Windows GUI MSI row on a Windows runner.

  6. Re-run installer validation against the published release surface if needed.

  7. Confirm Homebrew, Scoop, and Chocolatey manifests were generated and published through their PR flow.

  8. Do not describe artifacts as platform-signed unless the matching platform checks in Platform Installers and Signing passed for the published release.

  9. When validating a platform-signed release candidate, run the release validation path with PARANOID_RELEASE_SIGNING_MODE=signed on hosts that can verify the relevant platform signature.

  10. For macOS signed candidates, confirm the release workflow imported the Developer ID certificate and that scripts/macos_sign_notarize.sh signed/notarized both Paranoid Passwd.app and the GUI .dmg before publication.

  11. For Windows signed candidates, confirm the release workflow imported the signing certificate into the current-user certificate store, that scripts/windows_sign_artifact.sh signed the staged GUI executable before WiX packaging, and that it signed and verified the GUI .msi before publication.

Canary Expectations

The first release after a pipeline change should be treated as a canary:

  • inspect the archive matrix

  • inspect the Debian package set

  • inspect the macOS GUI .dmg set

  • inspect the Windows GUI .msi

  • verify the checksums

  • verify provenance

  • verify install.sh

  • confirm the docs download links resolve

  • confirm the public docs still describe unsigned artifacts as checksummed and attested, not as platform-signed

If any of those fail, treat the release pipeline as untrusted until the failure is fixed and the validation path passes again.