From c824d8d212a2d4acfdaf5e2141560d6e72acca8d Mon Sep 17 00:00:00 2001 From: sepehr-safari Date: Mon, 13 Jul 2026 00:28:35 +0300 Subject: [PATCH] feat(repo): one-line macOS installer (curl | bash) Add scripts/install-macos.sh: fetches the latest release DMG, verifies its SHA-256 against the release's SHA256SUMS, installs OCPP DebugKit Studio.app to /Applications, clears the download quarantine, and opens it. Guards for macOS + arm64 and fails loudly on a checksum mismatch. release.yml now publishes a SHA256SUMS asset (checksums of both packages). The README macOS install is collapsed to the one-liner; the manual download / xattr / notarization prose is removed. The installer goes live once a release carrying SHA256SUMS is published (v0.5.2). Verification is integrity against GitHub-over-TLS, not an independent signature. --- .github/workflows/release.yml | 2 + CHANGELOG.md | 12 ++++++ README.md | 23 +++++------- RELEASING.md | 15 ++++---- scripts/install-macos.sh | 69 +++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 21 deletions(-) create mode 100755 scripts/install-macos.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0958105..0fde53f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -84,6 +84,8 @@ jobs: with: path: dist merge-multiple: true + - name: Checksums + run: cd dist && sha256sum studio-* | tee SHA256SUMS - name: Publish GitHub release # ref_name / repository come in through the environment, never # interpolated into the script body, so a crafted tag can't inject shell. diff --git a/CHANGELOG.md b/CHANGELOG.md index 812ed57..0a64a69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,18 @@ reference are all pre-1.0, minor (0.x) releases may include breaking changes. ## [Unreleased] +### Added + +- **macOS one-line installer** — + `curl -fsSL https://raw.githubusercontent.com/ocpp-debugkit/studio/main/scripts/install-macos.sh | bash` + downloads the latest release, verifies its SHA-256, installs the app to + Applications, and opens it. Releases now publish a `SHA256SUMS` checksums asset. + +### Changed + +- The README macOS install is now the one-liner; the manual download / quarantine + instructions were removed. + ## [0.5.1] — 2026-07-12 ### Changed diff --git a/README.md b/README.md index a0c14bf..5275aeb 100644 --- a/README.md +++ b/README.md @@ -33,29 +33,24 @@ The two share **no code**. They meet only at a *conformance contract*: the same ## Install -Download the latest build for your platform from the -[**Releases**](https://github.com/ocpp-debugkit/studio/releases) page. - ### macOS (Apple silicon) -Open the `.dmg` and drag **OCPP DebugKit Studio** to Applications. The build is -**ad-hoc signed** (not notarized), so macOS quarantines the download and Gatekeeper -blocks the first launch. Clear it once with a single command: +Paste this into a terminal — it installs the latest **OCPP DebugKit Studio** into +Applications and opens it: ```sh -xattr -dr com.apple.quarantine "/Applications/OCPP DebugKit Studio.app" +curl -fsSL https://raw.githubusercontent.com/ocpp-debugkit/studio/main/scripts/install-macos.sh | bash ``` -Prefer not to use the Terminal? Double-click the app, and when macOS refuses, open -**System Settings → Privacy & Security** and click **Open Anyway**, then launch it -again. The ad-hoc signature is what lets the app run once unquarantined; -notarization — which would remove this step entirely — is a deliberate tradeoff -we've deferred. +The script downloads the latest release, verifies its SHA-256, installs the app, +and launches it — no toolchain, no manual steps. (Prefer to read it first? See +[`scripts/install-macos.sh`](scripts/install-macos.sh).) ### Linux -Extract the `.tar.gz` and run the `studio` binary. Requires GTK 4 (`libgtk-4`, -`libwebkitgtk-6.0`). +Download the `.tar.gz` from the +[**Releases**](https://github.com/ocpp-debugkit/studio/releases) page, extract it, +and run the `studio` binary. Requires GTK 4 (`libgtk-4`, `libwebkitgtk-6.0`). Studio is pre-1.0 (0.x) while Zig, the Native SDK, and the toolkit conformance reference are all pre-1.0 — see the [roadmap](ROADMAP.md). diff --git a/RELEASING.md b/RELEASING.md index 8839203..cee4d5c 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -13,13 +13,14 @@ which builds and publishes a GitHub release with two artifacts: | --- | --- | --- | | macOS | `studio-X.Y.Z-macos-ReleaseFast.dmg` | A `.app` bundle, **ad-hoc signed** | | Linux | `studio-X.Y.Z-linux-ReleaseFast.tar.gz` | The `studio` binary + resources | - -**macOS Gatekeeper:** the ad-hoc build is not notarized, so macOS quarantines the -download and blocks first launch. Users clear it once with -`xattr -dr com.apple.quarantine "/Applications/OCPP DebugKit Studio.app"` (or -*System Settings → Privacy & Security → Open Anyway*) — see the README. This is a -deliberate tradeoff; notarization, which removes the prompt, needs an Apple -Developer identity and is out of scope for now. +| both | `SHA256SUMS` | Checksums of both packages; the installer verifies against it | + +**macOS install:** users install with the one-line installer +([`scripts/install-macos.sh`](scripts/install-macos.sh); see the README), which +downloads the latest DMG, verifies its SHA-256 against `SHA256SUMS`, installs the +app, and clears the download quarantine. The build is ad-hoc signed, not notarized +(a deliberate tradeoff) — installing via `curl` sidesteps the browser-download +quarantine, so the first launch is clean. ## Cutting a release diff --git a/scripts/install-macos.sh b/scripts/install-macos.sh new file mode 100755 index 0000000..5fdc3dd --- /dev/null +++ b/scripts/install-macos.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# +# One-line installer for OCPP DebugKit Studio (macOS, Apple silicon): +# +# curl -fsSL https://raw.githubusercontent.com/ocpp-debugkit/studio/main/scripts/install-macos.sh | bash +# +# Fetches the latest release DMG, verifies its SHA-256 against the release's +# published SHA256SUMS, installs the app to /Applications, clears the download +# quarantine, and opens it. No toolchain, no manual steps. +# +# The checksum and the DMG are both served from the GitHub release over HTTPS, so +# this verifies integrity (a corrupt or truncated download is rejected); it is not +# an independent code signature. +set -euo pipefail + +repo="ocpp-debugkit/studio" +app="OCPP DebugKit Studio.app" +dest="/Applications/$app" +base="https://github.com/$repo/releases/latest/download" + +note() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } +fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; } + +[ "$(uname -s)" = "Darwin" ] || fail "This installer is macOS-only. On Linux, grab the .tar.gz from https://github.com/$repo/releases." +[ "$(uname -m)" = "arm64" ] || fail "OCPP DebugKit Studio ships an Apple-silicon (arm64) build; this Mac is $(uname -m)." + +mnt="" +tmp="$(mktemp -d)" +cleanup() { + [ -n "$mnt" ] && hdiutil detach "$mnt" >/dev/null 2>&1 || true + rm -rf "$tmp" +} +trap cleanup EXIT + +note "Finding the latest release" +sums="$(curl -fsSL "$base/SHA256SUMS")" || fail "could not fetch release checksums" +line="$(printf '%s\n' "$sums" | grep 'macos-ReleaseFast\.dmg$')" || fail "the latest release has no macOS build" +sha="${line%% *}" +name="${line##* }" + +note "Downloading $name" +curl -fSL --progress-bar -o "$tmp/$name" "$base/$name" || fail "download failed" + +note "Verifying SHA-256" +got="$(shasum -a 256 "$tmp/$name" | awk '{ print $1 }')" +[ "$got" = "$sha" ] || fail "checksum mismatch — expected $sha, got $got (not installing)" + +note "Mounting the disk image" +mnt="$(hdiutil attach "$tmp/$name" -nobrowse -readonly | grep -o '/Volumes/.*' | head -1)" +[ -n "$mnt" ] || fail "could not mount the disk image" + +sudo="" +if [ ! -w /Applications ]; then + sudo="sudo" + note "/Applications needs administrator access — you may be prompted for your password" +fi + +note "Installing to /Applications" +$sudo rm -rf "$dest" +$sudo ditto "$mnt/$app" "$dest" + +# The app copied out of a curl-downloaded DMG normally has no quarantine flag +# (curl does not set one), but clear it defensively so the first launch never +# hits Gatekeeper. Harmless if the attribute is absent. +$sudo xattr -dr com.apple.quarantine "$dest" 2>/dev/null || true + +note "Opening $app" +open "$dest" +note "Done — OCPP DebugKit Studio is installed in /Applications."