load("@rules_electron//electron:dmg.bzl", "electron_dmg")
electron_dmg(
name = "release",
app = ":app",
volume_name = "Sample Desktop",
volume_icon = "//assets:volume.icns",
source_date_epoch = 1577836800,
finder_window = [120, 140, 600, 360],
app_position = [140, 160],
applications_position = [460, 160],
icon_size = 112,
text_size = 12,
background_color = "#ddeeff",
background_image = "//assets:installer-background.png",
licenses = {"//legal:license.txt": "en_US"},
license_labels = "//legal:labels.json",
)The rule cross-packages a macOS ElectronAppInfo on BB Linux. Pinned xorriso and
UDIF converter sources compile with native Bazel C actions and declared zlib.
No configure, Make, CMake, mounted image or target executable runs during builds.
Output is a read-only, zlib-compressed UDIF disk image containing an HFS+ volume,
the app bundle and a standard /Applications link. applications_link = False
omits that link. Volume labels allow up to 32 UTF-8 bytes. Dates and ownership
are explicit; filesystem and UDIF identities derive from input bytes. User
configuration, host tools, filesystem times and libc PRNG state do not supply
image inputs. Existing app file bytes, modes and relative links survive staging.
Sign and notarize the app before immutable import when preparing a production release. The example's app carries ad hoc signatures.
finder_window enables a deterministic .DS_Store and HFS+ auto-open folder.
It declares Cocoa x, y, width and height, with a bottom-left screen origin.
App/Applications icon positions use centers
inside that window; icon_size allows 16..512 pixels and text_size 10..16.
background_color accepts #RRGGBB. Omitting finder_window retains the plain
volume layout.
background_image accepts a declared PNG, up to 64 MiB and 8192 pixels per axis.
It requires finder_window, overrides the background color and copies unchanged
bytes to .background.png. Its Carbon alias uses the explicit volume name/date
and a path inside that volume, without build paths, assumed mount points or host
file IDs. The writer
reads the background's catalog ID/date from its first generated HFS+ image,
finalizes the alias, then rebuilds and verifies unchanged catalog identity before
UDIF conversion. No mounting or target execution is involved. A path-based form also appears in
Chromium's Linux-compatible generator.
BB tests decode the packaged alias and image bytes, check actual catalog IDs/dates and
compare relocated builds. Native smoke resolves the packaged background
alias through macOS descriptors and compares captured Finder-window pixels with
the declared PNG through native color management. The picture getter is recorded
as a diagnostic; it throws -10000 on the hosted Finder even when the generated
alias resolves. The 74601b7 BB suite,
seven cross-builds
and all four native hosts
passed. The macOS host resolved the packaged alias and compared three clear
Finder-window samples with the same PNG through native color management:
all samples were identical, [187, 187, 187, 255]. Screenshots stay temporary;
only numeric samples enter logs. Existing signatures and updater lifecycle also
passed.
licenses maps declared UTF-8 .txt or .rtf files to explicit locales.
license_default_language defaults to en_US and must appear in that mapping.
The locale table includes English, French,
German, Japanese, Korean and Chinese regional IDs. Text uses that locale's legacy
encoding when representable, otherwise Unicode RTF. Declared RTF bytes stay
unchanged. No host locale or filename discovery supplies
inputs.
license_labels optionally provides a JSON object keyed by those same locales.
Each locale can override languageName, agree, disagree, print, save and
message. Defaults use the locale name and English controls. Labels must fit
255 bytes in that locale's legacy encoding. License inputs allow 2 MiB per file,
16 MiB total and at most 32 entries; labels allow 64 KiB and final XML 64 MiB.
{"en_US":{"languageName":"English","agree":"Agree","message":"Read license before installing."}}The separate ElectronDmgLicense action adds LPic, STR# and TEXT/RTF resources
to the unsigned image. License edits do not change filesystem-action inputs.
Compressed disk bytes and block maps stay unchanged; image identity includes the
new XML. Signed images, existing license resources, malformed bounds and
output/input aliases fail. Sign/notarize only after this stage.
Mapping entries and labels follow the dmg-license format.
The LPic default field is a resource index; region IDs belong in the mapping
entries. Native tests cover Japanese fallback at indices 0 and 1, with distinct
French text preventing a false match. BB tests independently decode mappings,
preserve disk bytes and compare relocated/reordered inputs.
The 63c5336 suite, seven cross-builds and all four native hosts passed. macOS displayed each GUI license, refused mounting after Disagree and mounted the app after Agree. Both RTF variants required visible CJK/emoji text. Finder pixels, signatures, runtime and updater checks also passed.
The manual dmg_license_probe workflow input tests a previously verified BB
image with the workflow's current macOS harness. Linux performs authenticated,
commit-bound artifact retrieval; the matching Mac host only inspects the image.
Probe results do not publish normal native-smoke commit status.
Set dmg_consent_mode=cli to inspect terminal consent instead. This requires
the complete decoded text, explicit refusal without mounting and acceptance with
a mounted payload; raw RTF markup fails.
license_texts optionally maps declared UTF-8 .txt companions to RTF license
locales. It emits TEXT beside unchanged RTF bytes at the same resource ID.
Companion text must fit the locale's legacy encoding. Duplicate/undeclared
locales, non-RTF primaries and invalid text fail. Companion files share the
existing input size budget and deterministic staging. The example's
English and
Japanese
CLI probes matched each decoded companion in full, refused mounting after No
and mounted the payload after Yes. GUI tests retain the RTF Unicode check.
RTF-only images mounted through hdiutil without requesting consent; declare a
plain-text companion when terminal consent is required.
electron_dmg_license creates another legal variant without rebuilding the
filesystem. Its image accepts an electron_dmg target (using that target's
unlicensed base) or a raw unsigned, unlicensed .dmg. It shares the licenses,
license_default_language, license_texts and license_labels attributes above. Signed or
already-licensed raw files fail. ElectronDmgInfo exposes image/unlicensed;
the original rule also exposes the unlicensed output group.
load("@rules_electron//electron:dmg.bzl", "electron_dmg_license")
electron_dmg_license(
name = "release_japanese",
image = ":release_dmg",
licenses = {"//legal:license.rtf": "ja_JP"},
license_default_language = "ja_JP",
)The example's English text, English Unicode RTF and Japanese-default Unicode RTF
variants use the same filesystem image. Hosted action inspection requires one
filesystem action feeding all three license variants. Native RTF consent remains
pending; select dmg_fixture=release_dmg_rtf.dmg or
dmg_fixture=release_dmg_japanese.dmg with the manual probe to inspect them.
Metadata uses checksum-pinned MIT-licensed ds_store 1.3.3 and mac_alias 2.2.2
Python sources. No host alias discovery, Finder, mounting or AppleScript
runs in artifact actions. Geometry/color inputs and metadata bytes participate
in deterministic image identity. BB tests decode the packaged settings and
auto-open catalog ID, preserve app seals and compare relocated input bytes.
Native smoke reads settings through Finder without changing them. The
02da44f BB suite,
seven cross-builds
and all four native hosts
passed window geometry, icon positions/sizes, background color, strict app
signatures and the full existing installer/update smoke. The native geometry
check converts Cocoa bounds using the actual display height. See the
codec contract.
BB tests independently decode UDIF block maps, check compressed/uncompressed CRC32 values, compare relocated ZIP/tree inputs, and read the image payload with xorriso. The native macOS smoke verifies/mounts the BB image read-only, copies the app, checks code signatures, then launches Electron with renderer/addon checks. BB tests, seven cross-builds and all four native hosts passed. The macOS ARM64 host verified/mounted the image, checked strict app signatures and launched the copied app. The writer leaves regular-file Finder metadata empty; adding default type/creator codes invalidates strict signatures.
volume_icon accepts a declared ICNS file. The writer validates and copies its
bytes to .VolumeIcon.icns and sets the HFS+ root folder's custom-icon flag.
The signed app bundle stays immutable; icon bytes participate in volume identity.
BB tests read catalog flags independently, compare relocated image bytes and
reject malformed icons or output/input aliases. Native smoke asks NSWorkspace
for the mounted volume icon and compares its rendered pixels against the same
declared app icon through native color management. Exact ICNS byte equality is
also required. The 69c3287 suite,
seven cross-builds
and all four native hosts
passed. The flag follows Apple TN1150.
load("@rules_electron//electron:release.bzl", "electron_macos_dmg_release_tool")
electron_macos_dmg_release_tool(
name = "release_dmg",
signer = "@rcodesign_linux_x64//:rcodesign",
)Run on the BB release client, outside cacheable artifact actions:
bazel run --config=bb-workflow //:release_dmg -- \
--input unsigned.dmg --output notarized.dmg \
--identifier org.example.sample \
--certificate-env RELEASE_CERTIFICATE_FILE --key-env RELEASE_PRIVATE_KEY_FILE \
--password-env RELEASE_KEY_PASSWORD --ca-file apple-roots.pem \
--expected-leaf-sha256 "$EXPECTED_LEAF_SHA256" --expected-team-id "$EXPECTED_TEAM_ID" \
--signing-time 2026-11-09T01:02:03Z --timestamp-url https://tsa.example.com/ \
--api-key-env APPLE_API_KEY_FILEThe client shares the app release client's real OpenSSL preflight: leaf pin, single team ID, explicit roots, encrypted key unlock and public-key match. The timestamp URL and identifier must be explicit. It requires Developer ID policy, then waits for accepted notarization and staples the image. Only the final DMG is committed; compute update hashes after this stage.
electron_macos_dmg_signing_tool stops after signing and does not accept notary
credentials. electron_macos_dmg_notarization_tool accepts an already signed
DMG, --input, --output, --api-key-env and optional --max-wait-seconds.
Every client requires a declared execution backend; keys enter through runtime
environment names, without inherited credentials or tool configuration in child
processes. Input artifacts remain unchanged.
Signing preserves the image prefix and all footer fields except embedded signature location/size. Notarization additionally preserves every existing signature blob; only the ticket slot can change. Duplicate, overlapping, truncated or malformed signature layouts fail. Output races preserve the competing file. These checks protect artifact bytes, and do not verify CMS or Apple ticket trust independently of the declared backend.
Tests use real OpenSSL and real rcodesign layouts with simulated certificate signature/TSA/Apple boundaries. Live Developer ID/TSA/Apple interoperability and production native trust remain unverified.