Every KC release zip is paired with two sidecar files:
KitsuneCommand-vX.Y.Z.zip.sha256— BSD-style sha256 sum lineKitsuneCommand-vX.Y.Z.zip.minisig— minisign Ed25519 signature
Together they let a downloader verify the zip is byte-identical to what GitHub Actions built (sha256) and signed by the KC maintainer (minisign).
This document covers both sides:
- For end users — how to verify a release before extracting
- For the maintainer — one-time setup + ongoing release process
You'll need minisign installed (single small binary; package-manager available on every platform).
# Download all three from the GitHub release page:
# KitsuneCommand-vX.Y.Z.zip
# KitsuneCommand-vX.Y.Z.zip.sha256
# KitsuneCommand-vX.Y.Z.zip.minisig
# 1. Verify the SHA-256 — proves the bytes match what was published
sha256sum -c KitsuneCommand-vX.Y.Z.zip.sha256
# 2. Verify the signature — proves the zip was signed by the KC maintainer
minisign -Vm KitsuneCommand-vX.Y.Z.zip -P <PUBLIC-KEY-PLACEHOLDER>The public key is published in docs/RELEASES.md and on the GitHub release notes for the first release that shipped signed.
If minisign -V prints Signature and comment signature verified, you're good. If it prints anything else — don't extract the zip. Open an issue at the repo.
Why both? SHA-256 alone proves the zip you downloaded is the one GitHub stored — but anyone with write access to the release page (or a successful MITM in the rare case of an old TLS surprise) could swap both the zip and its sha256. The minisign signature, anchored to a key the maintainer holds offline, closes that gap.
You're reading this because you maintain KC and need to generate the signing keypair for the first time, or rotate it.
| Platform | Install |
|---|---|
| Linux (Debian/Ubuntu) | sudo apt install minisign |
| Linux (Fedora/RHEL) | sudo dnf install minisign |
| macOS | brew install minisign |
| Windows (Chocolatey) | choco install minisign -y |
| Windows (Scoop) | scoop install minisign |
| Manual | Download from jedisct1/minisign releases — single ~150 KB binary, drop in PATH |
Confirm with minisign -v.
# Linux/macOS/Git Bash
bash tools/setup-signing-key.sh# Windows native PowerShell
tools\setup-signing-key.ps1The script:
- Refuses to overwrite an existing key (pass
-f/-Forceif you've lost the password and need a new one — but read key rotation first) - Calls
minisign -Gwhich prompts twice for a password - Saves
kc-minisign.pub+kc-minisign.keyunder~/.keys/ - Prints the public key contents and the next-step checklist
The password has no recovery path. Type it into your password manager before you confirm it in minisign.
The script prints the public key contents. Paste them into docs/RELEASES.md under the Verifying a release section, replacing the <PUBLIC-KEY-PLACEHOLDER> marker. Commit the change.
Put both in a password manager (1Password, KeePass, Bitwarden, etc.):
- File:
~/.keys/kc-minisign.key— paste the contents into a secure note. The file is small (~280 bytes), and it's encrypted with your password, but treat both as a single unit. - Password: the one you just typed.
~/.keys/ is in .gitignore — the key file will never land in the repo by accident. But you can also delete the local copy after backing it up. Future signings happen via the GitHub Actions secrets (next step), so you don't need the file on your laptop except for emergencies.
The release workflow signs each release zip in CI. It needs the private key + password as secrets:
- Open https://github.com/Kitsune-Den/KitsuneCommand/settings/secrets/actions
- New repository secret
KC_MINISIGN_PRIVATE_KEY— paste the entire contents of~/.keys/kc-minisign.key, including the leadinguntrusted comment:lines - New repository secret
KC_MINISIGN_PRIVATE_KEY_PASSWORD— the password
The CI workflow uses these temporarily (writes the key to a temp file, signs, deletes the temp file). They never appear in logs because GitHub redacts secret values automatically.
# From main, with all today's commits, after a version bump + CHANGELOG update:
git tag -a v2.7.2 -m "v2.7.2 — first signed release"
git push origin v2.7.2GitHub Actions runs the release workflow. When it finishes you'll see a draft release with three assets:
KitsuneCommand-v2.7.2.zipKitsuneCommand-v2.7.2.zip.sha256KitsuneCommand-v2.7.2.zip.minisig
Verify locally before publishing the draft:
minisign -Vm KitsuneCommand-v2.7.2.zip -P <your-public-key>If the signature verifies, hit Publish on the draft release.
If you need to change the keypair — lost password, suspected compromise, or just rotating periodically — the steps are:
- Generate a new keypair:
bash tools/setup-signing-key.sh -f(or-Forceon PowerShell). Overwrites the local copy. Old keypair stays in your password manager backup but isn't usable for new signings. - Update
docs/RELEASES.mdwith the new public key. Add a note about when the rotation happened — old releases stay verifiable with the old public key, new ones use the new one. - Update the GitHub secrets — both
KC_MINISIGN_PRIVATE_KEYandKC_MINISIGN_PRIVATE_KEY_PASSWORDget replaced. - Document in the release notes for the first release on the new key.
Older releases stay verifiable against the old public key (which lives forever in docs/RELEASES.md's history). New releases verify against the new key. Both states are normal.
| Symptom | Cause | Fix |
|---|---|---|
[sign-release] Skipping minisign signature: no private key in CI logs |
Secrets not set | Step 5 above |
Wrong password from minisign |
Password mismatch | Re-set KC_MINISIGN_PRIVATE_KEY_PASSWORD. If you lost the password, see key rotation |
WARNING: key file does NOT start with 'untrusted comment:' in CI logs |
KC_MINISIGN_PRIVATE_KEY secret was pasted incompletely — only the base64 body, not the full file contents |
Open ~/.keys/kc-minisign.key in a text editor, copy both lines (the untrusted comment: ... header AND the base64 body), paste both as the secret value |
<tempfile>: No error and minisign exited 2 |
Older symptom of the same issue above — pre-hardening sign-release.ps1 didn't print the header check | After this PR merges, the WARNING above should appear instead; re-set the secret with both lines |
Signature didn't verify on the downloader's side |
Zip was modified post-signing | Re-download. If it persists, open an issue. Don't extract the zip. |
bash: minisign: command not found locally |
minisign not installed | Step 1 |
Three reasons:
- Project consistency. The PackRelay launcher already uses minisign for its updater signatures (Tauri's update system is built on minisign internally). One signing primitive across the product family is easier to reason about.
- Smaller surface area. GPG has a long footgun list (key servers, web of trust, subkeys, expirations). minisign has one keypair, one password, one signature. Less to misconfigure.
- Lighter install on the verifier side. A KC server admin verifying a download on Windows can install minisign with one command. GPG on Windows requires Gpg4win which is significantly heavier.
If you need to verify on a system that already has gpg and you don't want to install minisign, you can still use the .sha256 file alone — it's the integrity floor. The minisig adds authenticity on top.