Release #72
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-sdist: | |
| name: Build sdists | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| - name: Build review app frontend | |
| working-directory: web/review-app | |
| run: npm ci && npm run build | |
| - name: Build terminal app frontend | |
| working-directory: web/terminal-app | |
| run: npm ci && npm run build | |
| - name: Build markdown preview app frontend | |
| working-directory: web/markdown-app | |
| run: npm ci && npm run build | |
| - name: Build VNC app frontend | |
| working-directory: web/vnc-app | |
| run: npm ci && npm run build | |
| - name: Build config app frontend | |
| working-directory: web/config-app | |
| run: npm ci && npm run build | |
| - name: Build open-shrimp sdist | |
| run: uv build --sdist | |
| - name: Build moonshine-stt sdist | |
| working-directory: moonshine-stt | |
| run: uv build --sdist | |
| - name: Upload open-shrimp sdist | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: sdist-openshrimp | |
| path: dist/*.tar.gz | |
| - name: Upload moonshine-stt sdist | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: sdist-moonshine-stt | |
| path: moonshine-stt/dist/*.tar.gz | |
| build-binary: | |
| name: Build ${{ matrix.artifact }} | |
| needs: build-sdist | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # open-shrimp | |
| - os: ubuntu-latest | |
| artifact: openshrimp-linux-x86_64 | |
| sdist_artifact: sdist-openshrimp | |
| exec_code: "from open_shrimp.main import main; main()" | |
| features: "libvirt" | |
| - os: ubuntu-24.04-arm | |
| artifact: openshrimp-linux-aarch64 | |
| sdist_artifact: sdist-openshrimp | |
| exec_code: "from open_shrimp.main import main; main()" | |
| features: "libvirt" | |
| - os: macos-latest | |
| artifact: openshrimp-macos-aarch64 | |
| sdist_artifact: sdist-openshrimp | |
| exec_code: "from open_shrimp.main import main; main()" | |
| - os: macos-latest | |
| artifact: openshrimp-macos-x86_64 | |
| sdist_artifact: sdist-openshrimp | |
| exec_code: "from open_shrimp.main import main; main()" | |
| rust_target: x86_64-apple-darwin | |
| # moonshine-stt | |
| - os: ubuntu-latest | |
| artifact: moonshine-stt-linux-x86_64 | |
| sdist_artifact: sdist-moonshine-stt | |
| exec_code: "from moonshine_stt.main import main; main()" | |
| - os: ubuntu-24.04-arm | |
| artifact: moonshine-stt-linux-aarch64 | |
| sdist_artifact: sdist-moonshine-stt | |
| exec_code: "from moonshine_stt.main import main; main()" | |
| - os: macos-latest | |
| artifact: moonshine-stt-macos-aarch64 | |
| sdist_artifact: sdist-moonshine-stt | |
| exec_code: "from moonshine_stt.main import main; main()" | |
| - os: macos-latest | |
| artifact: moonshine-stt-macos-x86_64 | |
| sdist_artifact: sdist-moonshine-stt | |
| exec_code: "from moonshine_stt.main import main; main()" | |
| rust_target: x86_64-apple-darwin | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Download sdist | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: ${{ matrix.sdist_artifact }} | |
| path: dist | |
| - name: Install libvirt development headers | |
| if: matrix.features && contains(matrix.features, 'libvirt') | |
| run: sudo apt-get update && sudo apt-get install -y libvirt-dev | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.rust_target || '' }} | |
| - name: Cache Cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| key: ${{ runner.os }}-cargo-pyapp-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: ${{ runner.os }}-cargo-pyapp- | |
| - name: Get sdist filename | |
| id: sdist | |
| run: echo "filename=$(realpath dist/*.tar.gz)" >> "$GITHUB_OUTPUT" | |
| - name: Build with PyApp | |
| env: | |
| PYAPP_PROJECT_PATH: ${{ steps.sdist.outputs.filename }} | |
| PYAPP_PROJECT_FEATURES: ${{ matrix.features || '' }} | |
| PYAPP_PYTHON_VERSION: "3.11" | |
| PYAPP_EXEC_CODE: ${{ matrix.exec_code }} | |
| PYAPP_DISTRIBUTION_EMBED: "1" | |
| PYAPP_PASS_LOCATION: "1" | |
| run: | | |
| if [ -n "${{ matrix.rust_target }}" ]; then | |
| cargo install pyapp --force --root dist/pyapp --target ${{ matrix.rust_target }} | |
| else | |
| cargo install pyapp --force --root dist/pyapp | |
| fi | |
| - name: Rename binary | |
| run: mv dist/pyapp/bin/pyapp dist/${{ matrix.artifact }} | |
| - name: Import signing certificate | |
| if: runner.os == 'macOS' | |
| env: | |
| CERT_B64: ${{ secrets.MACOS_CERTIFICATE_P12_BASE64 }} | |
| CERT_PW: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| KC_PW: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} | |
| run: | | |
| KC="$RUNNER_TEMP/build.keychain-db" | |
| echo -n "$CERT_B64" | base64 --decode -o "$RUNNER_TEMP/cert.p12" | |
| security create-keychain -p "$KC_PW" "$KC" | |
| security set-keychain-settings -lut 21600 "$KC" | |
| security unlock-keychain -p "$KC_PW" "$KC" | |
| security import "$RUNNER_TEMP/cert.p12" -k "$KC" -P "$CERT_PW" \ | |
| -T /usr/bin/codesign -T /usr/bin/security | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KC_PW" "$KC" | |
| security list-keychains -d user -s "$KC" $(security list-keychains -d user | tr -d '"') | |
| rm "$RUNNER_TEMP/cert.p12" | |
| - name: Sign and notarize binary | |
| if: runner.os == 'macOS' | |
| env: | |
| IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }} | |
| API_KEY_B64: ${{ secrets.MACOS_NOTARY_API_KEY_P8_BASE64 }} | |
| API_KEY_ID: ${{ secrets.MACOS_NOTARY_API_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_API_ISSUER_ID }} | |
| run: | | |
| set -e | |
| BIN="dist/${{ matrix.artifact }}" | |
| codesign --force --timestamp --options runtime \ | |
| --entitlements entitlements.plist \ | |
| --sign "$IDENTITY" "$BIN" | |
| codesign --verify --strict --verbose=2 "$BIN" | |
| KEY="$RUNNER_TEMP/notary_key.p8" | |
| echo -n "$API_KEY_B64" | base64 --decode -o "$KEY" | |
| ZIP="$RUNNER_TEMP/${{ matrix.artifact }}.zip" | |
| ditto -c -k --keepParent "$BIN" "$ZIP" | |
| set +e | |
| SUBMIT_OUT=$(xcrun notarytool submit "$ZIP" \ | |
| --key "$KEY" --key-id "$API_KEY_ID" --issuer "$API_ISSUER_ID" \ | |
| --wait --timeout 30m 2>&1) | |
| SUBMIT_RC=$? | |
| echo "$SUBMIT_OUT" | |
| SUBMIT_ID=$(printf '%s\n' "$SUBMIT_OUT" | awk '/^[[:space:]]*id:/ {print $2; exit}') | |
| if [ "$SUBMIT_RC" -ne 0 ] || ! printf '%s\n' "$SUBMIT_OUT" | grep -q 'status: Accepted'; then | |
| if [ -n "$SUBMIT_ID" ]; then | |
| echo "::group::Notary log for $SUBMIT_ID" | |
| xcrun notarytool log "$SUBMIT_ID" \ | |
| --key "$KEY" --key-id "$API_KEY_ID" --issuer "$API_ISSUER_ID" || true | |
| echo "::endgroup::" | |
| fi | |
| rm -f "$ZIP" "$KEY" | |
| exit 1 | |
| fi | |
| # Single-file binaries can't be stapled; Gatekeeper checks online. | |
| rm "$ZIP" "$KEY" | |
| - name: Upload binary | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: dist/${{ matrix.artifact }} | |
| build-virtiofsd: | |
| name: Build virtiofsd (${{ matrix.arch }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| arch: x86_64 | |
| artifact: virtiofsd-linux-x86_64 | |
| - os: ubuntu-24.04-arm | |
| arch: aarch64 | |
| artifact: virtiofsd-linux-aarch64 | |
| steps: | |
| - name: Install system build dependencies | |
| run: sudo apt-get update && sudo apt-get install -y libseccomp-dev libcap-ng-dev | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache Cargo registry | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| key: ${{ runner.os }}-${{ runner.arch }}-cargo-virtiofsd-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: ${{ runner.os }}-${{ runner.arch }}-cargo-virtiofsd- | |
| - name: Clone virtiofsd | |
| run: git clone --depth 1 --branch v1.13.3 https://gitlab.com/virtio-fs/virtiofsd.git | |
| - name: Build virtiofsd | |
| working-directory: virtiofsd | |
| run: cargo build --release | |
| - name: Rename binary | |
| run: mv virtiofsd/target/release/virtiofsd ${{ matrix.artifact }} | |
| - name: Upload binary | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: ${{ matrix.artifact }} | |
| build-limactl: | |
| # Builds the bundled `limactl` from upstream Lima at the version | |
| # pinned by `patches/PIN`, with `patches/lima-vznc-display.patch` | |
| # applied. The patch attaches Apple's private `_VZVNCServer` SPI to | |
| # the running `VZVirtualMachine` so OpenShrimp can scrape the | |
| # framebuffer without a `limactl` GUI window. Output tarball name and | |
| # layout match upstream Lima releases so the runtime extractor in | |
| # `lima_helpers.py:_download_lima_sync` works unchanged. | |
| name: Build limactl (${{ matrix.uname_m }}) | |
| runs-on: macos-26 | |
| defaults: | |
| run: | |
| shell: bash -euo pipefail {0} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - goarch: arm64 | |
| uname_m: arm64 | |
| - goarch: amd64 | |
| uname_m: x86_64 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Read pinned LIMA_VERSION | |
| id: pin | |
| run: | | |
| PIN_VER=$(awk -F': *' '$1 == "tag" {sub(/^v/, "", $2); print $2}' patches/PIN) | |
| if [ -z "$PIN_VER" ]; then | |
| echo "::error::no 'tag:' line in patches/PIN" | |
| exit 1 | |
| fi | |
| PY_VER=$(awk -F'"' '/^LIMA_VERSION/ {print $2}' \ | |
| src/open_shrimp/sandbox/lima_helpers.py) | |
| if [ "$PIN_VER" != "$PY_VER" ]; then | |
| echo "::error::LIMA_VERSION skew: patches/PIN says v$PIN_VER but lima_helpers.py says $PY_VER" | |
| exit 1 | |
| fi | |
| echo "version=$PIN_VER" >> "$GITHUB_OUTPUT" | |
| - name: Clone Lima at v${{ steps.pin.outputs.version }} | |
| run: | | |
| git clone --depth 1 \ | |
| --branch v${{ steps.pin.outputs.version }} \ | |
| https://github.com/lima-vm/lima.git lima-src | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: stable | |
| - name: Cache Go modules | |
| # Must run after `git clone lima-src` so hashFiles('lima-src/go.sum') | |
| # actually hashes a file — otherwise the cache key would not | |
| # invalidate on a Lima version bump. | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/go/pkg/mod | |
| ~/Library/Caches/go-build | |
| key: ${{ runner.os }}-${{ matrix.goarch }}-go-limactl-${{ hashFiles('lima-src/go.sum', 'patches/lima-vznc-display.patch', 'vznc/go.mod') }} | |
| restore-keys: ${{ runner.os }}-${{ matrix.goarch }}-go-limactl- | |
| - name: Apply OpenShrimp patch | |
| run: | | |
| cd lima-src | |
| git apply ../patches/lima-vznc-display.patch | |
| # The patch's `replace` line uses `../../vznc`, valid for the dev | |
| # checkout layout but not for the CI workspace. Rewrite it. | |
| go mod edit -replace=github.com/openshrimp/vznc=${GITHUB_WORKSPACE}/vznc | |
| - name: Build binaries (${{ matrix.goarch }}) | |
| working-directory: lima-src | |
| env: | |
| GOOS: darwin | |
| GOARCH: ${{ matrix.goarch }} | |
| CGO_ENABLED: "1" | |
| # Lima's Makefile pulls VERSION from `git describe`. The shallow | |
| # clone above drops tag annotations, so pass it explicitly. | |
| run: make VERSION=v${{ steps.pin.outputs.version }} binaries | |
| - name: Build manpages (host arch only) | |
| # Lima's manpage build runs the just-built limactl binary, so it | |
| # only works on the host arch (macos-26 = arm64). The amd64 | |
| # tarball ships without manpages — the runtime extractor doesn't | |
| # require them. | |
| if: matrix.goarch == 'arm64' | |
| working-directory: lima-src | |
| env: | |
| GOOS: darwin | |
| GOARCH: ${{ matrix.goarch }} | |
| CGO_ENABLED: "1" | |
| run: make VERSION=v${{ steps.pin.outputs.version }} manpages | |
| - name: Verify Code-Hex/vz field-layout test | |
| # Native arch only: the cross-built amd64 binary can't execute | |
| # on the arm64 host. The test reads struct layout via reflect, | |
| # so running it natively is sufficient coverage. | |
| if: matrix.goarch == 'arm64' | |
| working-directory: lima-src | |
| run: go test -run TestVZVMReflectedFields ./pkg/driver/vz/... | |
| - name: Import signing certificate | |
| env: | |
| CERT_B64: ${{ secrets.MACOS_CERTIFICATE_P12_BASE64 }} | |
| CERT_PW: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| KC_PW: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} | |
| run: | | |
| KC="$RUNNER_TEMP/build.keychain-db" | |
| echo -n "$CERT_B64" | base64 --decode -o "$RUNNER_TEMP/cert.p12" | |
| security create-keychain -p "$KC_PW" "$KC" | |
| security set-keychain-settings -lut 21600 "$KC" | |
| security unlock-keychain -p "$KC_PW" "$KC" | |
| security import "$RUNNER_TEMP/cert.p12" -k "$KC" -P "$CERT_PW" \ | |
| -T /usr/bin/codesign -T /usr/bin/security | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KC_PW" "$KC" | |
| security list-keychains -d user -s "$KC" $(security list-keychains -d user | tr -d '"') | |
| rm "$RUNNER_TEMP/cert.p12" | |
| - name: Sign and notarize limactl | |
| env: | |
| IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }} | |
| API_KEY_B64: ${{ secrets.MACOS_NOTARY_API_KEY_P8_BASE64 }} | |
| API_KEY_ID: ${{ secrets.MACOS_NOTARY_API_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_API_ISSUER_ID }} | |
| run: | | |
| BIN="lima-src/_output/bin/limactl" | |
| codesign --force --timestamp --options runtime \ | |
| --entitlements vznc/vznc.entitlements \ | |
| --sign "$IDENTITY" "$BIN" | |
| codesign --verify --strict --verbose=2 "$BIN" | |
| KEY="$RUNNER_TEMP/notary_key.p8" | |
| echo -n "$API_KEY_B64" | base64 --decode -o "$KEY" | |
| ZIP="$RUNNER_TEMP/limactl-${{ matrix.uname_m }}.zip" | |
| ditto -c -k --keepParent "$BIN" "$ZIP" | |
| set +e | |
| SUBMIT_OUT=$(xcrun notarytool submit "$ZIP" \ | |
| --key "$KEY" --key-id "$API_KEY_ID" --issuer "$API_ISSUER_ID" \ | |
| --wait --timeout 30m 2>&1) | |
| SUBMIT_RC=$? | |
| echo "$SUBMIT_OUT" | |
| SUBMIT_ID=$(printf '%s\n' "$SUBMIT_OUT" | awk '/^[[:space:]]*id:/ {print $2; exit}') | |
| if [ "$SUBMIT_RC" -ne 0 ] || ! printf '%s\n' "$SUBMIT_OUT" | grep -q 'status: Accepted'; then | |
| if [ -n "$SUBMIT_ID" ]; then | |
| echo "::group::Notary log for $SUBMIT_ID" | |
| xcrun notarytool log "$SUBMIT_ID" \ | |
| --key "$KEY" --key-id "$API_KEY_ID" --issuer "$API_ISSUER_ID" || true | |
| echo "::endgroup::" | |
| fi | |
| rm -f "$ZIP" "$KEY" | |
| exit 1 | |
| fi | |
| # Single-file binaries can't be stapled; Gatekeeper checks online. | |
| rm "$ZIP" "$KEY" | |
| - name: Build tarball | |
| working-directory: lima-src | |
| run: | | |
| mkdir -p _artifacts | |
| OUT="_artifacts/lima-${{ steps.pin.outputs.version }}-Darwin-${{ matrix.uname_m }}.tar.gz" | |
| tar -C _output --no-xattrs -czvf "$OUT" ./ | |
| - name: Smoke-test the binary | |
| # Native arch only — confirms codesigning didn't break the | |
| # binary and the entitlement load doesn't reject the helper. | |
| if: matrix.goarch == 'arm64' | |
| run: lima-src/_output/bin/limactl --version | |
| - name: Upload tarball | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: lima-darwin-${{ matrix.uname_m }} | |
| path: lima-src/_artifacts/lima-${{ steps.pin.outputs.version }}-Darwin-${{ matrix.uname_m }}.tar.gz | |
| build-macos-app: | |
| name: Build macOS .app | |
| needs: build-sdist | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| - name: Build review app frontend | |
| working-directory: web/review-app | |
| run: npm ci && npm run build | |
| - name: Build terminal app frontend | |
| working-directory: web/terminal-app | |
| run: npm ci && npm run build | |
| - name: Build markdown preview app frontend | |
| working-directory: web/markdown-app | |
| run: npm ci && npm run build | |
| - name: Build VNC app frontend | |
| working-directory: web/vnc-app | |
| run: npm ci && npm run build | |
| - name: Build config app frontend | |
| working-directory: web/config-app | |
| run: npm ci && npm run build | |
| - name: Install dependencies | |
| run: | | |
| uv pip install --system py2app setuptools | |
| uv pip install --system '.[macos]' | |
| - name: Build .app bundle | |
| run: | | |
| # ruamel is a PEP 420 namespace package (no __init__.py), which | |
| # py2app's imp.find_module cannot resolve. Add a stub so py2app | |
| # can locate the package. | |
| touch "$(python -c 'import ruamel; print(ruamel.__path__[0])')/__init__.py" | |
| mv pyproject.toml pyproject.toml.bak | |
| python setup_app.py py2app | |
| mv pyproject.toml.bak pyproject.toml | |
| - name: Import signing certificate | |
| env: | |
| CERT_B64: ${{ secrets.MACOS_CERTIFICATE_P12_BASE64 }} | |
| CERT_PW: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| KC_PW: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} | |
| run: | | |
| KC="$RUNNER_TEMP/build.keychain-db" | |
| echo -n "$CERT_B64" | base64 --decode -o "$RUNNER_TEMP/cert.p12" | |
| security create-keychain -p "$KC_PW" "$KC" | |
| security set-keychain-settings -lut 21600 "$KC" | |
| security unlock-keychain -p "$KC_PW" "$KC" | |
| security import "$RUNNER_TEMP/cert.p12" -k "$KC" -P "$CERT_PW" \ | |
| -T /usr/bin/codesign -T /usr/bin/security | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KC_PW" "$KC" | |
| security list-keychains -d user -s "$KC" $(security list-keychains -d user | tr -d '"') | |
| rm "$RUNNER_TEMP/cert.p12" | |
| - name: Sign .app bundle | |
| env: | |
| IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }} | |
| run: | | |
| set -e | |
| APP="dist/OpenShrimp.app" | |
| # Sign every Mach-O file inside the bundle. Extension-based matching | |
| # isn't enough for py2app (the embedded Python interpreter has no | |
| # suffix), so probe each file with `file`. | |
| find "$APP" -type f | while read -r f; do | |
| if file -b "$f" | grep -qE 'Mach-O|dynamically linked shared library'; then | |
| codesign --force --timestamp --options runtime \ | |
| --sign "$IDENTITY" "$f" | |
| fi | |
| done | |
| # Sign embedded bundles (frameworks, nested .app) deepest-first so | |
| # each enclosing CodeResources seal covers already-signed contents. | |
| find "$APP/Contents" -type d \( -name "*.framework" -o -name "*.app" \) | \ | |
| awk -F/ '{ print NF, $0 }' | sort -k1 -rn | cut -d' ' -f2- | \ | |
| while read -r b; do | |
| codesign --force --timestamp --options runtime \ | |
| --sign "$IDENTITY" "$b" | |
| done | |
| # Finally sign the outer bundle with entitlements. | |
| codesign --force --timestamp --options runtime \ | |
| --entitlements entitlements.plist \ | |
| --sign "$IDENTITY" "$APP" | |
| codesign --verify --strict --deep --verbose=2 "$APP" | |
| - name: Create DMG | |
| run: | | |
| brew install create-dmg | |
| create-dmg \ | |
| --volname "OpenShrimp" \ | |
| --window-size 600 400 \ | |
| --icon "OpenShrimp.app" 150 200 \ | |
| --app-drop-link 450 200 \ | |
| --no-internet-enable \ | |
| "dist/OpenShrimp-$(cat VERSION).dmg" \ | |
| "dist/OpenShrimp.app" | |
| - name: Sign, notarize, and staple DMG | |
| env: | |
| IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }} | |
| API_KEY_B64: ${{ secrets.MACOS_NOTARY_API_KEY_P8_BASE64 }} | |
| API_KEY_ID: ${{ secrets.MACOS_NOTARY_API_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_API_ISSUER_ID }} | |
| run: | | |
| set -e | |
| DMG="dist/OpenShrimp-$(cat VERSION).dmg" | |
| codesign --force --timestamp --sign "$IDENTITY" "$DMG" | |
| KEY="$RUNNER_TEMP/notary_key.p8" | |
| echo -n "$API_KEY_B64" | base64 --decode -o "$KEY" | |
| set +e | |
| SUBMIT_OUT=$(xcrun notarytool submit "$DMG" \ | |
| --key "$KEY" --key-id "$API_KEY_ID" --issuer "$API_ISSUER_ID" \ | |
| --wait --timeout 30m 2>&1) | |
| SUBMIT_RC=$? | |
| echo "$SUBMIT_OUT" | |
| SUBMIT_ID=$(printf '%s\n' "$SUBMIT_OUT" | awk '/^[[:space:]]*id:/ {print $2; exit}') | |
| if [ "$SUBMIT_RC" -ne 0 ] || ! printf '%s\n' "$SUBMIT_OUT" | grep -q 'status: Accepted'; then | |
| if [ -n "$SUBMIT_ID" ]; then | |
| echo "::group::Notary log for $SUBMIT_ID" | |
| xcrun notarytool log "$SUBMIT_ID" \ | |
| --key "$KEY" --key-id "$API_KEY_ID" --issuer "$API_ISSUER_ID" || true | |
| echo "::endgroup::" | |
| fi | |
| rm -f "$KEY" | |
| exit 1 | |
| fi | |
| rm "$KEY" | |
| xcrun stapler staple "$DMG" | |
| xcrun stapler validate "$DMG" | |
| - name: Upload DMG | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: OpenShrimp-macos-app | |
| path: dist/OpenShrimp-*.dmg | |
| release: | |
| name: Create GitHub Release | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: [build-binary, build-virtiofsd, build-limactl, build-macos-app] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: artifacts | |
| merge-multiple: true | |
| - name: Create release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| generate_release_notes: true | |
| files: | | |
| artifacts/openshrimp-* | |
| artifacts/moonshine-stt-* | |
| artifacts/virtiofsd-* | |
| artifacts/OpenShrimp-*.dmg | |
| artifacts/*.tar.gz |