mirror of
https://github.com/stablyai/orca.git
synced 2026-10-04 08:02:09 +00:00
* fix(ssh): launch the Windows relay outside sshd's job without WMI Win32-OpenSSH kills a session's job on close but allows breakaway. relay.js gains a one-shot launcher mode that starts the detached relay with CREATE_BREAKAWAY_FROM_JOB through the staged process-tree addon, so a standard user no longer needs a WMI Remote Enable grant. WMI stays as the fallback for a relay without the addon, and a refusal there is named. The Windows SSH-host lanes drop their WMI grant and assert the breakaway route and adoption. * fix(ssh): find runtime holds without WMI on a standard-user Windows host The store GC read held runtimes through Get-CimInstance Win32_Process, which WMI refuses to a standard user's SSH logon, so the pass kept every runtime. On a refusal it now reads this account's own process image paths through Get-Process. * build(relay): ship the Windows relay launcher addon in every desktop package macOS and Linux packages carried Windows relays without windows-process-tree.node, so a legacy-runtime relay they uploaded to a Windows SSH host could not launch outside sshd's job and fell back to WMI, which a standard user is refused. A reusable Windows job now compiles the x64 and arm64 addons once and uploads them; release-cut, release-mac-build, and the hourly/daily/adhoc mac builds download them before build:release and require both arches. Staging now rejects a binary with the wrong PE machine, the ReadProcessMemory import, or no spawnOutsideJob export, so a stale pre-launcher build cannot ship. * ci(ssh): run the Windows SSH-host lanes when the relay process-tree build scripts change The staging and gyp-rebuild scripts decide which windows-process-tree addon the relay ships, so a change to either must re-prove the Windows host cells. * test(ci): find the mac orcad-template download by artifact name The release mac job now also downloads the relay Windows process-tree addons, so the first download-artifact step is no longer the template's. --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
227 lines
9.5 KiB
YAML
227 lines
9.5 KiB
YAML
name: Release macOS Build
|
|
|
|
run-name: Mac release build ${{ inputs.tag }} (${{ inputs.release_run_id }})
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: Release tag whose draft should receive macOS artifacts
|
|
required: true
|
|
type: string
|
|
release_run_id:
|
|
description: release-cut workflow run that requested this build
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
# actions: read downloads the orcad template the parent release-cut run built.
|
|
actions: read
|
|
contents: write
|
|
|
|
concurrency:
|
|
group: release-mac-build-${{ inputs.tag }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
build-mac:
|
|
if: github.repository == 'stablyai/orca'
|
|
# Why: this workflow is outside the SignPath signing run, so Blacksmith
|
|
# cannot enter Windows artifact provenance while mac notarization gets the
|
|
# faster runner.
|
|
runs-on: blacksmith-6vcpu-macos-15
|
|
timeout-minutes: 60
|
|
# actions: read fetches the relay addons from the release-cut run.
|
|
permissions:
|
|
actions: read
|
|
contents: write
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=4096
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: refs/tags/${{ inputs.tag }}
|
|
|
|
- name: Restore draft-publish scripts from the workflow ref
|
|
env:
|
|
WORKFLOW_SHA: ${{ github.workflow_sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"
|
|
git checkout "$WORKFLOW_SHA" -- config/scripts/assert-github-release-is-draft.mjs
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/setup@v2
|
|
with:
|
|
install: false
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: package.json
|
|
cache: pnpm
|
|
cache-dependency-path: |
|
|
pnpm-lock.yaml
|
|
mobile/pnpm-lock.yaml
|
|
|
|
# Cache the Electron binary + electron-builder tool downloads (notarytool,
|
|
# winCodeSign, nsis, squirrel, AppImage). Saves ~30-90s per job, incl. mac.
|
|
- name: Cache electron-builder downloads
|
|
uses: actions/cache@v5
|
|
with:
|
|
path: |
|
|
~/Library/Caches/electron
|
|
~/Library/Caches/electron-builder
|
|
key: electron-builder-mac-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
electron-builder-mac-
|
|
|
|
# Why: pnpm install triggers electron's postinstall, which downloads the
|
|
# Electron binary from GitHub release assets. GitHub's download CDN
|
|
# occasionally returns 504s that fail the whole release. Retry on
|
|
# failure so transient network errors don't require a manual re-run.
|
|
# Why both CPUs: the mac config packages x64 and arm64 from this arm64
|
|
# runner, so the install must carry both variants of the native optional deps.
|
|
- name: Install dependencies
|
|
uses: nick-fields/retry@v4
|
|
with:
|
|
timeout_minutes: 10
|
|
max_attempts: 3
|
|
retry_wait_seconds: 30
|
|
command: pnpm install --frozen-lockfile --cpu=current,x64,arm64
|
|
|
|
# Why here: electron-builder's beforePack requires out/mobile-web, and the bundle
|
|
# build resolves React Native and Expo from mobile/node_modules.
|
|
- uses: ./.github/actions/install-mobile-dependencies
|
|
|
|
- name: Verify macOS signing environment
|
|
run: node config/scripts/verify-macos-release-env.mjs
|
|
env:
|
|
CSC_LINK: ${{ secrets.MAC_CERTS }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTS_PASSWORD }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
# Why: `plutil -lint` accepts duplicate plist keys, but `codesign`
|
|
# rejects duplicate entitlements after the expensive app build.
|
|
- name: Verify macOS entitlements
|
|
run: pnpm verify:macos-entitlements
|
|
|
|
# Why: telemetry's transport gate (`src/main/telemetry/client.ts:IS_OFFICIAL_BUILD`)
|
|
# requires the build identity to be the literal string `stable` or `rc`,
|
|
# substituted by electron-vite's `define` block at build time.
|
|
- name: Classify release tag for telemetry build identity
|
|
id: tag-classify
|
|
shell: bash
|
|
env:
|
|
TAG: ${{ inputs.tag }}
|
|
run: |
|
|
set -euo pipefail
|
|
# Why the optional trailing identifier: suffixed side-branch RCs
|
|
# (vX.Y.Z-rc.N.perf) are rc-channel prerelease builds — same telemetry
|
|
# identity as plain RCs.
|
|
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+(\.[0-9A-Za-z]+)?$ ]]; then
|
|
identity=rc
|
|
elif [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
identity=stable
|
|
else
|
|
echo "::error::Tag $TAG does not match stable or rc pattern; refusing to build official artifact"
|
|
exit 1
|
|
fi
|
|
echo "identity=$identity" >>"$GITHUB_OUTPUT"
|
|
echo "Classified $TAG as $identity"
|
|
|
|
# Only a Windows runner compiles these; release-cut's relay-windows-process-tree
|
|
# job built them from this tag before dispatching this workflow.
|
|
- name: Collect the Windows process-table addons for the relay
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
name: relay-windows-process-tree
|
|
path: .build/windows-process-tree
|
|
run-id: ${{ inputs.release_run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Build app
|
|
run: pnpm build:release
|
|
env:
|
|
# Why: Vite's web build crossed Node's default old-space ceiling on
|
|
# the macOS release runner, leaving v1.4.2-rc.8 as an incomplete draft.
|
|
NODE_OPTIONS: --max-old-space-size=4096
|
|
ORCA_BUILD_IDENTITY: ${{ steps.tag-classify.outputs.identity }}
|
|
ORCA_DIAGNOSTICS_TOKEN_URL: https://www.onorca.dev/diagnostics/token
|
|
ORCA_POSTHOG_WRITE_KEY: ${{ secrets.ORCA_POSTHOG_WRITE_KEY }}
|
|
# Fail the release rather than ship a relay that cannot launch outside
|
|
# sshd's job for a standard user on a Windows SSH host.
|
|
ORCA_REQUIRE_RELAY_NATIVE_ADDONS: x64,arm64
|
|
|
|
# Design D2: the parent release-cut run merged it from every node-server lane at this tag.
|
|
- name: Download the orcad deployment template from the release run
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
name: orcad-template
|
|
path: out/orcad-template
|
|
run-id: ${{ inputs.release_run_id }}
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Gate runtime file-watcher process isolation
|
|
run: |
|
|
# Why: #8212 is a native-process crash contract. Prove both the Node
|
|
# host and the exact Electron runtime survive SIGSEGV before packaging.
|
|
node config/scripts/runtime-file-watcher-fault-harness.mjs
|
|
ELECTRON_RUN_AS_NODE=1 pnpm exec electron config/scripts/runtime-file-watcher-fault-harness.mjs
|
|
|
|
- name: Gate SSH relay watcher process isolation
|
|
run: |
|
|
# Why: the remote native watcher shares a daemon with live PTYs.
|
|
# Kill only its child and require both PTY and watch recovery before packaging.
|
|
node config/scripts/relay-watcher-fault-harness.mjs
|
|
|
|
- name: Abort if the parent release-cut run was cancelled
|
|
# Why: this workflow is dispatched separately, so cancelling release-cut
|
|
# does not stop mac `--publish always`. A cancelled parent left v1.4.206
|
|
# public with only a partial mac upload.
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
PARENT_RUN: ${{ inputs.release_run_id }}
|
|
run: |
|
|
set -euo pipefail
|
|
conclusion="$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$PARENT_RUN" --jq '.conclusion // empty')"
|
|
if [[ "$conclusion" == "cancelled" || "$conclusion" == "failure" || "$conclusion" == "timed_out" ]]; then
|
|
echo "::error::Parent release-cut run $PARENT_RUN is $conclusion; refusing to publish mac artifacts."
|
|
exit 1
|
|
fi
|
|
|
|
- name: Publish release artifacts (macOS)
|
|
uses: nick-fields/retry@v4
|
|
with:
|
|
timeout_minutes: 45
|
|
max_attempts: 3
|
|
retry_wait_seconds: 30
|
|
command: node config/scripts/ensure-native-runtime.mjs --runtime=electron && ORCA_MAC_RELEASE=1 pnpm exec electron-builder --config config/electron-builder.config.cjs --mac --publish always -c.publish.releaseType=draft
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
ORCA_REQUIRE_ORCAD_TEMPLATE: '1'
|
|
CSC_LINK: ${{ secrets.MAC_CERTS }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTS_PASSWORD }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
- name: Verify release remains draft after artifact upload
|
|
# Why: re-draft immediately if electron-builder flipped the GitHub
|
|
# release public, then fail. Checking without restoring leaves
|
|
# /releases/latest serving a missing Windows exe.
|
|
shell: bash
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
TAG: ${{ inputs.tag }}
|
|
run: node config/scripts/assert-github-release-is-draft.mjs "${{ inputs.tag }}"
|
|
|
|
# Why post-publish for macOS: electron-builder packs and uploads in a
|
|
# single `--publish always` invocation, so there is no cheap insertion
|
|
# point between pack and upload without splitting those steps.
|
|
- name: Verify telemetry constants present in app.asar
|
|
run: node config/scripts/verify-telemetry-constants.mjs
|