Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codesigning packages for macOS #10645

Merged
merged 35 commits into from
Aug 12, 2024
Merged

Codesigning packages for macOS #10645

merged 35 commits into from
Aug 12, 2024

Conversation

jmarrec
Copy link
Contributor

@jmarrec jmarrec commented Aug 6, 2024

Pull request overview

Pull Request Author

Add to this list or remove from it as applicable. This is a simple templated set of guidelines.

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions
  • If any defect files are updated to a more recent version, upload new versions here or on DevSupport
  • If IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange label
  • If structural output changes, add to output rules file and add OutputChange label
  • If adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependencies

Reviewer

This will not be exhaustively relevant to every PR.

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

jmarrec added 30 commits August 6, 2024 13:52
…w due to installing mactex from brew (15min)
…'s only for ppc and i386 (so outdated, I recommend just trashing it)

On M1 mac
```
./bin/EP-Compare/Run-Mac/EP-Compare.app/Contents/MacOS/EP-Compare
-bash: /Users/julien/Software/Others/EnergyPlus/bin/EP-Compare/Run-Mac/EP-Compare.app/Contents/MacOS/EP-Compare: Bad CPU type in executable
`
``
The Fortran (and ConvertInputFormat) are actual sub-`project()` so codesigning does not work from Install.cmake
(locally I build with sphinxcontrib-moderncmakedomain)
@jmarrec jmarrec added Defect Includes code to repair a defect in EnergyPlus Developer Issue Related to cmake, packaging, installers, or developer tooling (CI, etc) labels Aug 6, 2024
@jmarrec jmarrec self-assigned this Aug 6, 2024
@@ -98,7 +98,7 @@ def generate_epJSON_schema(source_dir_path: str):
p = multiprocessing.Process(target=generate_epJSON_schema, args=(sys.argv[1], ))
p.start()

timeout_seconds = 30
timeout_seconds = 60
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept getting a timeout on macos-12, so I increased the timeout a bit.

I was getting it only intermittently, and never on macos-14 (the arm64 runner), so I suspect the runtime was very near 30 seconds and sometimes it'd be ok and sometimes not.

Comment on lines +691 to +698
if(APPLE)

include(${CMAKE_CURRENT_LIST_DIR}/CodeSigning.cmake)

# Defines CPACK_CODESIGNING_DEVELOPPER_ID_APPLICATION and CPACK_CODESIGNING_NOTARY_PROFILE_NAME
setup_macos_codesigning_variables()

if(CPACK_CODESIGNING_DEVELOPPER_ID_APPLICATION)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If APPLE and the CPACK_CODESIGNING_DEVELOPPER_ID_APPLICATION is defined, we're in business!

Comment on lines +699 to +721
set(FILES_TO_SIGN
# Targets are signed already via register_install_codesign_target
#$<TARGET_FILE_NAME:ConvertInputFormat>
#$<TARGET_FILE_NAME:energyplus>
#$<TARGET_FILE_NAME:energyplusapi>

# Bash scripts, not sure if needed or not
"runenergyplus"
"runepmacro"
"runreadvars"
# Copied-verbatim apps: Already signed because just copied from bin to package
# "EPMacro"
# "PreProcess/EP-Launch-Lite.app"
# "PreProcess/IDFVersionUpdater/IDFVersionUpdater.app"
# "PostProcess/EP-Compare/EP-Compare.app"
)

# Codesign inner binaries and libraries, in the CPack staging area for the EnergyPlus project, component Unspecified
# Define some required variables for the script in the scope of the install(SCRIPT) first
install(CODE "set(CPACK_CODESIGNING_DEVELOPPER_ID_APPLICATION \"${CPACK_CODESIGNING_DEVELOPPER_ID_APPLICATION}\")" COMPONENT Unspecified)
install(CODE "set(FILES_TO_SIGN \"${FILES_TO_SIGN}\")" COMPONENT Unspecified)
# call the script
install(SCRIPT "${CMAKE_CURRENT_LIST_DIR}/install_codesign_script.cmake" COMPONENT Unspecified)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bit will sign the:

  • FILES_TO_SIGN
    • but that part is probably not needed anymore since only scripts are left... I ended up changing totally the way I sign binaries after realizing that the FORTRAN stuff (and ConvertInputFormat) are in different cmake project() and therefore keep overriding this.
  • It globs the python .so and the root dylibs too.

