This is an automated email from the ASF dual-hosted git repository.
jimjag pushed a commit to branch AOO50X
in repository https://gitbox.apache.org/repos/asf/openoffice.git
The following commit(s) were added to refs/heads/AOO50X by this push:
new 721bd2d71f macOS: wire notarization into packaging and close release
gates
721bd2d71f is described below
commit 721bd2d71f31bd5eaea5b8cdc615e7e1688db39a
Author: Jim Jagielski <[email protected]>
AuthorDate: Fri Sep 11 07:49:00 2026 -0400
macOS: wire notarization into packaging and close release gates
A real Developer ID build - the first this signing work has had - surfaced
gaps ad-hoc testing couldn't: notarization was never invoked despite being
supported, Gatekeeper was checked before notarizing, and neither the DMG
nor its enclosed app was independently verified.
Also fixes a discarded license-resource return value and an EPM configure
requirement for package formats that never invoke EPM.
(cherry picked from commit c42fc0a9ce106621d53d9635e05c6ca7fd6a53e1)
---
main/configure.ac | 74 +++++++++++++++++++---
main/python/makefile.mk | 2 +-
main/set_soenv.in | 4 ++
main/solenv/bin/macosx-check-load-commands.sh | 8 ++-
main/solenv/bin/macosx-codesign.sh | 70 ++++++++++++++++++--
main/solenv/bin/modules/installer/simplepackage.pm | 4 +-
6 files changed, 143 insertions(+), 19 deletions(-)
diff --git a/main/configure.ac b/main/configure.ac
index ad97ff5ba8..227feb2c89 100644
--- a/main/configure.ac
+++ b/main/configure.ac
@@ -1000,6 +1000,18 @@ AC_ARG_WITH(macosx-codesigning-keychain,
Usage:
--with-macosx-codesigning-keychain=/path/to/build.keychain-db
],with_macosx_codesigning_keychain=$withval,)
+AC_ARG_WITH(macosx-notary-profile,
+[ --with-macosx-notary-profile
+ After code-signing with a Developer ID identity,
submit
+ the application and disk image to Apple's notary
service
+ and staple the ticket, using this "xcrun notarytool
+ store-credentials" keychain profile name. Requires
+ --with-macosx-codesigning-identity to be a real
+ Developer ID identity (not "-"). Unset: package
signed
+ but not notarized, as before.
+
+ Usage:
--with-macosx-notary-profile=my-notary-profile
+],with_macosx_notary_profile=$withval,)
AC_ARG_WITH(rat-scan,
[ --with-rat-scan Scan source code for license headers.
Use as --with-rat-scan to automatically download
pre-built Rat binaries.
@@ -4000,13 +4012,36 @@ dnl
===================================================================
dnl Checks for programs.
dnl ===================================================================
+dnl EPM is not needed for Windows, or when every requested package format is
+dnl handled directly by the simple packager (installer/simplepackage.pm)
+dnl rather than by EPM: "archive"/"installed" on any platform, and Darwin's
+dnl "dmg" - including the empty default, which resolves to "dmg" on Darwin
+dnl below. simplepackage.pm never invokes EPM for any of these three, so
+dnl requiring EPM to be present for e.g. a plain "dmg" or "archive dmg"
+dnl build serves no purpose.
+need_epm_for_packaging=yes
+if test "$_os" = "WINNT"; then
+ need_epm_for_packaging=no
+elif test "$with_package_format" = "archive" -o "$with_package_format" =
"installed"; then
+ need_epm_for_packaging=no
+elif test "$_os" = "Darwin"; then
+ need_epm_for_packaging=no
+ for pkgformat_word in $with_package_format; do
+ case "$pkgformat_word" in
+ archive|installed|dmg) ;;
+ *) need_epm_for_packaging=yes ;;
+ esac
+ done
+fi
+
AC_MSG_CHECKING([whether to enable EPM for packing])
if test "$enable_epm" = "yes"; then
AC_MSG_RESULT([yes])
dnl
================================================================================
- dnl Check for epm - not needed for Windows or building archive or installed
formats
+ dnl Check for epm - not needed for Windows, or when the requested package
+ dnl format(s) are all handled without it (see need_epm_for_packaging above)
dnl
================================================================================
- if test "$_os" != "WINNT" -a "$with_package_format" != "archive" -a
"$with_package_format" != "installed"; then
+ if test "$need_epm_for_packaging" = "yes"; then
if test -n "$with_epm"; then
EPM=$with_epm
else
@@ -4150,13 +4185,13 @@ msi - Windows .msi
fi
if echo "$PKGFORMAT" | $EGREP osx 2>&1 >/dev/null; then
if test "$_os" = "Darwin"; then
- if test "$_osxpkgbuild" = "no"; then
- AC_MSG_CHECKING([for PackageMaker availability])
- if ! test -x
/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker;
then
- AC_MSG_ERROR([not installed. Please install Apples Dev Tools])
- else
- AC_MSG_RESULT([ok])
- fi
+ AC_MSG_CHECKING([for PackageMaker availability])
+ if ! test -x
/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker;
then
+ AC_MSG_ERROR([not installed. Apple's PackageMaker does not exist on
+current Xcode; the "osx" EPM format is obsolete on this platform - use "dmg"
+instead, or see MACOS_PACKAGING_EPM_REVIEW.md for a modern product-PKG path.])
+ else
+ AC_MSG_RESULT([ok])
fi
else
AC_MSG_ERROR([PackageMaker needed to build OSX packages and you are
not on OSX...])
@@ -4176,7 +4211,15 @@ else
AC_MSG_RESULT([no])
BUILD_EPM=NO
EPM=NO
- PKGFORMAT=native
+ if test "$_os" = "Darwin" -a "$need_epm_for_packaging" = "no"; then
+ dnl simplepackage.pm builds archive/installed/dmg without EPM, so
+ dnl --disable-epm should not discard a requested "dmg" (or Darwin's
+ dnl "dmg" default) the way it must for a format that does need EPM.
+ PKGFORMAT=dmg
+ test -z "$with_package_format" || PKGFORMAT="$with_package_format"
+ else
+ PKGFORMAT=native
+ fi
fi
AC_SUBST(BUILD_EPM)
AC_SUBST(EPM_URL)
@@ -4584,6 +4627,7 @@ dnl Code signing during packaging:
solenv/bin/modules/installer/simplepackage.pm
dnl reads these from the environment (via set_soenv), so a bare "yes" is an
error.
MACOSX_CODESIGNING_IDENTITY=
MACOSX_CODESIGNING_KEYCHAIN=
+MACOSX_NOTARY_PROFILE=
if test "$with_macosx_codesigning_identity" = "yes"; then
AC_MSG_ERROR([--with-macosx-codesigning-identity needs a codesign identity,
or "-" for ad-hoc])
fi
@@ -4593,11 +4637,21 @@ fi
if test -n "$with_macosx_codesigning_keychain" -a
"$with_macosx_codesigning_keychain" != "no" -a
"$with_macosx_codesigning_keychain" != "yes"; then
MACOSX_CODESIGNING_KEYCHAIN=$with_macosx_codesigning_keychain
fi
+if test "$with_macosx_notary_profile" = "yes"; then
+ AC_MSG_ERROR([--with-macosx-notary-profile needs a notarytool keychain
profile name])
+fi
+if test -n "$with_macosx_notary_profile" -a "$with_macosx_notary_profile" !=
"no"; then
+ if test "$MACOSX_CODESIGNING_IDENTITY" = "" -o
"$MACOSX_CODESIGNING_IDENTITY" = "-"; then
+ AC_MSG_ERROR([--with-macosx-notary-profile needs
--with-macosx-codesigning-identity set to a real Developer ID identity, not
ad-hoc])
+ fi
+ MACOSX_NOTARY_PROFILE=$with_macosx_notary_profile
+fi
AC_SUBST(MACOSX_DEPLOYMENT_TARGET)
AC_SUBST(MACOSX_SDK_PATH)
AC_SUBST(SDKROOT)
AC_SUBST(MACOSX_CODESIGNING_IDENTITY)
AC_SUBST(MACOSX_CODESIGNING_KEYCHAIN)
+AC_SUBST(MACOSX_NOTARY_PROFILE)
dnl ===================================================================
diff --git a/main/python/makefile.mk b/main/python/makefile.mk
index ad196e1455..0919f12ac2 100644
--- a/main/python/makefile.mk
+++ b/main/python/makefile.mk
@@ -123,7 +123,7 @@ BUILD_ACTION=$(ENV_BUILD) $(GNUMAKE) -j$(EXTMAXPROCESS) &&
$(GNUMAKE) install &&
BUILD_ACTION+= && install_name_tool -id @loader_path/libpython3.11.dylib
$(MYCWD)/python-inst/lib/libpython3.11.dylib
BUILD_ACTION+= && install_name_tool -change
$(MYCWD)/python-inst/lib/libpython3.11.dylib
@executable_path/libpython3.11.dylib $(MYCWD)/python-inst/bin/python3.11
# install_name_tool -change succeeds silently when the old name does not match.
-BUILD_ACTION+= && $(SOLARENV)$/bin$/macosx-check-load-commands.sh
$(MYCWD)/python-inst/bin/python3.11
+BUILD_ACTION+= && $(SOLARENV)$/bin$/macosx-check-load-commands.sh
$(MYCWD)/python-inst/bin/python3.11 $(MYCWD)/python-inst/lib/libpython3.11.dylib
.ENDIF
.ELSE
diff --git a/main/set_soenv.in b/main/set_soenv.in
index 9e24f77a51..a12b61ce37 100644
--- a/main/set_soenv.in
+++ b/main/set_soenv.in
@@ -1869,6 +1869,10 @@ if ( $platform =~ m/darwin/ )
{
ToFile( "MACOSX_CODESIGNING_KEYCHAIN",
"@MACOSX_CODESIGNING_KEYCHAIN@", "e" );
}
+ if ( "@MACOSX_NOTARY_PROFILE@" ne "" )
+ {
+ ToFile( "MACOSX_NOTARY_PROFILE", "@MACOSX_NOTARY_PROFILE@", "e" );
+ }
ToFile( "LIBINTL_PREFIX", "@LIBINTL_PREFIX@", "e" );
}
if ( $platform =~ m/freebsd/ )
diff --git a/main/solenv/bin/macosx-check-load-commands.sh
b/main/solenv/bin/macosx-check-load-commands.sh
index d28a462fc3..5f1f25e01a 100755
--- a/main/solenv/bin/macosx-check-load-commands.sh
+++ b/main/solenv/bin/macosx-check-load-commands.sh
@@ -34,7 +34,13 @@ machos=()
while IFS= read -r -d '' f && IFS= read -r type; do
case "$type" in ": Mach-O"*) machos+=("$f") ;; esac
done < <(find "$@" -type f -print0 | xargs -0 file --no-pad --print0 --
2>/dev/null)
-[ ${#machos[@]} -gt 0 ] || exit 0
+# Every caller passes a real app bundle or binary that is expected to contain
+# Mach-O content; zero matches means a wrong path or missing build output, not
+# "nothing to check" - fail loudly instead of silently passing.
+if [ ${#machos[@]} -eq 0 ]; then
+ echo "no Mach-O files found under: $*" >&2
+ exit 1
+fi
# A dylib's own ID (LC_ID_DYLIB) is never used to locate it at runtime.
bad=$(printf '%s\0' "${machos[@]}" | xargs -0 otool -l | awk '
diff --git a/main/solenv/bin/macosx-codesign.sh
b/main/solenv/bin/macosx-codesign.sh
index d64f5a0918..40c8970fed 100755
--- a/main/solenv/bin/macosx-codesign.sh
+++ b/main/solenv/bin/macosx-codesign.sh
@@ -16,6 +16,10 @@
# the "xcrun notarytool store-credentials" keychain
# profile PROFILE and staple the ticket (.dmg, or a .app
# zipped for submission); needs a real identity
+# --release fail if the Gatekeeper (spctl) assessment rejects the
+# result, instead of only reporting it; ignored for an
+# ad-hoc identity, which spctl always rejects regardless
+# of notarization
# --verify only report the current signing state, change nothing
#
# The linker already ad-hoc-signs each Mach-O it produces, which is why the
@@ -36,6 +40,7 @@ ENTITLEMENTS="$SRCDIR/macosx-codesign-entitlements.plist"
KEYCHAIN="${MACOSX_CODESIGNING_KEYCHAIN:-}"
NOTARY_PROFILE=""
HARDENED=no
+RELEASE=no
VERIFY_ONLY=no
TARGETS=()
@@ -54,8 +59,9 @@ while [ $# -gt 0 ]; do
--notarize)
[ $# -ge 2 ] || { echo "$1 requires an argument" >&2;
exit 2; }
NOTARY_PROFILE="$2"; shift 2 ;;
+ --release) RELEASE=yes; shift ;;
--verify) VERIFY_ONLY=yes; shift ;;
- -h|--help) sed -n '2,29p' "$0"; exit 0 ;;
+ -h|--help) sed -n '2,33p' "$0"; exit 0 ;;
-*) echo "unknown option: $1" >&2; exit 2 ;;
*) TARGETS+=("$1"); shift ;;
esac
@@ -122,21 +128,70 @@ notarize() {
return 1
fi
echo " stapled notarization ticket to $target"
+ if ! xcrun stapler validate "$target"; then
+ echo "stapler validate: FAILED (staple reported success but
does not validate)" >&2
+ return 1
+ fi
+ echo " stapled ticket validates"
+}
+
+# hdiutil create/codesign only ever touch the staged tree before it goes into
+# the image; nothing checks the *finished* image's own structure, or that the
+# application actually mounts and verifies from inside it. See the "older
+# hdiutil makehybrid" note above sign_app() for why that distinction matters.
+verify_dmg_contents() {
+ local dmg="$1" mnt rc=0 app
+ if ! hdiutil verify "$dmg" >/dev/null; then
+ echo "hdiutil verify: FAILED" >&2
+ return 1
+ fi
+ echo "hdiutil verify: OK"
+
+ mnt=$(hdiutil attach -readonly -nobrowse "$dmg" | tail -1 | awk -F'\t'
'{print $NF}')
+ if [ -z "$mnt" ] || [ ! -d "$mnt" ]; then
+ echo "could not mount $dmg to verify its contents" >&2
+ return 1
+ fi
+ for app in "$mnt"/*.app; do
+ [ -d "$app" ] || continue
+ if ! codesign --verify --deep --strict --verbose=2 "$app"; then
+ echo "enclosed application verify: FAILED ($app)" >&2
+ rc=1
+ fi
+ done
+ hdiutil detach "$mnt" -quiet
+ if [ "$rc" -eq 0 ]; then
+ echo " enclosed application verifies from the mounted image"
+ fi
+ return "$rc"
}
report() {
- local target="$1"
+ local target="$1" spctl_rc=0 dv
echo "--- $target"
- codesign -dv --verbose=2 "$target" 2>&1 | grep -E
'Identifier|Format|CodeDirectory|Authority|TeamIdentifier|Sealed' || true
+ dv=$(codesign -dv --verbose=2 "$target" 2>&1) || true
+ printf '%s\n' "$dv" | grep -E
'Identifier|Format|CodeDirectory|Authority|TeamIdentifier|Sealed' || true
if ! codesign --verify --deep --strict --verbose=2 "$target"; then
echo "verify: FAILED" >&2
return 1
fi
echo "verify: OK"
case "$target" in
- *.dmg) spctl --assess --type open --context
context:primary-signature --verbose=4 "$target" || true ;;
- *) spctl --assess --type exec --verbose=4 "$target" || true
;;
+ *.dmg)
+ verify_dmg_contents "$target" || return 1
+ spctl --assess --type open --context
context:primary-signature --verbose=4 "$target" || spctl_rc=$? ;;
+ *) spctl --assess --type exec --verbose=4 "$target" ||
spctl_rc=$? ;;
esac
+ # spctl rejects every ad-hoc signature outright, notarized or not, so
only
+ # a real signature's rejection is meaningful enough to fail the build
on.
+ # Detect that from the target's own signature (an "Authority=" line
means a
+ # real CA-chained identity; ad-hoc has none) rather than the -i/env
+ # default, so this is also correct when --verify checks an
+ # already-signed artifact without re-passing -i.
+ if [ "$spctl_rc" -ne 0 ] && [ "$RELEASE" = yes ] && printf '%s\n' "$dv"
| grep -q 'Authority='; then
+ echo "spctl: FAILED (fatal under --release)" >&2
+ return 1
+ fi
}
# codesign rewrites every Mach-O it signs and writes _CodeSignature/ into
@@ -223,7 +278,6 @@ sign_app() {
# 3. the app bundle itself
sign_executable "$app"
echo " sealed $app"
- report "$app"
}
for target in "${TARGETS[@]}"; do
@@ -244,6 +298,10 @@ for target in "${TARGETS[@]}"; do
if [ "$VERIFY_ONLY" = yes ]; then report "$target";
continue; fi
sign_app "$target"
[ -z "$NOTARY_PROFILE" ] || notarize "$target"
+ # spctl rejects a Developer ID app that isn't notarized
yet, so this
+ # must run after notarize, not inside sign_app() - see
the .dmg
+ # branch above, which already had this order right.
+ report "$target"
;;
esac
done
diff --git a/main/solenv/bin/modules/installer/simplepackage.pm
b/main/solenv/bin/modules/installer/simplepackage.pm
index 4d3da52361..4f118d322b 100644
--- a/main/solenv/bin/modules/installer/simplepackage.pm
+++ b/main/solenv/bin/modules/installer/simplepackage.pm
@@ -423,7 +423,7 @@ sub create_package
if ( ! $allvariables->{'HIDELICENSEDIALOG'} )
{
-
installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$sla,
$includepatharrayref, 0);
+ $ref =
installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$sla,
$includepatharrayref, 0);
}
my $localtempdir = $tempdir;
@@ -567,6 +567,7 @@ sub create_package
{
my @signcall = ($signscript, "-i",
$ENV{'MACOSX_CODESIGNING_IDENTITY'});
push(@signcall, "-k",
$ENV{'MACOSX_CODESIGNING_KEYCHAIN'}) if $ENV{'MACOSX_CODESIGNING_KEYCHAIN'};
+ push(@signcall, "--notarize",
$ENV{'MACOSX_NOTARY_PROFILE'}) if $ENV{'MACOSX_NOTARY_PROFILE'};
push(@signcall, $appdir);
my $signreturn = system(@signcall);
if ( $signreturn ) {
installer::exiter::exit_program("ERROR: Could not code-sign $appdir!",
"create_package"); }
@@ -643,6 +644,7 @@ sub create_package
my $signscript = $ENV{'SOLARENV'} .
"/bin/macosx-codesign.sh";
my @signcall = ($signscript, "-i",
$ENV{'MACOSX_CODESIGNING_IDENTITY'});
push(@signcall, "-k",
$ENV{'MACOSX_CODESIGNING_KEYCHAIN'}) if $ENV{'MACOSX_CODESIGNING_KEYCHAIN'};
+ push(@signcall, "--notarize",
$ENV{'MACOSX_NOTARY_PROFILE'}) if $ENV{'MACOSX_NOTARY_PROFILE'};
push(@signcall, $archive);
my $signreturn = system(@signcall);
if ( $signreturn ) {
installer::exiter::exit_program("ERROR: Could not code-sign $archive!",
"create_package"); }