feat(release): publish latest.json for Tauri auto-updater on production

The updater was wired client-side (prepareTauriConfig.js sets
plugins.updater.endpoints to
https://github.com/tinyhumansai/openhuman/releases/latest/download/latest.json
and embeds UPDATER_PUBLIC_KEY) but the manifest itself was never
generated after we moved off tauri-action — so installed apps would
fetch 404 and believe they were up to date forever.

Add scripts/release/publish-updater-manifest.sh which:
- Lists the release's assets via gh CLI
- Finds the updater bundles produced by createUpdaterArtifacts=true
  (.app.tar.gz for macOS, .AppImage.tar.gz for Linux, -setup.nsis.zip
  for Windows) for each of darwin-aarch64 / darwin-x86_64 /
  linux-x86_64 / windows-x86_64
- Reads the matching .sig files (minisign base64 payloads)
- Composes latest.json per the Tauri v2 static-manifest schema with
  version, pub_date, notes, and a platforms map
- Uploads it to the release via gh release upload --clobber

Wired as a new production-only job `publish-updater-manifest` that runs
after the build-desktop matrix. publish-release now waits on it, and
the asset-validation step requires /^latest\.json$/ so releases can't
ship without the manifest. cleanup-failed-release also tears down
if the manifest step fails.

Staging builds are deliberately skipped — they shouldn't poison the
public updater endpoint.
This commit is contained in:
Steven Enamakel
2026-04-17 21:12:47 -07:00
parent 8f4696bdfb
commit e98f537fb7
2 changed files with 188 additions and 3 deletions
+39 -3
View File
@@ -786,6 +786,37 @@ jobs:
# org.opencontainers.image.source=https://github.com/tinyhumansai/openhuman
# org.opencontainers.image.revision=${{ needs.prepare-release.outputs.sha }}
# =========================================================================
# Phase 3c: Generate and upload latest.json for the Tauri auto-updater.
# Runs after every platform has uploaded its updater artifact (.sig files
# from createUpdaterArtifacts) so the manifest can reference all four
# platform entries. Production-only — staging builds don't feed the public
# updater endpoint.
# =========================================================================
publish-updater-manifest:
name: Publish updater manifest (latest.json)
needs: [prepare-build, create-release, build-desktop]
if: >-
needs.prepare-build.outputs.release_enabled == 'true'
&& needs.build-desktop.result == 'success'
runs-on: ubuntu-latest
environment: Production
steps:
- name: Checkout build ref
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
- name: Generate and upload latest.json
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.prepare-build.outputs.tag }}
VERSION: ${{ needs.prepare-build.outputs.version }}
REPO: tinyhumansai/openhuman
run: bash scripts/release/publish-updater-manifest.sh
# =========================================================================
# Phase 4: Publish the draft release (waits for ALL build phases)
# =========================================================================
@@ -793,11 +824,12 @@ jobs:
name: Publish draft release
runs-on: ubuntu-latest
environment: Production
needs: [prepare-build, create-release, build-desktop, build-docker]
needs: [prepare-build, create-release, build-desktop, build-docker, publish-updater-manifest]
if: >-
needs.prepare-build.outputs.release_enabled == 'true'
&& needs.build-desktop.result == 'success'
&& needs.build-docker.result == 'success'
&& needs.publish-updater-manifest.result == 'success'
steps:
- name: Validate required installer assets exist
uses: actions/github-script@v7
@@ -819,6 +851,9 @@ jobs:
/OpenHuman_.*_amd64\.AppImage$/,
/OpenHuman_.*_amd64\.deb$/,
/(OpenHuman_.*_x64-setup\.exe$|OpenHuman_.*_x64.*\.msi$)/,
// Auto-updater manifest — without this, installed clients can't
// discover new releases via plugins.updater.endpoints.
/^latest\.json$/,
];
const missing = requiredPatterns.filter((pattern) => !names.some((name) => pattern.test(name)));
@@ -875,13 +910,14 @@ jobs:
name: Remove release and tag if build failed
runs-on: ubuntu-latest
environment: Production
needs: [prepare-build, create-release, build-desktop, build-docker]
needs: [prepare-build, create-release, build-desktop, build-docker, publish-updater-manifest]
if: >-
always()
&& needs.prepare-build.outputs.release_enabled == 'true'
&& needs.create-release.result == 'success'
&& (needs.build-desktop.result == 'failure' || needs.build-desktop.result == 'cancelled'
|| needs.build-docker.result == 'failure' || needs.build-docker.result == 'cancelled')
|| needs.build-docker.result == 'failure' || needs.build-docker.result == 'cancelled'
|| needs.publish-updater-manifest.result == 'failure' || needs.publish-updater-manifest.result == 'cancelled')
steps:
- name: Delete GitHub release
uses: actions/github-script@v7