diff --git a/dashcaddy-installer/BUILD_GUIDE.md b/dashcaddy-installer/BUILD_GUIDE.md index ba254d6..3bcc980 100644 --- a/dashcaddy-installer/BUILD_GUIDE.md +++ b/dashcaddy-installer/BUILD_GUIDE.md @@ -58,9 +58,13 @@ npm run build # Windows (creates portable .exe and installer) npm run build:win -# macOS (creates .dmg) +# macOS zip (from any host; electron-builder's native target) npm run build:mac +# macOS real drag-install .dmg — built ON LINUX, no Mac needed +# (one-time toolchain: see scripts/build-dmg-linux.sh header) +npm run build:dmg + # Linux (creates AppImage and .deb) npm run build:linux ``` @@ -73,8 +77,12 @@ Built applications are placed in the `build-output/` directory: `build-output/DashCaddy Installer Setup .exe` (NSIS installer) — filenames embed the current `version` from package.json - **macOS**: `build-output/DashCaddy Installer--mac.zip` — the - configured mac target is `zip` (unsigned; signed `.dmg` builds require - a Mac with signing credentials) + configured mac target is `zip` (unsigned; signed builds require a Mac + with signing credentials). `npm run build:dmg` additionally produces a + real drag-install `build-output/DashCaddy Installer-.dmg` + built entirely on Linux (libguestfs HFS+ volume + libdmg-hfsplus UDZO + compression; unsigned — macOS Gatekeeper will show the standard + right-click→Open dialog on first launch) - **Linux**: `build-output/DashCaddy Installer-.AppImage` and `build-output/dashcaddy-installer__amd64.deb` diff --git a/dashcaddy-installer/package.json b/dashcaddy-installer/package.json index 66d0cc8..488bf40 100644 --- a/dashcaddy-installer/package.json +++ b/dashcaddy-installer/package.json @@ -12,7 +12,8 @@ "build:win": "electron-builder --win", "build:mac": "electron-builder --mac", "build:linux": "electron-builder --linux", - "build:scan": "bash scripts/check-artifact-secrets.sh build-output" + "build:scan": "bash scripts/check-artifact-secrets.sh build-output", + "build:dmg": "npm run build:mac && bash scripts/build-dmg-linux.sh" }, "keywords": [ "dashcaddy", diff --git a/dashcaddy-installer/scripts/build-dmg-linux.sh b/dashcaddy-installer/scripts/build-dmg-linux.sh new file mode 100755 index 0000000..6a3f7ec --- /dev/null +++ b/dashcaddy-installer/scripts/build-dmg-linux.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Build a REAL .dmg for macOS users ON LINUX (no Mac needed). +# +# One-time toolchain setup (all on the Linux build host): +# apt-get install -y hfsprogs libguestfs-tools linux-modules-extra-$(uname -r) +# hfsprogs = the HFS+ volume formatter; libguestfs runs it INSIDE its +# sandboxed appliance VM, where it only ever formats disk-image FILES — +# never real block devices/drives. +# modprobe hfsplus && echo hfsplus >> /etc/modules (kernel support) +# git clone https://github.com/planetbeing/libdmg-hfsplus.git /opt/libdmg-hfsplus +# cd /opt/libdmg-hfsplus +# sed -i 's/IF(OPENSSL_FOUND)/IF(FALSE)/' dmg/CMakeLists.txt # OpenSSL 3 breaks FileVault; not needed for plain UDZO +# mkdir build && cd build && cmake .. && make +# +# Usage: scripts/build-dmg-linux.sh (run from dashcaddy-installer/, after npm run build:mac) +set -euo pipefail +cd "$(dirname "$0")/.." + +LIBDMG=/opt/libdmg-hfsplus/build +STAGE="$(mktemp -d)" +trap 'rm -rf "$STAGE"' EXIT +APP="build-output/mac/DashCaddy Installer.app" +VERSION=$(node -p "require('./package.json').version") +OUT="build-output/DashCaddy Installer-$VERSION.dmg" + +[ -d "$APP" ] || { echo "ERROR: $APP missing — run: npm run build:mac"; exit 1; } +[ -x "$LIBDMG/hdutil/hdutil" ] || { echo "ERROR: libdmg-hfsplus not built at $LIBDMG"; exit 1; } +modprobe hfsplus 2>/dev/null || { echo "ERROR: hfsplus kernel module missing"; exit 1; } + +echo ">>> staging app + /Applications drag-install link" +cp -a "$APP" "$STAGE/DashCaddy Installer.app" +ln -s /Applications "$STAGE/Applications" + +echo ">>> creating HFS+ volume inside a 400M image file (no drives touched)" +# LIBGUESTFS_BACKEND=direct is deliberate: the appliance must run the host +# kernel so the hfsplus module is available; direct backend on a dedicated +# build host is accepted (appliance only ever touches image files here). +export LIBGUESTFS_BACKEND=direct +virt-make-fs --type=hfsplus --size=400M "$STAGE" "$STAGE/vol.hfs" + +echo ">>> verifying volume contents (app + symlink present)" +"$LIBDMG/hdutil/hdutil" "$STAGE/vol.hfs" ls / + +echo ">>> compressing to UDIF .dmg" +"$LIBDMG/dmg/dmg" dmg "$STAGE/vol.hfs" "$OUT" + +echo ">>> secret-scanning the DMG contents" +VERIFY="$STAGE/verify" +mkdir -p "$VERIFY" +"$LIBDMG/hdutil/hdutil" "$STAGE/vol.hfs" extractall / "$VERIFY" +bash scripts/check-artifact-secrets.sh "$VERIFY" + +echo ">>> DONE: $OUT ($(du -h "$OUT" | cut -f1))" +file "$OUT"