Comment on lines +723 to +724
# Register the CPACK_POST_BUILD_SCRIPTS
set(CPACK_POST_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/CPackSignAndNotarizeDmg.cmake")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This post cpack script will sign the resulting .dmg

and notarize + staple (+ verify via spctl --assess) it if CPACK_CODESIGNING_NOTARY_PROFILE_NAME is defined.

include(${CMAKE_CURRENT_LIST_DIR}/CodeSigning.cmake)

# Defines CPACK_CODESIGNING_DEVELOPPER_ID_APPLICATION and CPACK_CODESIGNING_NOTARY_PROFILE_NAME
setup_macos_codesigning_variables()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will setset CPACK_IFW_PACKAGE_SIGNING_IDENTITY to the same value as CPACK_CODESIGNING_DEVELOPPER_ID_APPLICATION, so QtIFW's binarycreator signs the .app installer created.

Note: I had to patch the source code for binarycreator so the signing works, more on this in a bit when I comment the release workflow

Comment on lines +173 to +180
- name: Upload DMG as artifact for testing
uses: actions/upload-artifact@v4
with:
name: energyplus-${{ matrix.os }}.dmg
path: build/EnergyPlus-*-${{ matrix.arch }}.dmg
if-no-files-found: error
retention-days: 7
overwrite: false
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uploading the dmg as an artifact too, for testing you'll see.

Comment on lines +182 to +216
- name: Quick Test Package Signing and otool exes and libs
shell: bash
working-directory: ./build
run: |
begin_group() { echo -e "::group::\033[93m$1\033[0m"; }

subheader() { echo -e "\033[95m---- $1\033[0m"; }

exes=(
"energyplus" "libenergyplusapi.dylib"
"ExpandObjects" "ConvertInputFormat"
"PreProcess/IDFVersionUpdater/Transition-V23-1-0-to-V23-2-0"
"PostProcess/ReadVarsESO" "PostProcess/HVAC-Diagram"
)

TGZ_DIR=$(find _CPack_Packages/Darwin/TGZ -name "EnergyPlus*" -type d -maxdepth 1)
echo "TGZ_DIR=$TGZ_DIR" >> $GITHUB_ENV
echo "Checking TGZ dir at $TGZ_DIR"

for rel_exe in "${exes[@]}"; do
exe="$TGZ_DIR/$rel_exe"
begin_group "Checking $exe"
subheader "otool"
otool -L "${exe}" || true
subheader "codesign"
siginfo=$(codesign --display -vv "${exe}" 2>&1)
if [[ $siginfo == *"K7JYVQJL7R"* ]]; then
echo -e "\033[92mSIGNATURE OK\033[0m"
echo "$siginfo" | grep Authority
else
echo -e "\033[91mSignature not ok for ${exe}\033[0m"
echo "::error::title=Signature not ok for ${exe}::$siginfo"
fi
echo "::endgroup::"
done
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this could be removed altogether, but I kinda like having a short and sweet version, the full test below is verbose. And I've improved the grouping and colors and co so that's very readable here

cf https://github.com/jmarrec/EnergyPlus/actions/runs/10266015716/job/28403444892

image

Comment on lines +218 to +238
- name: Full Test Package signing and otool for IFW and TGZ
working-directory: ./build
shell: bash
run: |
begin_group() { echo -e "::group::\033[93m$1\033[0m"; }

begin_group "Full Check signature of _CPack_Packages for both IFW and TGZ and resolve otool libraries"
python ../scripts/dev/verify_signature.py --verbose --otool --otool-out-file otool_infos_cpack.json .
echo "::endgroup::"

begin_group "Running a simulation with python"
./$TGZ_DIR/energyplus --help
./$TGZ_DIR/energyplus -w ./$TGZ_DIR/WeatherData/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw -d out ./$TGZ_DIR/ExampleFiles/PythonPluginCustomSchedule.idf
echo "::endgroup::"

- name: Upload otool info as artifact
uses: actions/upload-artifact@v4
with:
name: otool_infos_cpack_${{ matrix.os }}_${{ matrix.arch }}
path: build/otool*json
if-no-files-found: error
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I check the _CPack staging areas to ensure it's codesigned there. No point continuing if not.

I also make sure I can run a python simulation, I was getting issues early on when the python lib-dynload sos were not signed as well

and I upload the otool json for inspection if needed


- name: Run Package Tests
run: python checkout/scripts/package_tests/runner.py --verbose ${{ matrix.test_key }} package/
- uses: actions/checkout@v4 # Still need E+ checked out to get testing scripts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just whitespace change, use https://github.com/NREL/EnergyPlus/pull/10645/files?w=1 to not see them.

Comment on lines +309 to +362
- name: Gather Dmg Package from Artifacts
uses: actions/download-artifact@v4
with:
name: energyplus-${{ matrix.os }}.dmg
path: dmg

- name: Test Dmg Install and Package signing
working-directory: ./dmg
shell: bash
run: |
begin_group() { echo -e "::group::\033[93m$1\033[0m"; }

set -x

dmg=$(ls EnergyPlus-*.dmg)
begin_group "Checking Signature of .dmg"
spctl --assess --type open --context context:primary-signature -vvvv $dmg
echo "::endgroup::"

begin_group "Mounting Dmg, and checking signature of installer app"
mkdir temp_mount
hdiutil attach -mountpoint ./temp_mount/ $dmg
filename="${dmg%.*}"
spctl --assess --type open --context context:primary-signature -vvvv ./temp_mount/$filename.app
echo "::endgroup::"

begin_group "Installing"
sudo ./temp_mount/$filename.app/Contents/MacOS/$filename --accept-licenses --default-answer --confirm-command --root $(pwd)/test_install install
hdiutil detach ./temp_mount/
echo "::endgroup::"

begin_group "Quick Check signature of inner executables and binaries"
codesign -dvvv ./test_install/energyplus
codesign -dvvv ./test_install/libenergyplusapi.dylib
codesign -dvvv ./test_install/libpython*.dylib
codesign -dvvv ./test_install/ConvertInputFormat
codesign -dvvv ./test_install/PostProcess/ReadVarsESO
echo "::endgroup::"

begin_group "Full Check signature of installed DMG for all executables and resolve otool libraries"
python ../checkout/scripts/dev/verify_signature.py --otool --otool-out-file otool_info_dmg.json --verbose --install test_install
echo "::endgroup::"

begin_group "Running a simulation with python"
./test_install/energyplus --help
./test_install/energyplus -w ./test_install/WeatherData/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.epw -d out ./test_install/ExampleFiles/PythonPluginCustomSchedule.idf
echo "::endgroup::"

- name: Upload otool info as artifact
uses: actions/upload-artifact@v4
with:
name: otool_info_dmg_${{ matrix.os }}_${{ matrix.arch }}
path: dmg/otool*json
if-no-files-found: error
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new.

I download the .dmg artifact on the test machine and I:

  • Ensure it's properly signed and notarized
  • Mount it
  • Ensure the installer .app is properly signed and notarized
  • Install the ifw installer
  • Then I test the resulting folder for codesigning and otool for binaries and executables

@jmarrec jmarrec requested a review from Myoldmopar August 6, 2024 14:02
@jmarrec jmarrec changed the title Codesigning Codesigning for macOS Aug 6, 2024
@jmarrec jmarrec changed the title Codesigning for macOS Codesigning packages for macOS Aug 6, 2024
@JasonGlazer
Copy link
Contributor

Thanks @jmarrec for doing this, I just took a quick look at the changes but only understood a little bit of it so I don't think it can be considered a real review. I do think the users will really like this change. If I update a MacOS exe file in the repo, do I need to do anything special?

@jmarrec
Copy link
Contributor Author

jmarrec commented Aug 8, 2024

@JasonGlazer Yes, the exe will need to resigned.


env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_TYPE: Release
FC: gfortran-13
SDKROOT: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
Python_REQUIRED_VERSION: 3.12.2
BUILD_DOCS: true # Installing MacTex takes like 15min, so you can speed things up by disabling it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. we should make sure that our package testing scripts confirm docs are built, otherwise this could easily slip through on someone's test commits on a PR.

@Myoldmopar
Copy link
Member

Alright. This is going in. We will see how things go with IO freeze and tweak things as needed, but this is going to be vital as we move toward upcoming Mac OS releases. @jmarrec this was a substantial lift, and I am especially grateful for not only the work itself but also how you have documented the process. I look forward to a day soon when we can eliminate all the prebuilt binaries, and all the Fortran apps, and make this whole process just much easier.

@Myoldmopar Myoldmopar merged commit 7b298a8 into develop Aug 12, 2024
38 checks passed
@Myoldmopar Myoldmopar deleted the codesigning branch August 12, 2024 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Defect Includes code to repair a defect in EnergyPlus Developer Issue Related to cmake, packaging, installers, or developer tooling (CI, etc)
Projects
None yet
8 participants