Skip to content

Commit 231a2e3

Browse files
anchapinAlex Chapin
andauthored
Ci_fixes (#5569)
* fix: Reset exit code on successful test rerun in CI When CTest failures trigger a rerun, the exit code from the initial failure was previously retained even if the rerun passed. This caused the CI job to fail despite successful retries. This change ensures that overall_exit_code is reset to 0 if the rerun command succeeds, while preserving the failure code if the rerun also fails. Updated Linux, Mac, and Windows build jobs. * Fix tar.gz artifact uploads to exclude dependencies Updated the 'upload-artifact' path in linux, macos, and windows build jobs to specifically match 'OpenStudio-*.tar.gz'. This prevents dependency tarballs (EnergyPlus, Radiance, etc.) from being included in the OpenStudio installer artifact, ensuring the uploaded asset is a single file as expected. * fix: Update CI workflow conditions and add permissions for container jobs * Fix macOS tarball generation issues and improve ad-hoc signing logic * fix: Add sudo to xattr and codesign commands in macOS installation notes * fix: Improve macOS app signing process by clearing extended attributes and ensuring proper signing of nested components * fix: Resize DMG for ad-hoc signatures and improve nested item signing logic * fix: Enhance DMG resizing and signing process for ad-hoc signatures * fix: Simplify ad-hoc DMG signing process by using a dedicated script * fix: Add script for ad-hoc DMG signing with enhanced nested component signing * fix: Verify location of ad-hoc script and update path for DMG patching * fix: Remove redundant verification step for ad-hoc script and update DMG installation instructions --------- Co-authored-by: Alex Chapin <a.n.chapin@gmai.com>
1 parent 15d1db6 commit 231a2e3

File tree

3 files changed

+226
-34
lines changed

3 files changed

+226
-34
lines changed

.github/workflows/full-build.yml

Lines changed: 117 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ jobs:
6868
container:
6969
image: ${{ matrix.container_image }}
7070
options: ${{ matrix.container_options }} --volume /mnt:/mnt
71+
permissions:
72+
contents: write
7173
strategy:
7274
fail-fast: false
7375
matrix:
@@ -363,7 +365,7 @@ jobs:
363365
364366
if [ $overall_exit_code -ne 0 ]; then
365367
echo "Rerunning failing tests..."
366-
ctest -C ${{ env.BUILD_TYPE }} --rerun-failed -T test --no-compress-output || overall_exit_code=$?
368+
ctest -C ${{ env.BUILD_TYPE }} --rerun-failed -T test --no-compress-output && overall_exit_code=0 || overall_exit_code=$?
367369
fi
368370
echo "exit_code=${overall_exit_code}" >> $GITHUB_OUTPUT
369371
@@ -464,7 +466,7 @@ jobs:
464466
uses: actions/upload-artifact@v4
465467
with:
466468
name: OS-Installers-${{ matrix.platform }}-TGZ-${{ github.sha }}
467-
path: ${{ steps.build_path.outputs.path }}/*.tar.gz
469+
path: ${{ steps.build_path.outputs.path }}/OpenStudio-*.tar.gz
468470
if-no-files-found: ignore
469471

470472
- name: Upload WHEEL installer
@@ -478,7 +480,7 @@ jobs:
478480
name: Publish Linux Artifacts
479481
needs: [linux-build]
480482
runs-on: ubuntu-latest
481-
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
483+
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
482484
steps:
483485
- name: Download all installers
484486
uses: actions/download-artifact@v4
@@ -510,6 +512,80 @@ jobs:
510512
if command -v md5sum >/dev/null 2>&1; then md5sum "$file"; else md5 "$file"; fi
511513
done
512514
515+
- name: Trigger Docker Build
516+
if: inputs.skip_docker_trigger != 'true' && github.event.inputs.skip_docker_trigger != 'true'
517+
working-directory: installers
518+
env:
519+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
520+
BRANCH_NAME: ${{ github.ref_name }}
521+
S3_PREFIX: ${{ github.ref_type == 'tag' && format('releases/{0}', github.ref_name) || format('{0}', github.ref_name) }}
522+
run: |
523+
set -euo pipefail
524+
525+
# Find the 22.04 deb file locally
526+
DEB_FILE=$(find . -name "*22.04*.deb" | head -n 1)
527+
if [ -z "$DEB_FILE" ]; then
528+
echo "::error::Could not find Ubuntu 22.04 deb file in installers directory"
529+
ls -la
530+
exit 1
531+
fi
532+
533+
FILENAME=$(basename "$DEB_FILE")
534+
echo "Found file: $FILENAME"
535+
536+
# Construct S3 URL
537+
# Replace + with %2B
538+
ENCODED_FILENAME=${FILENAME//+/%2B}
539+
BINARY_URL="https://${AWS_S3_BUCKET}.s3.amazonaws.com/${S3_PREFIX}/${ENCODED_FILENAME}"
540+
echo "Binary URL: $BINARY_URL"
541+
542+
# Parse version from filename
543+
# Expected format: OpenStudio-<Version>-<Platform>.deb
544+
if [[ "$FILENAME" =~ OpenStudio-(.+)-Ubuntu-22\.04.*\.deb ]]; then
545+
OS_VERSION_FULL=${BASH_REMATCH[1]}
546+
elif [[ "$FILENAME" =~ OpenStudio-(.+)-Linux.*\.deb ]]; then
547+
OS_VERSION_FULL=${BASH_REMATCH[1]}
548+
else
549+
echo "::error::Could not parse version from filename: $FILENAME"
550+
exit 1
551+
fi
552+
553+
echo "Full Version: $OS_VERSION_FULL"
554+
555+
# Logic from Jenkins:
556+
# Split by +
557+
IFS='+' read -r VER_PART SHA_PART <<< "$OS_VERSION_FULL"
558+
559+
if [[ "$VER_PART" == *"-"* ]]; then
560+
# 3.3.0-rc1 -> Ver: 3.3.0, Ext: rc1
561+
IFS='-' read -r OS_VERSION OS_VERSION_EXT <<< "$VER_PART"
562+
else
563+
# 3.3.0+sha -> Ver: 3.3.0, Ext: sha
564+
OS_VERSION="$VER_PART"
565+
OS_VERSION_EXT="$SHA_PART"
566+
fi
567+
568+
echo "OS Version: $OS_VERSION"
569+
echo "OS Version Ext: $OS_VERSION_EXT"
570+
571+
# Docker Tag Logic
572+
if [[ "$BRANCH_NAME" == "develop" ]]; then
573+
DOCKER_IMAGE_TAG="develop"
574+
else
575+
DOCKER_IMAGE_TAG="${OS_VERSION}-${OS_VERSION_EXT}"
576+
fi
577+
echo "Docker Image Tag: $DOCKER_IMAGE_TAG"
578+
579+
# Trigger Workflow
580+
echo "Triggering manual_update_develop workflow in NREL/docker-openstudio..."
581+
gh workflow run 'manual_update_develop' \
582+
--repo NREL/docker-openstudio \
583+
--ref develop \
584+
-f docker_image_tag="$DOCKER_IMAGE_TAG" \
585+
-f os_installer_link="$BINARY_URL" \
586+
-f os_version="$OS_VERSION" \
587+
-f os_version_ext="$OS_VERSION_EXT"
588+
513589
macos-build:
514590
name: Build Packages for ${{ matrix.pretty }}
515591
runs-on: ${{ matrix.os }}
@@ -645,7 +721,7 @@ jobs:
645721
646722
- name: Create Build Directory
647723
run: cmake -E make_directory ${{ env.OPENSTUDIO_BUILD }}
648-
724+
649725
- name: Configure Conan remotes
650726
run: |
651727
set -euo pipefail
@@ -797,13 +873,13 @@ jobs:
797873
798874
if [ $overall_exit_code -ne 0 ]; then
799875
echo "Rerunning failing tests..."
800-
ctest -C ${{ env.BUILD_TYPE }} --rerun-failed -T test --no-compress-output --output-on-failure || overall_exit_code=$?
876+
ctest -C ${{ env.BUILD_TYPE }} --rerun-failed -T test --no-compress-output --output-on-failure && overall_exit_code=0 || overall_exit_code=$?
801877
fi
802878
803879
echo "exit_code=${overall_exit_code}" >> $GITHUB_OUTPUT
804880
805881
- name: Setup Keychain
806-
if: ${{ success() && !cancelled() && (github.ref == 'refs/heads/develop' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true' || matrix.os == 'macOS') }}
882+
if: success() && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true' )
807883
env:
808884
APPLE_CERT_DATA: ${{ secrets.APPLE_CERT_DATA }}
809885
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
@@ -829,6 +905,8 @@ jobs:
829905
- name: Create packages
830906
if: ${{ success() && !cancelled() }}
831907
working-directory: ${{ env.OPENSTUDIO_BUILD }}
908+
env:
909+
COPYFILE_DISABLE: 1
832910
run: |
833911
set -euo pipefail
834912
. ./conanbuild.sh
@@ -841,6 +919,28 @@ jobs:
841919
find . -name "*.o" -type f -delete || true
842920
df -h .
843921
922+
- name: Ad-hoc Sign Inner Installer (Fix "Killed" Error)
923+
if: ${{ success() && !cancelled() }}
924+
working-directory: ${{ env.OPENSTUDIO_BUILD }}
925+
env:
926+
# Check if we have a real ID; if not, we must patch the installer
927+
APPLE_DEV_ID: ${{ secrets.APPLE_DEV_ID }}
928+
run: |
929+
set -euo pipefail
930+
931+
# Only run this fix if we DO NOT have a valid Developer ID.
932+
if [ -n "$APPLE_DEV_ID" ]; then
933+
echo "Valid Developer ID detected. Skipping ad-hoc patch."
934+
exit 0
935+
fi
936+
937+
echo "No Developer ID found. Patching DMGs with ad-hoc signature..."
938+
939+
# Loop through all generated DMGs
940+
find . -maxdepth 1 -name "*.dmg" -print0 | while IFS= read -r -d '' dmg_file; do
941+
../${{ env.OPENSTUDIO_SOURCE }}/developer/scripts/patch_adhoc_dmg.sh "$dmg_file"
942+
done
943+
844944
- name: Sign DMG and Notarize
845945
if: ${{ steps.create_packages.outcome == 'success' && (github.ref == 'refs/heads/develop' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true' || matrix.os == 'macOS') }}
846946
working-directory: ${{ env.OPENSTUDIO_BUILD }}
@@ -980,7 +1080,7 @@ jobs:
9801080
uses: actions/upload-artifact@v4
9811081
with:
9821082
name: OS-TGZ-${{ matrix.platform }}-${{ github.sha }}
983-
path: ${{ env.OPENSTUDIO_BUILD }}/*.tar.gz
1083+
path: ${{ env.OPENSTUDIO_BUILD }}/OpenStudio-*.tar.gz
9841084
if-no-files-found: ignore
9851085

9861086
- name: Fail job on test failures
@@ -992,7 +1092,7 @@ jobs:
9921092
name: Publish MacOS Artifacts
9931093
needs: [macos-build]
9941094
runs-on: ubuntu-latest
995-
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
1095+
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
9961096
steps:
9971097
- name: Download all installers
9981098
uses: actions/download-artifact@v4
@@ -1028,6 +1128,8 @@ jobs:
10281128
windows-build:
10291129
name: Build ${{ matrix.pretty }}
10301130
runs-on: ${{ matrix.os }}
1131+
permissions:
1132+
contents: write
10311133
strategy:
10321134
fail-fast: false
10331135
matrix:
@@ -1307,7 +1409,7 @@ jobs:
13071409
if ($overall_exit_code -ne 0) {
13081410
Write-Host "Rerunning failing tests..."
13091411
ctest -C ${{ env.BUILD_TYPE }} --rerun-failed -T test
1310-
if ($LASTEXITCODE -ne 0) { $overall_exit_code = 1 }
1412+
if ($LASTEXITCODE -eq 0) { $overall_exit_code = 0 } else { $overall_exit_code = 1 }
13111413
}
13121414
"exit_code=$overall_exit_code" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
13131415
@@ -1392,25 +1494,25 @@ jobs:
13921494
13931495
# CODE SIGNING - AWS Signing Service
13941496
- name: Setup Node.js
1395-
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
1497+
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
13961498
uses: actions/setup-node@v4
13971499
with:
13981500
node-version: "18"
13991501

14001502
- name: Install Signing Client Dependencies
1401-
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
1503+
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
14021504
run: npm install
14031505
working-directory: ./.github/signing-client
14041506

14051507
- name: Create .env file for Signing
1406-
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
1508+
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
14071509
run: |
14081510
echo "ACCESS_KEY=${{ secrets.AWS_SIGNING_ACCESS_KEY }}" > .env
14091511
echo "SECRET_KEY=${{ secrets.AWS_SIGNING_SECRET_KEY }}" >> .env
14101512
working-directory: ${{ env.OPENSTUDIO_BUILD }}
14111513

14121514
- name: Code sign installer
1413-
if: success() && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true')
1515+
if: success() && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true')
14141516
working-directory: ${{ env.OPENSTUDIO_BUILD }}
14151517
run: |
14161518
# Check if signing client exists
@@ -1517,7 +1619,7 @@ jobs:
15171619
uses: actions/upload-artifact@v4
15181620
with:
15191621
name: OS-Installers-${{ matrix.platform }}-TGZ-${{ github.sha }}
1520-
path: ${{ env.OPENSTUDIO_BUILD }}/*.tar.gz
1622+
path: ${{ env.OPENSTUDIO_BUILD }}/OpenStudio-*.tar.gz
15211623
if-no-files-found: ignore
15221624

15231625
- name: Upload Signed installers
@@ -1531,7 +1633,7 @@ jobs:
15311633
name: Publish Windows Artifacts
15321634
needs: [windows-build]
15331635
runs-on: ubuntu-latest
1534-
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
1636+
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') || inputs.publish_to_s3 == 'true' || github.event.inputs.publish_to_s3 == 'true'
15351637
steps:
15361638
- name: Download all installers
15371639
uses: actions/download-artifact@v4

README.md

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,12 @@ More information and documentation is available at the [OpenStudio website](http
1111

1212
For development builds (artifacts downloaded from GitHub Actions), you may encounter a "Damaged" error or "Unidentified Developer" warning on macOS, especially on Apple Silicon (ARM) machines. This is because these builds are not notarized by Apple.
1313

14-
If you encounter these issues, standard `xattr` commands on the DMG may not be sufficient. Please follow these steps:
15-
16-
1. **Mount the DMG** image.
17-
2. **Copy** the Installer application (e.g., `OpenStudio-3.11.0...app`) from the mounted volume to a local folder (e.g., your `Downloads` folder). *Do not run it directly from the DMG.*
18-
3. Open a **Terminal** and run the following commands on the *local copy* of the installer:
19-
20-
```bash
21-
# 1. Remove quarantine attributes
22-
xattr -cr path/to/local/OpenStudio-Installer.app
23-
24-
# 2. Ad-hoc sign the application (fixes "Killed" or crashes on startup)
25-
codesign --force --deep --sign - path/to/local/OpenStudio-Installer.app
26-
```
27-
28-
4. Run the installer. If double-clicking fails, run the executable directly with `sudo`:
29-
30-
```bash
31-
sudo path/to/local/OpenStudio-Installer.app/Contents/MacOS/OpenStudio-3.11.0-<version>-Darwin-<arch>
32-
```
14+
If you encounter these issues, please follow these steps to bypass the security check for this specific installer:
15+
16+
1. **Mount the DMG**: Locate the downloaded `.dmg` file in Finder. Right-click (or Control-click) the file and select **Open**.
17+
2. **Launch Installer**: Inside the mounted disk image window, Right-click (or Control-click) the `OpenStudio-Installer.app` file and select **Open**.
18+
3. **Acknowledge Warning**: A security warning dialog will appear. Click **Open** if available. If only **OK** is available, click it (the installer might close).
19+
4. **Security Settings**: Open **System Settings** (or System Preferences) and navigate to **Privacy & Security**.
20+
5. **Allow the App**: Scroll down to the "Security" section. Look for a note about the OpenStudio application being blocked. Click the **Open Anyway** button.
21+
6. **Confirm Open**: A final confirmation dialog will appear. Click **Open**.
22+
7. **Authenticate**: Enter your system password when prompted to authorize the installation.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
if [ "$#" -ne 1 ]; then
5+
echo "Usage: $0 <dmg_file>"
6+
exit 1
7+
fi
8+
9+
DMG_FILE="$1"
10+
MOUNT_POINT="mount_point_$(date +%s)"
11+
TEMP_RW="temp_rw_$(date +%s).dmg"
12+
13+
echo "-------------------------------------------------------"
14+
echo "Target DMG: $DMG_FILE"
15+
echo "-------------------------------------------------------"
16+
17+
# 1. Convert to Read-Write
18+
echo "Converting to Read-Write..."
19+
rm -f "$TEMP_RW"
20+
hdiutil convert "$DMG_FILE" -format UDRW -o "$TEMP_RW" -quiet
21+
22+
# 2. Resize DMG
23+
# Ad-hoc signatures add metadata. We resize to 2GB to be absolutely sure there's space.
24+
# For DMGs with partition maps (like CPack's GUID images), standard resize works.
25+
# For flat images, -imageonly might be needed.
26+
echo "Resizing DMG..."
27+
if hdiutil resize -size 2g "$TEMP_RW" 2>/dev/null; then
28+
echo " Standard resize to 2GB succeeded."
29+
elif hdiutil resize -size 2g -imageonly "$TEMP_RW" 2>/dev/null; then
30+
echo " Image-only resize to 2GB succeeded."
31+
else
32+
echo "Warning: Resize failed, proceeding anyway. This may cause 'internal error' in codesign if space is tight."
33+
fi
34+
35+
# 3. Mount
36+
echo "Mounting..."
37+
mkdir -p "$MOUNT_POINT"
38+
hdiutil attach "$TEMP_RW" -mountpoint "$MOUNT_POINT" -nobrowse -noverify -quiet
39+
40+
# 4. Sign
41+
echo "Applying ad-hoc signature..."
42+
export CODESIGN_ALLOCATE=$(xcrun -find codesign_allocate)
43+
44+
# Find all .app bundles in the mount point
45+
find "$MOUNT_POINT" -maxdepth 1 -name "*.app" -print0 | while IFS= read -r -d '' app_path; do
46+
echo "Processing app bundle: $app_path"
47+
48+
# Ensure everything is writable
49+
echo "Ensuring app bundle is writable..."
50+
chmod -R u+w "$app_path" || true
51+
52+
# 1. Clear extended attributes
53+
echo "Clearing extended attributes..."
54+
xattr -cr "$app_path" || echo "Warning: Some extended attributes could not be cleared."
55+
56+
# 2. Sign nested components
57+
echo "Signing nested components..."
58+
# Sign in depth-first order so that inner items are signed before their containers
59+
find "$app_path" -depth -print0 \( \
60+
\( -type d -name "*.framework" \) -o \
61+
\( -type d -name "*.bundle" \) -o \
62+
\( -type d -name "*.plugin" \) -o \
63+
\( -type f -name "*.dylib" \) -o \
64+
\( -type f -perm -111 \) \
65+
\) | while IFS= read -r -d '' item; do
66+
if [ "$item" != "$app_path" ]; then
67+
# Double check it's actually signable (directory bundle or Mach-O file)
68+
if [ -d "$item" ]; then
69+
echo " Signing nested bundle: $item"
70+
codesign --force --verify --verbose --sign - --timestamp=none --generate-entitlement-der "$item" || true
71+
elif [ -f "$item" ]; then
72+
if file "$item" | grep -qE "Mach-O|current ar archive"; then
73+
echo " Signing nested binary: $item"
74+
# Try to remove signature first if it fails with internal error
75+
codesign --force --verify --verbose --sign - --timestamp=none --generate-entitlement-der "$item" || {
76+
echo " Failed to sign $item, attempting signature removal first..."
77+
codesign --remove-signature "$item" || true
78+
codesign --force --verify --verbose --sign - --timestamp=none --generate-entitlement-der "$item"
79+
}
80+
fi
81+
fi
82+
fi
83+
done
84+
85+
echo "Signing top-level app..."
86+
codesign --force --verify --verbose --sign - --timestamp=none --generate-entitlement-der "$app_path"
87+
done
88+
89+
# 5. Cleanup and Convert Back
90+
echo "Detaching..."
91+
hdiutil detach "$MOUNT_POINT" -force
92+
rmdir "$MOUNT_POINT"
93+
94+
echo "Converting back to compressed DMG..."
95+
FINAL_DMG="signed_repacked.dmg"
96+
hdiutil convert "$TEMP_RW" -format UDZO -o "$FINAL_DMG" -quiet
97+
mv "$FINAL_DMG" "$DMG_FILE"
98+
rm "$TEMP_RW"
99+
100+
echo "Success: $DMG_FILE updated."

0 commit comments

Comments
 (0)