Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions .agents/skills/release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,17 +465,17 @@ Before printing the summary, verify the draft release carries every expected ass
gh release view "v<VERSION>" --json assets --jq '.assets[].name' | sort
```

Expected asset set when `scope.desktop=true`:
Expected asset set when `scope.desktop=true` (releases are macOS-only right now;
Windows publishing is commented out in `release-core.yml`):
- `ADE-<version>-universal.dmg`
- `ADE-<version>-universal-mac.zip`
- `ADE-<version>-universal-mac.zip.blockmap`
- `latest-mac.yml`
- `ADE-<version>-win-x64.exe`
- `ADE-<version>-win-x64.exe.blockmap`
- `latest.yml`

If any macOS asset is missing → mac build or upload broke; re-inspect the `build-mac-release` job.
If any Windows asset is missing → `build-win-release` broke or its artifact upload failed; re-inspect that job. Do not flip the draft if Windows artifacts are missing — shipping an asymmetric desktop release will confuse electron-updater consumers on the missing platform.
These four are the complete set — the zip + blockmap + `latest-mac.yml` are what
electron-updater consumes for auto-update (macOS updates install from the zip,
not the DMG), so a release missing any of them silently bricks auto-update.
If any asset is missing → mac build or upload broke; re-inspect the `build-mac-release` job.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Then print a single final block and stop:

Expand All @@ -484,12 +484,17 @@ Release v<VERSION> — summary

- Changelog: https://www.ade-app.dev/docs/changelog/v<VERSION>
- Draft release: <gh release url> (still draft — flip manually)
- Desktop assets: mac=<present|MISSING>, windows=<present|MISSING>
- Desktop assets: mac=<present|MISSING>
- Workflow run: <gh run url> (conclusion: success)
- iOS TestFlight build <BUILD_NUMBER>: <VALID | processing | skipped>
- Beta group: <group name | n/a>

Next step: review the draft release, then `gh release edit v<VERSION> --draft=false` to publish.
Next steps:
1. Review the draft release, then `gh release edit v<VERSION> --draft=false` to publish.
2. Publishing automatically bumps the Homebrew tap (arul28/homebrew-ade) via the
`update-brew-tap.yml` workflow — verify with
`gh run list --workflow update-brew-tap.yml --limit 1` after publishing.
Manual fallback if that run fails: `scripts/update-brew-tap.sh v<VERSION>`.
```

If any phase ended in `blocked`, the summary says `BLOCKED` at the top with the failing phase and the command to resume.
Expand Down
232 changes: 125 additions & 107 deletions .github/workflows/release-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,74 +175,78 @@ jobs:
apps/desktop/release/latest-mac.yml
if-no-files-found: error

build-win-release:
needs:
- verify
- build-runtime-binaries
runs-on: windows-latest
concurrency:
group: release-${{ inputs.release_tag }}-win
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.target_ref }}
fetch-depth: 0

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: |
apps/desktop/package-lock.json
apps/ade-cli/package-lock.json

- name: Install desktop dependencies
run: cd apps/desktop && npm ci

- name: Install ADE CLI dependencies
run: cd apps/ade-cli && npm ci

- name: Download ADE runtime binaries
uses: actions/download-artifact@v4
with:
pattern: ade-runtime-*
path: apps/desktop/resources/runtime
merge-multiple: true

- name: Materialize ADE runtime resources
env:
ADE_RUNTIME_ARTIFACTS_DIR: ${{ github.workspace }}\apps\desktop\resources\runtime
run: cd apps/desktop && npm run materialize:runtime-resources

- name: Stamp release version
env:
ADE_RELEASE_TAG: ${{ inputs.release_tag }}
run: cd apps/desktop && npm run version:release

- name: Reset release output
shell: pwsh
run: |
Remove-Item -Recurse -Force apps/desktop/release, apps/desktop/.cache -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path apps/desktop/.cache | Out-Null

- name: Build and validate Windows release
env:
ELECTRON_CACHE: ${{ github.workspace }}\apps\desktop\.cache\electron
ELECTRON_BUILDER_CACHE: ${{ github.workspace }}\apps\desktop\.cache\electron-builder
CSC_LINK: ${{ ((secrets.WINDOWS_CSC_LINK || secrets.WIN_CSC_LINK) && (secrets.WINDOWS_CSC_KEY_PASSWORD || secrets.WIN_CSC_KEY_PASSWORD)) && (secrets.WINDOWS_CSC_LINK || secrets.WIN_CSC_LINK) || '' }}
CSC_KEY_PASSWORD: ${{ ((secrets.WINDOWS_CSC_LINK || secrets.WIN_CSC_LINK) && (secrets.WINDOWS_CSC_KEY_PASSWORD || secrets.WIN_CSC_KEY_PASSWORD)) && (secrets.WINDOWS_CSC_KEY_PASSWORD || secrets.WIN_CSC_KEY_PASSWORD) || '' }}
run: cd apps/desktop && npm run dist:win

