[eric] release: every publish and download path names the public shell by literal, the release workflows publish with a shell-scoped token behind a fail-closed check, and a push runs only the Windows suite leg (ENG-516)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WFgFyiXdf8goqjeyckFLj8
This commit is contained in:
ciregenz
2026-09-08 00:23:06 -07:00
co-authored by Claude Fable 5.1
parent 62c8535967
commit cc5f0d9d22
15 changed files with 401 additions and 15 deletions
+2 -2
View File
@@ -32,7 +32,7 @@ jobs:
- name: download published x64 DMG
run: |
curl -sSL -o /tmp/x64.dmg "https://github.com/${{ github.repository }}/releases/latest/download/OpenSwarm-x64.dmg"
curl -sSL -o /tmp/x64.dmg "https://github.com/openswarm-ai/openswarm/releases/latest/download/OpenSwarm-x64.dmg"
ls -la /tmp/x64.dmg
hdiutil attach -nobrowse -readonly -mountpoint /tmp/oswmnt /tmp/x64.dmg
mkdir -p /tmp/oswapp
@@ -106,7 +106,7 @@ jobs:
- name: download published Setup.exe
shell: pwsh
run: |
curl.exe -sSL -o $env:TEMP\OpenSwarm-Setup-x64.exe "https://github.com/${{ github.repository }}/releases/latest/download/OpenSwarm-Setup-x64.exe"
curl.exe -sSL -o $env:TEMP\OpenSwarm-Setup-x64.exe "https://github.com/openswarm-ai/openswarm/releases/latest/download/OpenSwarm-Setup-x64.exe"
Get-Item $env:TEMP\OpenSwarm-Setup-x64.exe | Select-Object Name,Length
- name: silent install (Squirrel)
+5 -4
View File
@@ -9,9 +9,10 @@ name: Promotion gate (update feeds agree)
# missing or versions mismatch, this goes red so the bad release is caught
# before users auto-update into it.
# Release events fire in the repo that HOLDS the releases: the public shell (openswarm-ai/openswarm).
# The copy that answers them lives in release-shell/.github/workflows/promotion-gate.yml and is pushed
# by scripts/release/sync-shell.sh; this one is the by-hand form for the repo that builds.
on:
release:
types: [published, released, prereleased]
workflow_dispatch:
inputs:
tag:
@@ -44,7 +45,7 @@ jobs:
shell: bash
run: |
mkdir -p feeds
gh release download "${{ steps.tag.outputs.tag }}" --repo "${{ github.repository }}" \
gh release download "${{ steps.tag.outputs.tag }}" --repo openswarm-ai/openswarm \
-p 'latest*.yml' -D feeds || true
ls -la feeds
- name: Verify both feeds exist, agree, and resolve
@@ -53,4 +54,4 @@ jobs:
node scripts/release/verify-release.js \
--dir feeds \
--expect-version "${{ steps.tag.outputs.ver }}" \
--base-url "https://github.com/${{ github.repository }}/releases/download/${{ steps.tag.outputs.tag }}"
--base-url "https://github.com/openswarm-ai/openswarm/releases/download/${{ steps.tag.outputs.tag }}"
+10 -1
View File
@@ -99,13 +99,22 @@ jobs:
shell: bash
run: python3 -m pip install --upgrade castlabs-evs
- name: The release shell must be reachable with the release token
# Releases live in the public shell every installed updater polls (openswarm-ai/openswarm),
# never in the repo that builds them, and a workflow's own token cannot write outside its repo.
if: ${{ env.APPLE_ID != '' && (github.event_name == 'push' || github.event.inputs.publish == 'true') }}
shell: bash
env:
GH_TOKEN: ${{ secrets.RELEASE_SHELL_TOKEN }}
run: bash scripts/release/check-shell-token.sh
- name: Build app
# Skip (green) when Apple signing secrets aren't in CI: Mac ships via local
# publish.sh, so a secret-less CI run should no-op, not fail red.
if: ${{ env.APPLE_ID != '' }}
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.RELEASE_SHELL_TOKEN }}
GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.GOOGLE_OAUTH_CLIENT_ID }}
GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.GOOGLE_OAUTH_CLIENT_SECRET }}
run: |
+13 -2
View File
@@ -138,10 +138,19 @@ jobs:
"SIGNTOOL_PATH=$signtool" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
Write-Host "SIGNTOOL_PATH=$signtool"
- name: The release shell must be reachable with the release token
# Releases live in the public shell every installed updater polls (openswarm-ai/openswarm),
# never in the repo that builds them, and a workflow's own token cannot write outside its repo.
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true')
shell: bash
env:
GH_TOKEN: ${{ secrets.RELEASE_SHELL_TOKEN }}
run: bash scripts/release/check-shell-token.sh
- name: Build app
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.RELEASE_SHELL_TOKEN }}
GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.GOOGLE_OAUTH_CLIENT_ID }}
GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.GOOGLE_OAUTH_CLIENT_SECRET }}
run: |
@@ -206,7 +215,9 @@ jobs:
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true')
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.RELEASE_SHELL_TOKEN }}
# Every gh release call below lands in the shell, whatever repo this workflow runs in.
GH_REPO: openswarm-ai/openswarm
run: |
$ErrorActionPreference = 'Stop'
$version = (Get-Content electron/package.json | ConvertFrom-Json).version
+5 -2
View File
@@ -46,6 +46,8 @@ jobs:
- name: Download the shipped installer
env:
GH_TOKEN: ${{ github.token }}
# Draft releases sit in the public shell and are readable only with a token that can see it.
RELEASE_SHELL_TOKEN: ${{ secrets.RELEASE_SHELL_TOKEN }}
run: |
$exe = Join-Path $env:RUNNER_TEMP "OpenSwarm-Setup-x64.exe"
$runId = "${{ inputs.run_id }}"
@@ -68,14 +70,15 @@ jobs:
# "release not found" even though the assets are right there. Resolve it out of the full
# list and pull the asset by id, which works for drafts and published releases alike.
$tag = "${{ inputs.tag || 'v1.7.0' }}"
$rel = gh api "repos/$env:GITHUB_REPOSITORY/releases?per_page=50" | ConvertFrom-Json |
if ($env:RELEASE_SHELL_TOKEN) { $env:GH_TOKEN = $env:RELEASE_SHELL_TOKEN }
$rel = gh api "repos/openswarm-ai/openswarm/releases?per_page=50" | ConvertFrom-Json |
Where-Object { $_.tag_name -eq $tag } | Select-Object -First 1
if (-not $rel) { throw "no release (draft or published) tagged $tag" }
"release: $($rel.tag_name) draft=$($rel.draft)"
$asset = $rel.assets | Where-Object { $_.name -eq 'OpenSwarm-Setup-x64.exe' } | Select-Object -First 1
if (-not $asset) { throw "OpenSwarm-Setup-x64.exe is not attached to $tag" }
$exe = Join-Path $env:RUNNER_TEMP "OpenSwarm-Setup-x64.exe"
gh api -H "Accept: application/octet-stream" "repos/$env:GITHUB_REPOSITORY/releases/assets/$($asset.id)" > $exe
gh api -H "Accept: application/octet-stream" "repos/openswarm-ai/openswarm/releases/assets/$($asset.id)" > $exe
$size = (Get-Item $exe).Length
"installer: $size bytes (release says $($asset.size))"
if ($size -ne $asset.size) { throw "FAIL: download is truncated" }
+5 -1
View File
@@ -4,6 +4,10 @@ name: Suites on every OS
# CI ran a hermetic subset on Ubuntu. Users run a 2017 iMac, Intel Macs and Windows laptops, so the
# full suites run on the three hosted OSes. fail-fast is off and every suite runs even after a red
# one, so one run reports all nine verdicts.
#
# A private repo bills macOS minutes at ten times Linux; the two Mac legs ran 579 minutes in the
# fortnight before the move (5,790 billable against a 2,000-minute month), so a push runs the Windows
# leg, which no developer machine here can run, and a dispatch runs all three.
on:
workflow_dispatch:
push:
@@ -22,7 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [macos-latest, macos-15-intel, windows-latest]
os: ${{ github.event_name == 'push' && fromJSON('["windows-latest"]') || fromJSON('["macos-latest", "macos-15-intel", "windows-latest"]') }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
env: