diff --git a/cmd/probo-agent/installer/macos/build.sh b/cmd/probo-agent/installer/macos/build.sh index 1cfb49c9e..2ffa9bf42 100755 --- a/cmd/probo-agent/installer/macos/build.sh +++ b/cmd/probo-agent/installer/macos/build.sh @@ -149,6 +149,59 @@ team_id_option() { printf '"%s"' "${APPLE_TEAM_ID}" } +# Build AppIcon.icns from the single committed master PNG +# (enroll-ui/Resources/icon-original.png), matching auditor-mode's +# pad-then-resize pipeline. Writes under STAGE; does not touch the +# source tree. +generate_app_icon_icns() { + local icon_original="$1" + local icns_out="$2" + local icon_dir padded tmp iconset + + if [ ! -f "${icon_original}" ]; then + echo "error: missing app icon source ${icon_original}" >&2 + exit 1 + fi + + icon_dir="${STAGE}/app-icon" + padded="${icon_dir}/icon-padded.png" + tmp="${icon_dir}/icon-padded.tmp.png" + iconset="${icon_dir}/AppIcon.iconset" + rm -rf "${icon_dir}" + mkdir -p "${iconset}" + + # 10% padding on all sides (960 content inside 1200 canvas). + sips -z 960 960 "${icon_original}" --out "${tmp}" >/dev/null + sips --padToHeightWidth 1200 1200 "${tmp}" --out "${padded}" >/dev/null + rm -f "${tmp}" + + # Write through temp names: sips mishandles @2x suffixes in --out paths. + sips -z 16 16 "${padded}" --out "${icon_dir}/16.png" >/dev/null + sips -z 32 32 "${padded}" --out "${icon_dir}/32.png" >/dev/null + sips -z 64 64 "${padded}" --out "${icon_dir}/64.png" >/dev/null + sips -z 128 128 "${padded}" --out "${icon_dir}/128.png" >/dev/null + sips -z 256 256 "${padded}" --out "${icon_dir}/256.png" >/dev/null + sips -z 512 512 "${padded}" --out "${icon_dir}/512.png" >/dev/null + sips -z 1024 1024 "${padded}" --out "${icon_dir}/1024.png" >/dev/null + + # Build @2x names via concatenation so the shell never treats @ as a + # glob qualifier (and sips is never asked to write those paths). + local at2x + at2x='@2x.png' + cp "${icon_dir}/16.png" "${iconset}/icon_16x16.png" + cp "${icon_dir}/32.png" "${iconset}/icon_16x16${at2x}" + cp "${icon_dir}/32.png" "${iconset}/icon_32x32.png" + cp "${icon_dir}/64.png" "${iconset}/icon_32x32${at2x}" + cp "${icon_dir}/128.png" "${iconset}/icon_128x128.png" + cp "${icon_dir}/256.png" "${iconset}/icon_128x128${at2x}" + cp "${icon_dir}/256.png" "${iconset}/icon_256x256.png" + cp "${icon_dir}/512.png" "${iconset}/icon_256x256${at2x}" + cp "${icon_dir}/512.png" "${iconset}/icon_512x512.png" + cp "${icon_dir}/1024.png" "${iconset}/icon_512x512${at2x}" + + iconutil -c icns "${iconset}" -o "${icns_out}" +} + # Build Probo Agent.app (URL handler + embedded privileged helper) into # parent_dir. Signs nested Mach-Os then the .app bundle (bottom-up). build_probo_agent_app() { @@ -156,9 +209,9 @@ build_probo_agent_app() { local build_dir render_dir local helper_info_plist helper_launchd_plist local helper_binary url_handler_binary bin_dir - local app_root contents macos launch_services launch_daemons + local app_root contents macos resources launch_services launch_daemons local plist embedded_helper embedded_launchd - local helper_requirement + local helper_requirement app_icon_original app_icon_icns local -a helper_linker_flags swift_arch_args build_dir="${STAGE}/enroll-ui-build" @@ -218,18 +271,24 @@ build_probo_agent_app() { app_root="${parent_dir}/${APP_NAME}" contents="${app_root}/Contents" macos="${contents}/MacOS" + resources="${contents}/Resources" launch_services="${contents}/Library/LaunchServices" launch_daemons="${contents}/Library/LaunchDaemons" plist="${contents}/Info.plist" embedded_helper="${launch_services}/${HELPER_LABEL}" embedded_launchd="${launch_daemons}/${HELPER_LABEL}.plist" + app_icon_original="${ENROLL_UI_DIR}/Resources/icon-original.png" + app_icon_icns="${STAGE}/AppIcon.icns" rm -rf "${app_root}" - mkdir -p "${macos}" "${launch_services}" "${launch_daemons}" + mkdir -p "${macos}" "${resources}" "${launch_services}" "${launch_daemons}" + + generate_app_icon_icns "${app_icon_original}" "${app_icon_icns}" install -m 0755 "${url_handler_binary}" "${macos}/${URL_HANDLER_NAME}" install -m 0755 "${helper_binary}" "${embedded_helper}" install -m 0644 "${helper_launchd_plist}" "${embedded_launchd}" + ditto --norsrc --noextattr "${app_icon_icns}" "${resources}/AppIcon.icns" # Sign helper before writing Info.plist so SMPrivilegedExecutables # can embed the helper's designated requirement. diff --git a/cmd/probo-agent/installer/macos/enroll-ui/.gitignore b/cmd/probo-agent/installer/macos/enroll-ui/.gitignore index 709c71f8c..08a02ed3c 100644 --- a/cmd/probo-agent/installer/macos/enroll-ui/.gitignore +++ b/cmd/probo-agent/installer/macos/enroll-ui/.gitignore @@ -4,3 +4,9 @@ # Rendered by build.sh from *.tmpl (do not commit) Shared/*.generated.swift + +# Generated from Resources/icon-original.png (build staging preferred; +# ignore if produced locally under enroll-ui). +Resources/AppIcon.icns +Resources/AppIcon.iconset/ +Resources/icon-padded.png diff --git a/cmd/probo-agent/installer/macos/enroll-ui/Info.plist.tmpl b/cmd/probo-agent/installer/macos/enroll-ui/Info.plist.tmpl index 3b11bb923..60a6aeefb 100644 --- a/cmd/probo-agent/installer/macos/enroll-ui/Info.plist.tmpl +++ b/cmd/probo-agent/installer/macos/enroll-ui/Info.plist.tmpl @@ -21,6 +21,8 @@ Probo Agent CFBundleDisplayName Probo Agent + CFBundleIconFile + AppIcon CFBundlePackageType APPL CFBundleShortVersionString diff --git a/cmd/probo-agent/installer/macos/enroll-ui/Resources/icon-original.png b/cmd/probo-agent/installer/macos/enroll-ui/Resources/icon-original.png new file mode 100644 index 000000000..65615e8f8 Binary files /dev/null and b/cmd/probo-agent/installer/macos/enroll-ui/Resources/icon-original.png differ diff --git a/contrib/claude/release/probo-agent.md b/contrib/claude/release/probo-agent.md index ab090f18a..fa451566b 100644 --- a/contrib/claude/release/probo-agent.md +++ b/contrib/claude/release/probo-agent.md @@ -64,6 +64,14 @@ then the app bundle, optionally signs the product with profile; submits use `--keychain-profile` so the secret is not on `notarytool submit` argv). +The Finder/Dock icon for `Probo Agent.app` comes from a single master +PNG, `cmd/probo-agent/installer/macos/enroll-ui/Resources/icon-original.png` +(Probo square mark). At PKG build time `build.sh` pads/resizes it with +`sips`, compiles `AppIcon.icns` with `iconutil` under the build stage +directory, and installs it into `Contents/Resources/`. `Info.plist` +sets `CFBundleIconFile` to `AppIcon`. Do not commit generated +`.icns` / iconset PNGs. + There is no unsigned PKG path and no osascript elevation fallback. Local testing of browser enrollment requires a Developer ID–signed build. CLI enrollment without the app uses `sudo probo-agent install`. diff --git a/pkg/dnsverify/names.go b/pkg/dnsverify/names.go index 2ed6da077..e2f25548b 100644 --- a/pkg/dnsverify/names.go +++ b/pkg/dnsverify/names.go @@ -51,6 +51,7 @@ func EqualNames(a, b string) bool { // itself, not its apex. func CheckNames(hostname string) ([]string, error) { hostname = strings.ToLower(strings.TrimSpace(hostname)) + hostname = strings.TrimSuffix(hostname, ".") if hostname == "" { return nil, fmt.Errorf("cannot build DNS check names: empty hostname")