- name: Upload validated Windows artifacts to workflow run
uses: actions/upload-artifact@v4
with:
name: ade-win-release-${{ inputs.release_tag }}
path: |
apps/desktop/release/*.exe
apps/desktop/release/*.exe.blockmap
apps/desktop/release/latest.yml
if-no-files-found: error
# Windows release builds are disabled for now — ADE ships macOS-only releases.
# To re-enable: uncomment this job, add `build-win-release` back to
# publish-release `needs`, and restore the win blocks in the publish job
# (artifact download, manifest validation, upload list).
# build-win-release:
# needs:
# - verify
# - build-runtime-binaries
# runs-on: windows-latest
# concurrency:
# group: release-${{ inputs.release_tag }}-win
# cancel-in-progress: true
# steps:
# - uses: actions/checkout@v4
# with:
# ref: ${{ inputs.target_ref }}
# fetch-depth: 0
#
# - uses: actions/setup-node@v4
# with:
# node-version: 22
# cache: npm
# cache-dependency-path: |
# apps/desktop/package-lock.json
# apps/ade-cli/package-lock.json
#
# - name: Install desktop dependencies
# run: cd apps/desktop && npm ci
#
# - name: Install ADE CLI dependencies
# run: cd apps/ade-cli && npm ci
#
# - name: Download ADE runtime binaries
# uses: actions/download-artifact@v4
# with:
# pattern: ade-runtime-*
# path: apps/desktop/resources/runtime
# merge-multiple: true
#
# - name: Materialize ADE runtime resources
# env:
# ADE_RUNTIME_ARTIFACTS_DIR: ${{ github.workspace }}\apps\desktop\resources\runtime
# run: cd apps/desktop && npm run materialize:runtime-resources
#
# - name: Stamp release version
# env:
# ADE_RELEASE_TAG: ${{ inputs.release_tag }}
# run: cd apps/desktop && npm run version:release
#
# - name: Reset release output
# shell: pwsh
# run: |
# Remove-Item -Recurse -Force apps/desktop/release, apps/desktop/.cache -ErrorAction SilentlyContinue
# New-Item -ItemType Directory -Path apps/desktop/.cache | Out-Null
#
# - name: Build and validate Windows release
# env:
# ELECTRON_CACHE: ${{ github.workspace }}\apps\desktop\.cache\electron
# ELECTRON_BUILDER_CACHE: ${{ github.workspace }}\apps\desktop\.cache\electron-builder
# CSC_LINK: ${{ ((secrets.WINDOWS_CSC_LINK || secrets.WIN_CSC_LINK) && (secrets.WINDOWS_CSC_KEY_PASSWORD || secrets.WIN_CSC_KEY_PASSWORD)) && (secrets.WINDOWS_CSC_LINK || secrets.WIN_CSC_LINK) || '' }}
# CSC_KEY_PASSWORD: ${{ ((secrets.WINDOWS_CSC_LINK || secrets.WIN_CSC_LINK) && (secrets.WINDOWS_CSC_KEY_PASSWORD || secrets.WIN_CSC_KEY_PASSWORD)) && (secrets.WINDOWS_CSC_KEY_PASSWORD || secrets.WIN_CSC_KEY_PASSWORD) || '' }}
# run: cd apps/desktop && npm run dist:win
#
# - name: Upload validated Windows artifacts to workflow run
# uses: actions/upload-artifact@v4
# with:
# name: ade-win-release-${{ inputs.release_tag }}
# path: |
# apps/desktop/release/*.exe
# apps/desktop/release/*.exe.blockmap
# apps/desktop/release/latest.yml
# if-no-files-found: error

build-runtime-binaries:
needs: verify
Expand Down Expand Up @@ -377,7 +381,6 @@ jobs:
needs:
- build-runtime-binaries
- build-mac-release
- build-win-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -391,23 +394,33 @@ jobs:
name: ade-mac-release-${{ inputs.release_tag }}
path: release-assets/mac

- name: Download Windows release artifacts
uses: actions/download-artifact@v4
with:
name: ade-win-release-${{ inputs.release_tag }}
path: release-assets/win

- name: Download ADE runtime binaries
uses: actions/download-artifact@v4
with:
pattern: ade-runtime-*
path: release-assets/runtime
merge-multiple: true

- name: Add standalone runtime installer
run: |
cp apps/ade-cli/scripts/install-runtime.sh release-assets/runtime/install.sh
chmod 755 release-assets/runtime/install.sh
# Windows artifacts and the standalone runtime assets (ade-* binaries,
# native tarballs, install.sh) are intentionally NOT published right now.
# The release surface is macOS-only and kept minimal: the DMG for humans,
# plus the zip + blockmap + latest-mac.yml that electron-updater requires
# for auto-update (macOS auto-update installs from the zip, NOT the DMG —
# removing those three assets silently bricks updates for every install).
# The runtime binaries are still BUILT above because the macOS app bundles
# them as sidecars (local brain + remote-runtime bootstrap payloads).
# To publish them again, restore the blocks below.
#
# - name: Download Windows release artifacts
# uses: actions/download-artifact@v4
# with:
# name: ade-win-release-${{ inputs.release_tag }}
# path: release-assets/win
#
# - name: Download ADE runtime binaries
# uses: actions/download-artifact@v4
# with:
# pattern: ade-runtime-*
# path: release-assets/runtime
# merge-multiple: true
#
# - name: Add standalone runtime installer
# run: |
# cp apps/ade-cli/scripts/install-runtime.sh release-assets/runtime/install.sh
# chmod 755 release-assets/runtime/install.sh

- name: Validate publish asset manifest
run: |
Expand Down Expand Up @@ -440,23 +453,26 @@ jobs:
require_glob 'release-assets/mac/*.zip' 'macOS zip'
require_glob 'release-assets/mac/*-mac.zip.blockmap' 'macOS blockmap'
require_file 'release-assets/mac/latest-mac.yml' 'macOS auto-update metadata'
require_glob 'release-assets/win/*.exe' 'Windows installer'
require_glob 'release-assets/win/*.exe.blockmap' 'Windows blockmap'
require_file 'release-assets/win/latest.yml' 'Windows auto-update metadata'
require_file 'release-assets/runtime/install.sh' 'standalone runtime installer'
if [ ! -x 'release-assets/runtime/install.sh' ]; then
echo "::error::Standalone runtime installer is not executable."
exit 1
fi

for target in darwin-arm64 darwin-x64 linux-arm64 linux-x64; do
require_file "release-assets/runtime/ade-$target" "ADE runtime binary for $target"
require_file "release-assets/runtime/ade-$target.native.tar.gz" "ADE native dependency archive for $target"
tar -tzf "release-assets/runtime/ade-$target.native.tar.gz" | grep -q '^\./node_modules/' || {
echo "::error::ADE native dependency archive for $target is missing node_modules."
exit 1
}
done
# Windows + standalone runtime assets are not published right now.
# Restore these checks together with the publish blocks above.
# require_glob 'release-assets/win/*.exe' 'Windows installer'
# require_glob 'release-assets/win/*.exe.blockmap' 'Windows blockmap'
# require_file 'release-assets/win/latest.yml' 'Windows auto-update metadata'
# require_file 'release-assets/runtime/install.sh' 'standalone runtime installer'
# if [ ! -x 'release-assets/runtime/install.sh' ]; then
# echo "::error::Standalone runtime installer is not executable."
# exit 1
# fi
#
# for target in darwin-arm64 darwin-x64 linux-arm64 linux-x64; do
# require_file "release-assets/runtime/ade-$target" "ADE runtime binary for $target"
# require_file "release-assets/runtime/ade-$target.native.tar.gz" "ADE native dependency archive for $target"
# tar -tzf "release-assets/runtime/ade-$target.native.tar.gz" | grep -q '^\./node_modules/' || {
# echo "::error::ADE native dependency archive for $target is missing node_modules."
# exit 1
# }
# done

- name: Create or update draft GitHub release
env:
Expand All @@ -466,16 +482,18 @@ jobs:
GH_REPO: ${{ github.repository }}
run: |
shopt -s nullglob
# macOS-only release surface. The zip + blockmap + latest-mac.yml are
# required by electron-updater; the DMG is the human download.
files=(
release-assets/mac/*.dmg
release-assets/mac/*.zip
release-assets/mac/*-mac.zip.blockmap
release-assets/mac/latest-mac.yml
release-assets/win/*.exe
release-assets/win/*.exe.blockmap
release-assets/win/latest.yml
release-assets/runtime/install.sh
release-assets/runtime/ade-*
# release-assets/win/*.exe
# release-assets/win/*.exe.blockmap
# release-assets/win/latest.yml
# release-assets/runtime/install.sh
# release-assets/runtime/ade-*
)

if [ "${#files[@]}" -eq 0 ]; then
Expand Down
74 changes: 74 additions & 0 deletions .github/workflows/update-brew-tap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Update brew tap

# Bumps the arul28/homebrew-ade cask (version + sha256) whenever a release is
# published, so `brew install --cask arul28/ade/ade` always serves the latest
# DMG. Fires on publish (not draft creation) because the cask download URL only
# resolves for published releases.
#
# Auth: HOMEBREW_TAP_DEPLOY_KEY repo secret — an SSH deploy key with write
# access on arul28/homebrew-ade. Manual fallback: scripts/update-brew-tap.sh.

on:
release:
types: [published]

permissions:
contents: read

jobs:
bump-cask:
if: ${{ !github.event.release.prerelease }}
runs-on: ubuntu-latest
steps:
- name: Resolve DMG asset digest
id: dmg
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG_NAME: ${{ github.event.release.tag_name }}
run: |
set -euo pipefail
version="${TAG_NAME#v}"
asset_name="ADE-$version-universal.dmg"
digest="$(gh api "repos/$GH_REPO/releases/tags/$TAG_NAME" \
--jq ".assets[] | select(.name == \"$asset_name\") | .digest // empty")"
case "$digest" in
sha256:*) sha="${digest#sha256:}" ;;
*)
echo "::error::No sha256 digest found for $asset_name on $TAG_NAME."
exit 1
;;
esac
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "sha=$sha" >> "$GITHUB_OUTPUT"

- name: Update cask in arul28/homebrew-ade
env:
DEPLOY_KEY: ${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }}
VERSION: ${{ steps.dmg.outputs.version }}
SHA256: ${{ steps.dmg.outputs.sha }}
run: |
set -euo pipefail
if [ -z "$DEPLOY_KEY" ]; then
echo "::error::Missing HOMEBREW_TAP_DEPLOY_KEY secret (write deploy key for arul28/homebrew-ade)."
exit 1
fi
mkdir -p ~/.ssh
printf '%s\n' "$DEPLOY_KEY" > ~/.ssh/tap_deploy_key
chmod 600 ~/.ssh/tap_deploy_key
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
export GIT_SSH_COMMAND="ssh -i ~/.ssh/tap_deploy_key -o IdentitiesOnly=yes"
Comment on lines +59 to +60

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pin GitHub's SSH host key before using the write deploy key.

This job currently trusts whatever ssh-keyscan returns at runtime, then uses that connection for a push-capable deploy key. A DNS/TCP MITM here can redirect or tamper with the tap update. Please switch to a pinned known_hosts entry and force strict host-key checking for this push path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/update-brew-tap.yml around lines 59 - 60, Replace the
runtime ssh-keyscan usage and permissive SSH behavior with a pinned GitHub host
key and strict host-key checking: add a committed/inline known_hosts entry for
GitHub (the specific public key fingerprint for github.com) into the job's
~/.ssh/known_hosts, ensure its permissions are correct, and set GIT_SSH_COMMAND
to include -i ~/.ssh/tap_deploy_key -o IdentitiesOnly=yes -o
UserKnownHostsFile=~/.ssh/known_hosts -o StrictHostKeyChecking=yes so pushes
using the tap_deploy_key fail if the host key does not match; update the
workflow step that currently runs ssh-keyscan and exports GIT_SSH_COMMAND
accordingly.


git clone -q --depth 1 git@github.com:arul28/homebrew-ade.git tap
cd tap
sed -i -E "s|^ version \".*\"$| version \"$VERSION\"|" Casks/ade.rb
sed -i -E "s|^ sha256 \".*\"$| sha256 \"$SHA256\"|" Casks/ade.rb
if git diff --quiet; then
echo "Cask already at ADE $VERSION — nothing to do."
exit 0
Comment thread
coderabbitai[bot] marked this conversation as resolved.
fi
git config user.name "ade-release-bot"
git config user.email "release-bot@users.noreply.github.com"
git commit -aqm "ade $VERSION"
git push -q origin HEAD:main
echo "Updated cask to ADE $VERSION (sha256 $SHA256)."
Loading