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"); }

Reply via email to