feat: GitHub Pages apt repo with per-major-version dist tracks (#230)
Implements ADR-010: stable releases are now published to https://thegrandwazoo.github.io/freenas-proxmox/ in addition to Cloudsmith. Dist tracks: v3 main — v3.x releases (new installs) main main — v2.x only (backward-compat, never auto-promoted to v3) v2 main — v2.x alias (explicit pin) CI: new "Publish to GitHub Pages APT repo" step in the publish job runs on tagged stable releases. Downloads the built .deb, places it in pool/v{major}, regenerates Packages.gz and a GPG-signed InRelease for the relevant dist(s), and pushes to the gh-pages branch. Setup: scripts/setup-apt-signing-key.sh generates the GPG key pair and prints the exact `gh secret set` commands to run. Requires APT_SIGNING_KEY and APT_SIGNING_KEY_PASSPHRASE secrets to be added to the repo before the first tagged release. README updated to point new installs at GitHub Pages; Cloudsmith testing channel retained for beta builds. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1d0cbca537
commit
dfbb4f6c31
|
|
@ -292,6 +292,89 @@ jobs:
|
|||
release: any-version
|
||||
file: ${{ needs.build.outputs.transitional_deb_file }}
|
||||
|
||||
- name: Publish to GitHub Pages APT repo
|
||||
if: needs.build.outputs.is_release == 'true'
|
||||
env:
|
||||
APT_SIGNING_KEY: ${{ secrets.APT_SIGNING_KEY }}
|
||||
APT_SIGNING_KEY_PASSPHRASE: ${{ secrets.APT_SIGNING_KEY_PASSPHRASE }}
|
||||
GH_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
run: |
|
||||
# Abort clearly if signing key not configured
|
||||
if [[ -z "$APT_SIGNING_KEY" ]]; then
|
||||
echo "::error::APT_SIGNING_KEY secret is not set — run scripts/setup-apt-signing-key.sh and add the secret"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine major version from package version (e.g. 3.0.0-1 → 3)
|
||||
VERSION="${{ needs.build.outputs.version }}"
|
||||
MAJOR="${VERSION%%.*}"
|
||||
|
||||
# Import GPG signing key
|
||||
echo "$APT_SIGNING_KEY" | base64 -d | gpg --batch --import
|
||||
GPG_KEY_ID="$(gpg --list-secret-keys --with-colons 2>/dev/null \
|
||||
| awk -F: '/^sec/{print $5; exit}')"
|
||||
|
||||
# Checkout gh-pages branch into a temp directory
|
||||
PAGES_DIR="$(mktemp -d)"
|
||||
git clone --branch gh-pages \
|
||||
"https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" \
|
||||
"$PAGES_DIR"
|
||||
|
||||
# Add .deb files to the versioned pool directory
|
||||
mkdir -p "${PAGES_DIR}/pool/v${MAJOR}"
|
||||
cp "${{ needs.build.outputs.deb_file }}" "${PAGES_DIR}/pool/v${MAJOR}/"
|
||||
cp "${{ needs.build.outputs.transitional_deb_file }}" "${PAGES_DIR}/pool/v${MAJOR}/"
|
||||
|
||||
# Install apt tooling
|
||||
sudo apt-get install -y --no-install-recommends dpkg-dev apt-utils
|
||||
|
||||
# Determine which dists to update
|
||||
# v2.x: update v2, main (alias), and v2 (explicit)
|
||||
# v3.x and above: update only the versioned dist
|
||||
if [[ "$MAJOR" == "2" ]]; then
|
||||
DISTS="v2 main"
|
||||
else
|
||||
DISTS="v${MAJOR}"
|
||||
fi
|
||||
|
||||
for DIST in $DISTS; do
|
||||
mkdir -p "${PAGES_DIR}/dists/${DIST}/main/binary-all"
|
||||
|
||||
# Generate Packages file (paths relative to repo root)
|
||||
dpkg-scanpackages --multiversion "${PAGES_DIR}/pool/v${MAJOR}" \
|
||||
| sed "s|^Filename: ${PAGES_DIR}/||" \
|
||||
> "${PAGES_DIR}/dists/${DIST}/main/binary-all/Packages"
|
||||
gzip -kf "${PAGES_DIR}/dists/${DIST}/main/binary-all/Packages"
|
||||
|
||||
# Generate Release file
|
||||
apt-ftparchive \
|
||||
-o "APT::FTPArchive::Release::Origin=truenas-proxmox" \
|
||||
-o "APT::FTPArchive::Release::Label=truenas-proxmox" \
|
||||
-o "APT::FTPArchive::Release::Suite=${DIST}" \
|
||||
-o "APT::FTPArchive::Release::Codename=${DIST}" \
|
||||
-o "APT::FTPArchive::Release::Components=main" \
|
||||
-o "APT::FTPArchive::Release::Architectures=all" \
|
||||
release "${PAGES_DIR}/dists/${DIST}" \
|
||||
> "${PAGES_DIR}/dists/${DIST}/Release"
|
||||
|
||||
# Sign → InRelease
|
||||
gpg --batch --yes \
|
||||
--passphrase "${APT_SIGNING_KEY_PASSPHRASE}" \
|
||||
--default-key "${GPG_KEY_ID}" \
|
||||
--clearsign \
|
||||
-o "${PAGES_DIR}/dists/${DIST}/InRelease" \
|
||||
"${PAGES_DIR}/dists/${DIST}/Release"
|
||||
done
|
||||
|
||||
# Commit and push
|
||||
cd "$PAGES_DIR"
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add .
|
||||
git diff --staged --quiet || \
|
||||
git commit -m "apt: publish ${VERSION} to dist(s): ${DISTS}"
|
||||
git push
|
||||
|
||||
- name: Create draft GitHub Release
|
||||
if: needs.build.outputs.is_release == 'true'
|
||||
uses: softprops/action-gh-release@v3
|
||||
|
|
|
|||
59
README.md
59
README.md
|
|
@ -120,24 +120,51 @@ v3.0 is a fully API-driven custom storage plugin. No SSH keys required.
|
|||
|
||||
## Installation
|
||||
|
||||
### Stable Release
|
||||
|
||||
Add the repository and install:
|
||||
### Stable Release (v3.x)
|
||||
|
||||
```bash
|
||||
# Import the GPG key
|
||||
curl -fsSL https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox/gpg.284C106104A8CE6D.key \
|
||||
curl -fsSL https://thegrandwazoo.github.io/freenas-proxmox/public.gpg.key \
|
||||
| gpg --dearmor \
|
||||
| tee /usr/share/keyrings/ksatechnologies-truenas-proxmox-keyring.gpg > /dev/null
|
||||
| sudo tee /etc/apt/keyrings/truenas-proxmox.gpg > /dev/null
|
||||
|
||||
# Add the repository
|
||||
cat > /etc/apt/sources.list.d/ksatechnologies-repo.list << 'EOF'
|
||||
deb [signed-by=/usr/share/keyrings/ksatechnologies-truenas-proxmox-keyring.gpg] \
|
||||
https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox/deb/debian any-version main
|
||||
EOF
|
||||
# Add the v3 repository track
|
||||
echo "deb [signed-by=/etc/apt/keyrings/truenas-proxmox.gpg] \
|
||||
https://thegrandwazoo.github.io/freenas-proxmox v3 main" \
|
||||
| sudo tee /etc/apt/sources.list.d/truenas-proxmox.list
|
||||
|
||||
# Install
|
||||
apt update && apt install truenas-proxmox
|
||||
sudo apt update && sudo apt install truenas-proxmox
|
||||
```
|
||||
|
||||
`apt upgrade` will deliver v3.x point releases automatically. You will never be
|
||||
automatically promoted to a future v4 — that requires changing the dist track in
|
||||
your `sources.list` to `v4`.
|
||||
|
||||
### Upgrading from v2.x
|
||||
|
||||
**v3.0 is a breaking change.** Do not run `apt upgrade` until you have read the
|
||||
migration guide — your storage configuration will need to be updated.
|
||||
|
||||
See [docs/migrating-from-v2.md](docs/migrating-from-v2.md).
|
||||
|
||||
### Staying on v2.x
|
||||
|
||||
If you are on v2.x and want to continue receiving v2.x point releases without
|
||||
risking a v3 upgrade, switch to the `main` dist track (v2.x only):
|
||||
|
||||
```bash
|
||||
# Import the GPG key (if not already done)
|
||||
curl -fsSL https://thegrandwazoo.github.io/freenas-proxmox/public.gpg.key \
|
||||
| gpg --dearmor \
|
||||
| sudo tee /etc/apt/keyrings/truenas-proxmox.gpg > /dev/null
|
||||
|
||||
# Add the v2 repository track
|
||||
echo "deb [signed-by=/etc/apt/keyrings/truenas-proxmox.gpg] \
|
||||
https://thegrandwazoo.github.io/freenas-proxmox main main" \
|
||||
| sudo tee /etc/apt/sources.list.d/truenas-proxmox.list
|
||||
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
### Testing / Beta Release
|
||||
|
|
@ -145,19 +172,17 @@ apt update && apt install truenas-proxmox
|
|||
For early access to new features (may be unstable):
|
||||
|
||||
```bash
|
||||
# Import the GPG key
|
||||
# Cloudsmith testing channel (beta builds from release/3.x branch)
|
||||
curl -fsSL https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox-testing/gpg.CACC9EE03F2DFFCC.key \
|
||||
| gpg --dearmor \
|
||||
| tee /usr/share/keyrings/ksatechnologies-truenas-proxmox-testing-keyring.gpg > /dev/null
|
||||
| sudo tee /usr/share/keyrings/ksatechnologies-truenas-proxmox-testing-keyring.gpg > /dev/null
|
||||
|
||||
# Add the repository
|
||||
cat > /etc/apt/sources.list.d/ksatechnologies-testing-repo.list << 'EOF'
|
||||
cat > /etc/apt/sources.list.d/truenas-proxmox-testing.list << 'EOF'
|
||||
deb [signed-by=/usr/share/keyrings/ksatechnologies-truenas-proxmox-testing-keyring.gpg] \
|
||||
https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox-testing/deb/debian any-version main
|
||||
EOF
|
||||
|
||||
# Install
|
||||
apt update && apt install truenas-proxmox
|
||||
sudo apt update && sudo apt install truenas-proxmox
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env bash
|
||||
# One-time setup: generate the GPG key used to sign the GitHub Pages apt repo.
|
||||
#
|
||||
# Run this locally once. After running:
|
||||
# 1. Commit public.gpg.key to the gh-pages branch (instructions printed below)
|
||||
# 2. Add APT_SIGNING_KEY to GitHub Actions secrets
|
||||
# 3. Add APT_SIGNING_KEY_PASSPHRASE to GitHub Actions secrets (empty string if no passphrase)
|
||||
#
|
||||
# Re-running is safe — it checks for an existing key first.
|
||||
set -euo pipefail
|
||||
|
||||
REPO="TheGrandWazoo/freenas-proxmox"
|
||||
KEY_NAME="truenas-proxmox"
|
||||
KEY_EMAIL="packages@ksatechnologies.com"
|
||||
KEY_COMMENT="truenas-proxmox apt repo signing key"
|
||||
|
||||
# ── Check for existing key ────────────────────────────────────────────────────
|
||||
EXISTING="$(gpg --list-secret-keys --with-colons 2>/dev/null \
|
||||
| awk -F: -v name="$KEY_NAME" '$1=="uid" && $10 ~ name {found=1} END {print found+0}')"
|
||||
|
||||
if [[ "$EXISTING" == "1" ]]; then
|
||||
echo "Key '$KEY_NAME' already exists in your keyring — skipping generation."
|
||||
KEY_ID="$(gpg --list-secret-keys --with-colons 2>/dev/null \
|
||||
| awk -F: '/^sec/{print $5; exit}')"
|
||||
else
|
||||
# ── Generate key ─────────────────────────────────────────────────────────────
|
||||
echo "Generating GPG key for apt repo signing..."
|
||||
read -r -s -p "Enter a passphrase (leave empty for no passphrase): " PASSPHRASE
|
||||
echo
|
||||
|
||||
gpg --batch --gen-key <<EOF
|
||||
%echo Generating truenas-proxmox apt signing key
|
||||
Key-Type: RSA
|
||||
Key-Length: 4096
|
||||
Subkey-Type: RSA
|
||||
Subkey-Length: 4096
|
||||
Name-Real: ${KEY_NAME}
|
||||
Name-Comment: ${KEY_COMMENT}
|
||||
Name-Email: ${KEY_EMAIL}
|
||||
Expire-Date: 0
|
||||
$([ -n "$PASSPHRASE" ] && echo "Passphrase: ${PASSPHRASE}" || echo "%no-protection")
|
||||
%commit
|
||||
%echo Done
|
||||
EOF
|
||||
|
||||
KEY_ID="$(gpg --list-secret-keys --with-colons 2>/dev/null \
|
||||
| awk -F: '/^sec/{print $5; exit}')"
|
||||
echo "Generated key: $KEY_ID"
|
||||
fi
|
||||
|
||||
# ── Export public key ─────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo "==> Exporting public key..."
|
||||
gpg --export --armor "$KEY_ID" > /tmp/truenas-proxmox-public.gpg.key
|
||||
echo "Public key written to /tmp/truenas-proxmox-public.gpg.key"
|
||||
|
||||
# ── Export private key (base64) ───────────────────────────────────────────────
|
||||
echo
|
||||
echo "==> Exporting private key (base64) for GitHub Actions secret..."
|
||||
PRIVATE_KEY_B64="$(gpg --export-secret-keys --armor "$KEY_ID" | base64 -w 0)"
|
||||
|
||||
# ── Instructions ─────────────────────────────────────────────────────────────
|
||||
cat <<INSTRUCTIONS
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
NEXT STEPS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1. Add APT_SIGNING_KEY to GitHub Actions secrets:
|
||||
gh secret set APT_SIGNING_KEY --repo ${REPO} --body "${PRIVATE_KEY_B64}"
|
||||
|
||||
2. Add APT_SIGNING_KEY_PASSPHRASE to GitHub Actions secrets:
|
||||
gh secret set APT_SIGNING_KEY_PASSPHRASE --repo ${REPO} --body "YOUR_PASSPHRASE"
|
||||
(use empty string if you chose no passphrase:)
|
||||
gh secret set APT_SIGNING_KEY_PASSPHRASE --repo ${REPO} --body ""
|
||||
|
||||
3. Commit public.gpg.key to the gh-pages branch:
|
||||
git checkout gh-pages
|
||||
cp /tmp/truenas-proxmox-public.gpg.key public.gpg.key
|
||||
git add public.gpg.key
|
||||
git commit -m "chore: add apt repo GPG public key"
|
||||
git push origin gh-pages
|
||||
git checkout release/3.x
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
INSTRUCTIONS
|
||||
Loading…
Reference in New Issue