From 9f6d08fc1faafeed4df2ba1b06316fe09b7d827a Mon Sep 17 00:00:00 2001 From: Mbucari <37587114+Mbucari@users.noreply.github.com> Date: Wed, 12 Nov 2025 10:41:52 -0700 Subject: [PATCH] Update Workflows - Simplify workflows build commands - Don't build ReadyToRun on validate - Move get-version into it's own job in build.yml - Split macOS into it's own reusable workflow - Add app bundle code signing - Add notarization --- .github/workflows/build-linux.yml | 125 ++++++------------ .github/workflows/build-mac.yml | 99 ++++++++++++++ .github/workflows/build-windows.yml | 116 ++++++---------- .github/workflows/build.yml | 68 ++++++---- .github/workflows/release.yml | 7 +- .github/workflows/validate.yml | 20 ++- Scripts/Bundle_Debian.sh | 8 -- Scripts/Bundle_MacOS.sh | 53 +++++--- Scripts/Bundle_Redhat.sh | 8 -- Source/LoadByOS/MacOSConfigApp/Info.plist | 13 -- .../MacOSConfigApp/Libation.entitlements | 20 +++ .../LoadByOS/MacOSConfigApp/Libation_DS_Store | Bin 0 -> 14340 bytes .../MacOSConfigApp/MacOSConfigApp.csproj | 12 ++ Source/LoadByOS/MacOSConfigApp/background.png | Bin 0 -> 12463 bytes 14 files changed, 309 insertions(+), 240 deletions(-) create mode 100644 .github/workflows/build-mac.yml create mode 100644 Source/LoadByOS/MacOSConfigApp/Libation.entitlements create mode 100644 Source/LoadByOS/MacOSConfigApp/Libation_DS_Store create mode 100644 Source/LoadByOS/MacOSConfigApp/background.png diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index e76d1b87..91abad26 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -6,63 +6,46 @@ name: build on: workflow_call: inputs: - version_override: + libation-version: type: string - description: "Version number override" - required: false - run_unit_tests: + required: true + dotnet-version: + type: string + required: true + run-unit-tests: type: boolean - description: "Skip running unit tests" - required: false - default: true - runs_on: + publish-r2r: + type: boolean + retention-days: + type: number + architecture: type: string - description: "The GitHub hosted runner to use" + description: "CPU architecture targeted by the build." required: true OS: type: string description: > The operating system targeted by the build. - + There must be a corresponding Bundle_$OS.sh script file in ./Scripts required: true - architecture: - type: string - description: "CPU architecture targeted by the build." - required: true - -env: - DOTNET_CONFIGURATION: "Release" - DOTNET_VERSION: "9.0.x" - RELEASE_NAME: "chardonnay" jobs: build: name: "${{ inputs.OS }}-${{ inputs.architecture }}" - runs-on: ${{ inputs.runs_on }} + runs-on: ubuntu-latest + env: + RUNTIME_ID: "linux-${{ inputs.architecture }}" steps: - uses: actions/checkout@v5 - - name: Setup .NET - uses: actions/setup-dotnet@v5 + + - uses: actions/setup-dotnet@v5 with: - dotnet-version: ${{ env.DOTNET_VERSION }} - env: - NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Get version - id: get_version - run: | - inputVersion="${{ inputs.version_override }}" - if [[ "${#inputVersion}" -gt 0 ]] - then - version="${inputVersion}" - else - version="$(grep -Eio -m 1 '.*' ./Source/AppScaffolding/AppScaffolding.csproj | sed -r 's/<\/?Version>//g')" - fi - echo "version=${version}" >> "${GITHUB_OUTPUT}" + dotnet-version: ${{ inputs.dotnet-version }} + dotnet-quality: "ga" - name: Unit test - if: ${{ inputs.run_unit_tests }} + if: ${{ inputs.run-unit-tests }} working-directory: ./Source run: dotnet test @@ -70,63 +53,31 @@ jobs: id: publish working-directory: ./Source run: | - if [[ "${{ inputs.OS }}" == "MacOS" ]] - then - display_os="macOS" - RUNTIME_ID="osx-${{ inputs.architecture }}" - else - display_os="Linux" - RUNTIME_ID="linux-${{ inputs.architecture }}" - fi - - OUTPUT="bin/Publish/${display_os}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }}" - - echo "display_os=${display_os}" >> $GITHUB_OUTPUT - echo "Runtime Identifier: $RUNTIME_ID" - echo "Output Directory: $OUTPUT" - - dotnet publish \ - LibationAvalonia/LibationAvalonia.csproj \ - --runtime $RUNTIME_ID \ - --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output $OUTPUT \ - -p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml - dotnet publish \ - LoadByOS/${display_os}ConfigApp/${display_os}ConfigApp.csproj \ - --runtime $RUNTIME_ID \ - --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output $OUTPUT \ - -p:PublishProfile=LoadByOS/Properties/${display_os}ConfigApp/PublishProfiles/${display_os}Profile.pubxml - dotnet publish \ - LibationCli/LibationCli.csproj \ - --runtime $RUNTIME_ID \ - --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output $OUTPUT \ - -p:PublishProfile=LibationCli/Properties/PublishProfiles/${display_os}Profile.pubxml - dotnet publish \ - HangoverAvalonia/HangoverAvalonia.csproj \ - --runtime $RUNTIME_ID \ - --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output $OUTPUT \ - -p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml + PUBLISH_ARGS=( + '--runtime' '${{ env.RUNTIME_ID }}' + '--configuration' 'Release' + '--output' '../bin' + '-p:PublishProtocol=FileSystem' + "-p:PublishReadyToRun=${{ inputs.publish-r2r }}" + '-p:SelfContained=true') + + dotnet publish LibationAvalonia/LibationAvalonia.csproj "${PUBLISH_ARGS[@]}" + dotnet publish LoadByOS/LinuxConfigApp/LinuxConfigApp.csproj "${PUBLISH_ARGS[@]}" + dotnet publish LibationCli/LibationCli.csproj "${PUBLISH_ARGS[@]}" + dotnet publish HangoverAvalonia/HangoverAvalonia.csproj "${PUBLISH_ARGS[@]}" - name: Build bundle id: bundle - working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }} run: | - BUNDLE_DIR=$(pwd) - echo "Bundle dir: ${BUNDLE_DIR}" - cd .. - SCRIPT=../../../Scripts/Bundle_${{ inputs.OS }}.sh + SCRIPT=./Scripts/Bundle_${{ inputs.OS }}.sh chmod +rx ${SCRIPT} - ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ inputs.architecture }}" + ${SCRIPT} ./bin "${{ inputs.libation-version }}" "${{ inputs.architecture }}" artifact=$(ls ./bundle) echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}" - - name: Publish bundle - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v5 with: name: ${{ steps.bundle.outputs.artifact }} - path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }} + path: ./bundle/${{ steps.bundle.outputs.artifact }} if-no-files-found: error - retention-days: 7 + retention-days: ${{ inputs.retention-days }} diff --git a/.github/workflows/build-mac.yml b/.github/workflows/build-mac.yml new file mode 100644 index 00000000..75ba2863 --- /dev/null +++ b/.github/workflows/build-mac.yml @@ -0,0 +1,99 @@ +# build-mac.yml +# Reusable workflow that builds the MacOS (x64 and arm64) versions of Libation. +--- +name: build + +on: + workflow_call: + inputs: + libation-version: + type: string + required: true + dotnet-version: + type: string + required: true + run-unit-tests: + type: boolean + publish-r2r: + type: boolean + retention-days: + type: number + architecture: + type: string + description: "CPU architecture targeted by the build." + required: true + +env: + WAIT_FOR_NOTARIZE: true + +jobs: + build: + name: "macOS-${{ inputs.architecture }}" + runs-on: macos-latest + env: + RUNTIME_ID: "osx-${{ inputs.architecture }}" + CAN_SIGN: ${{ secrets.APPLE_TEAM_ID != '' && vars.APPLE_DEV_EMAIL != '' && secrets.APPLE_DEV_PASSWORD != '' }} + steps: + - uses: apple-actions/import-codesign-certs@v3 + if: ${{ env.CAN_SIGN == 'true' }} + with: + p12-file-base64: ${{ secrets.DISTRIBUTION_SIGNING_CERT }} + p12-password: ${{ secrets.DISTRIBUTION_SIGNING_CERT_PW }} + + - uses: actions/checkout@v5 + + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: ${{ inputs.dotnet-version }} + dotnet-quality: "ga" + + - name: Unit test + if: ${{ inputs.run-unit-tests }} + working-directory: ./Source + run: dotnet test + + - name: Publish + id: publish + working-directory: ./Source + run: | + PUBLISH_ARGS=( + '--runtime' '${{ env.RUNTIME_ID }}' + '--configuration' 'Release' + '--output' '../bin' + '-p:PublishProtocol=FileSystem' + "-p:PublishReadyToRun=${{ inputs.publish-r2r }}" + '-p:SelfContained=true') + + dotnet publish LibationAvalonia/LibationAvalonia.csproj "${PUBLISH_ARGS[@]}" + dotnet publish LoadByOS/MacOSConfigApp/MacOSConfigApp.csproj "${PUBLISH_ARGS[@]}" + dotnet publish LibationCli/LibationCli.csproj "${PUBLISH_ARGS[@]}" + dotnet publish HangoverAvalonia/HangoverAvalonia.csproj "${PUBLISH_ARGS[@]}" + + - name: Build bundle + id: bundle + run: | + SCRIPT=./Scripts/Bundle_MacOS.sh + chmod +rx ${SCRIPT} + ${SCRIPT} ./bin "${{ inputs.libation-version }}" "${{ inputs.architecture }}" ${{ env.CAN_SIGN }} + artifact=$(ls ./bundle) + echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}" + + - name: Notarize bundle + if: ${{ env.CAN_SIGN == 'true' }} + run: | + if [ ${{ env.WAIT_FOR_NOTARIZE }} ]; then + WAIT="--wait" + fi + + xcrun notarytool submit ./bundle/${{ steps.bundle.outputs.artifact }} $WAIT --no-progress --apple-id ${{ vars.APPLE_DEV_EMAIL }} --password ${{ secrets.APPLE_DEV_PASSWORD }} --team-id ${{ secrets.APPLE_TEAM_ID }} + + if [ ${{ env.WAIT_FOR_NOTARIZE }} ]; then + xcrun stapler staple "./bundle/${{ steps.bundle.outputs.artifact }}" + fi + + - uses: actions/upload-artifact@v5 + with: + name: ${{ steps.bundle.outputs.artifact }} + path: ./bundle/${{ steps.bundle.outputs.artifact }} + if-no-files-found: error + retention-days: ${{ inputs.retention-days }} diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 725ea5a7..62b3a343 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -6,113 +6,77 @@ name: build on: workflow_call: inputs: - version_override: + libation-version: type: string - description: "Version number override" - required: false - run_unit_tests: - type: boolean - description: "Skip running unit tests" - required: false - default: true - architecture: - type: string - description: "CPU architecture targeted by the build." required: true - -env: - DOTNET_CONFIGURATION: "Release" - DOTNET_VERSION: "9.0.x" + dotnet-version: + type: string + required: true + run-unit-tests: + type: boolean + publish-r2r: + type: boolean + retention-days: + type: number jobs: build: - name: "${{ matrix.os }}-${{ matrix.release_name }}-${{ inputs.architecture }}" + name: "Windows-${{ matrix.release_name }}-x64" runs-on: windows-latest - env: - OUTPUT_NAME: "${{ matrix.os }}-${{ matrix.release_name }}-${{ inputs.architecture }}" - RUNTIME_ID: "win-${{ inputs.architecture }}" strategy: matrix: - os: [Windows] ui: [Avalonia] release_name: [chardonnay] include: - - os: Windows - ui: WinForms + - ui: WinForms release_name: classic prefix: Classic- steps: - uses: actions/checkout@v5 - - name: Setup .NET - uses: actions/setup-dotnet@v5 + + - uses: actions/setup-dotnet@v5 with: - dotnet-version: ${{ env.DOTNET_VERSION }} - env: - NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Get version - id: get_version - run: | - if ("${{ inputs.version_override }}".length -gt 0) { - $version = "${{ inputs.version_override }}" - } else { - $version = (Select-Xml -Path "./Source/AppScaffolding/AppScaffolding.csproj" -XPath "/Project/PropertyGroup/Version").Node.InnerXML.Trim() - } - "version=$version" >> $env:GITHUB_OUTPUT + dotnet-version: ${{ inputs.dotnet-version }} + dotnet-quality: "ga" - name: Unit test - if: ${{ inputs.run_unit_tests }} + if: ${{ inputs.run-unit-tests }} working-directory: ./Source run: dotnet test - + - name: Publish working-directory: ./Source run: | - dotnet publish ` - Libation${{ matrix.ui }}/Libation${{ matrix.ui }}.csproj ` - --runtime ${{ env.RUNTIME_ID }} ` - --configuration ${{ env.DOTNET_CONFIGURATION }} ` - --output bin/Publish/${{ env.OUTPUT_NAME }} ` - -p:PublishProfile=Libation${{ matrix.ui }}/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml - dotnet publish ` - LoadByOS/${{ matrix.os }}ConfigApp/${{ matrix.os }}ConfigApp.csproj ` - --runtime ${{ env.RUNTIME_ID }} ` - --configuration ${{ env.DOTNET_CONFIGURATION }} ` - --output bin/Publish/${{ env.OUTPUT_NAME }} ` - -p:PublishProfile=LoadByOS/${{ matrix.os }}ConfigApp/PublishProfiles/${{ matrix.os }}Profile.pubxml - dotnet publish ` - LibationCli/LibationCli.csproj ` - --runtime ${{ env.RUNTIME_ID }} ` - --configuration ${{ env.DOTNET_CONFIGURATION }} ` - --output bin/Publish/${{ env.OUTPUT_NAME }} ` - -p:DefineConstants="${{ matrix.release_name }}" ` - -p:PublishProfile=LibationCli/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml - dotnet publish ` - Hangover${{ matrix.ui }}/Hangover${{ matrix.ui }}.csproj ` - --runtime ${{ env.RUNTIME_ID }} ` - --configuration ${{ env.DOTNET_CONFIGURATION }} ` - --output bin/Publish/${{ env.OUTPUT_NAME }} ` - -p:PublishProfile=Hangover${{ matrix.ui }}/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml + $PUBLISH_ARGS=@( + "--runtime", "win-x64", + "--configuration", "Release", + "--output", "../bin", + "-p:PublishProtocol=FileSystem", + "-p:PublishReadyToRun=${{ inputs.publish-r2r }}", + "-p:SelfContained=true") + + dotnet publish "Libation${{ matrix.ui }}/Libation${{ matrix.ui }}.csproj" $PUBLISH_ARGS + dotnet publish "LoadByOS/WindowsConfigApp/WindowsConfigApp.csproj" $PUBLISH_ARGS + dotnet publish "LibationCli/LibationCli.csproj" $PUBLISH_ARGS + dotnet publish "Hangover${{ matrix.ui }}/Hangover${{ matrix.ui }}.csproj" $PUBLISH_ARGS - name: Zip artifact id: zip - working-directory: ./Source/bin/Publish + working-directory: ./bin run: | - $bin_dir = "${{ env.OUTPUT_NAME }}\" $delfiles = @( "WindowsConfigApp.exe", "WindowsConfigApp.runtimeconfig.json", - "WindowsConfigApp.deps.json" - ) - foreach ($file in $delfiles){ if (test-path $bin_dir$file){ Remove-Item $bin_dir$file } } - $artifact="${{ matrix.prefix }}Libation.${{ steps.get_version.outputs.version }}-" + "${{ matrix.os }}".ToLower() + "-${{ matrix.release_name }}-${{ inputs.architecture }}" + "WindowsConfigApp.deps.json") + + foreach ($file in $delfiles){ if (test-path $file){ Remove-Item $file } } + $artifact="${{ matrix.prefix }}Libation.${{ inputs.libation-version }}-windows-${{ matrix.release_name }}-x64.zip" "artifact=$artifact" >> $env:GITHUB_OUTPUT - Compress-Archive -Path "${bin_dir}*" -DestinationPath "$artifact.zip" + Compress-Archive -Path * -DestinationPath "$artifact" - - name: Publish artifact - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v5 with: - name: ${{ steps.zip.outputs.artifact }}.zip - path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip + name: ${{ steps.zip.outputs.artifact }} + path: ./bin/${{ steps.zip.outputs.artifact }} if-no-files-found: error - retention-days: 7 + retention-days: ${{ inputs.retention-days }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 341f8033..9880c23d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,26 +6,47 @@ name: build on: workflow_call: inputs: - version_override: + libation-version: type: string - description: "Version number override" - required: false - run_unit_tests: + description: "Libation version number" + required: true + dotnet-version: + type: string + default: "9.x" + description: ".NET version to target" + run-unit-tests: type: boolean - description: "Skip running unit tests" - required: false - default: true + description: "Whether to run unit tests prior to publishing." + publish-r2r: + type: boolean + description: "Whether to publish assemblies as ReadyToRun." + retention-days: + type: number + description: "Number of days the artifacts are to be retained." -jobs: +jobs: windows: - strategy: - matrix: - architecture: [x64] uses: ./.github/workflows/build-windows.yml with: - version_override: ${{ inputs.version_override }} - run_unit_tests: ${{ inputs.run_unit_tests }} + libation-version: ${{ inputs.libation-version }} + dotnet-version: ${{ inputs.dotnet-version }} + run-unit-tests: ${{ inputs.run-unit-tests }} + publish-r2r: ${{ inputs.publish-r2r }} + retention-days: ${{ inputs.retention-days }} + + macOS: + strategy: + matrix: + architecture: [x64, arm64] + uses: ./.github/workflows/build-mac.yml + with: + libation-version: ${{ inputs.libation-version }} + dotnet-version: ${{ inputs.dotnet-version }} + run-unit-tests: ${{ inputs.run-unit-tests }} + publish-r2r: ${{ inputs.publish-r2r }} + retention-days: ${{ inputs.retention-days }} architecture: ${{ matrix.architecture }} + secrets: inherit linux: strategy: @@ -34,20 +55,11 @@ jobs: architecture: [x64, arm64] uses: ./.github/workflows/build-linux.yml with: - version_override: ${{ inputs.version_override }} - runs_on: ubuntu-latest + libation-version: ${{ inputs.libation-version }} + dotnet-version: ${{ inputs.dotnet-version }} + run-unit-tests: ${{ inputs.run-unit-tests }} + publish-r2r: ${{ inputs.publish-r2r }} + retention-days: ${{ inputs.retention-days }} + architecture: ${{ matrix.architecture }} OS: ${{ matrix.OS }} - architecture: ${{ matrix.architecture }} - run_unit_tests: ${{ inputs.run_unit_tests }} - macos: - strategy: - matrix: - architecture: [x64, arm64] - uses: ./.github/workflows/build-linux.yml - with: - version_override: ${{ inputs.version_override }} - runs_on: macos-latest - OS: MacOS - architecture: ${{ matrix.architecture }} - run_unit_tests: ${{ inputs.run_unit_tests }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 244b6e75..867f56e3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ on: - "v*" jobs: prerelease: - runs-on: ubuntu-latest + runs-on: ubuntu-slim outputs: version: ${{ steps.get_version.outputs.version }} steps: @@ -31,9 +31,10 @@ jobs: build: needs: [prerelease] uses: ./.github/workflows/build.yml + secrets: inherit with: - version_override: ${{ needs.prerelease.outputs.version }} - run_unit_tests: false + libation-version: ${{ needs.prerelease.outputs.version }} + publish-r2r: true release: needs: [prerelease, build] diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 27abc275..89877043 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -10,12 +10,30 @@ on: branches: [master] jobs: + get_version: + runs-on: ubuntu-slim + outputs: + version: ${{ steps.get_version.outputs.version }} + steps: + - name: Get version + id: get_version + run: | + wget "https://raw.githubusercontent.com/${{ github.repository }}/${{ github.sha }}/Source/AppScaffolding/AppScaffolding.csproj" + version="$(grep -Eio -m 1 '.*' ./AppScaffolding.csproj | sed -r 's/<\/?Version>//g')" + echo "version=${version}" >> "${GITHUB_OUTPUT}" build: + needs: [get_version] uses: ./.github/workflows/build.yml + with: + libation-version: ${{ needs.get_version.outputs.version }} + retention-days: 14 + run-unit-tests: true + docker: + needs: [get_version] uses: ./.github/workflows/docker.yml with: - version: ${GITHUB_SHA} + version: ${{ needs.get_version.outputs.version }} release: false secrets: docker_username: ${{ secrets.DOCKERHUB_USERNAME }} diff --git a/Scripts/Bundle_Debian.sh b/Scripts/Bundle_Debian.sh index b69eb76f..2a5d5034 100644 --- a/Scripts/Bundle_Debian.sh +++ b/Scripts/Bundle_Debian.sh @@ -28,14 +28,6 @@ then exit fi -contains() { case "$1" in *"$2"*) true ;; *) false ;; esac } - -if ! contains "$BIN_DIR" "$ARCH" -then - echo "This script must be called with a Libation binaries for ${ARCH}." - exit -fi - ARCH=$(echo $ARCH | sed 's/x64/amd64/') DEB_DIR=./deb diff --git a/Scripts/Bundle_MacOS.sh b/Scripts/Bundle_MacOS.sh index 7b5f6a0b..09bd9d03 100644 --- a/Scripts/Bundle_MacOS.sh +++ b/Scripts/Bundle_MacOS.sh @@ -3,6 +3,7 @@ BIN_DIR=$1; shift VERSION=$1; shift ARCH=$1; shift +SIGN_WITH_KEY=$1; shift if [ -z "$BIN_DIR" ] then @@ -28,12 +29,9 @@ then exit fi -contains() { case "$1" in *"$2"*) true ;; *) false ;; esac } - -if ! contains "$BIN_DIR" $ARCH +if [ "$SIGN_WITH_KEY" != "true" ] then - echo "This script must be called with a Libation binaries for ${ARCH}." - exit + echo "[WARNING] App will fail Gatekeeper verification without valid Apple Team information." fi BUNDLE=./Libation.app @@ -74,6 +72,16 @@ mv $BUNDLE_MACOS/libation.icns $BUNDLE_RESOURCES/libation.icns echo "Moving Info.plist file..." mv $BUNDLE_MACOS/Info.plist $BUNDLE_CONTENTS/Info.plist +echo "Moving Libation_DS_Store file..." +mv $BUNDLE_MACOS/Libation_DS_Store ./Libation_DS_Store + +echo "Moving background.png file..." +mv $BUNDLE_MACOS/background.png ./background.png + +echo "Moving background.png file..." +mv $BUNDLE_MACOS/Libation.entitlements ./Libation.entitlements +ENTITLEMENTS="./Libation.entitlements" + PLIST_ARCH=$(echo $ARCH | sed 's/x64/x86_64/') echo "Set LSArchitecturePriority to $PLIST_ARCH" sed -i -e "s/ARCHITECTURE_STRING/$PLIST_ARCH/" $BUNDLE_CONTENTS/Info.plist @@ -81,27 +89,40 @@ sed -i -e "s/ARCHITECTURE_STRING/$PLIST_ARCH/" $BUNDLE_CONTENTS/Info.plist echo "Set CFBundleVersion to $VERSION" sed -i -e "s/VERSION_STRING/$VERSION/" $BUNDLE_CONTENTS/Info.plist - delfiles=('MacOSConfigApp' 'MacOSConfigApp.deps.json' 'MacOSConfigApp.runtimeconfig.json') - for n in "${delfiles[@]}" do echo "Deleting $n" rm $BUNDLE_MACOS/$n done -APP_FILE=Libation.${VERSION}-macOS-chardonnay-${ARCH}.tgz +DMG_FILE="Libation.${VERSION}-macOS-chardonnay-${ARCH}.dmg" -echo "Signing executables in: $BUNDLE" -codesign --force --deep -s - $BUNDLE +all_identities=$(security find-identity -v -p codesigning) +identity=$(echo ${all_identities} | sed -n 's/.*"\(.*\)".*/\1/p') -echo "Creating app bundle: $APP_FILE" -tar -czvf $APP_FILE $BUNDLE +if [ "$SIGN_WITH_KEY" == "true" ]; then + echo "Signing executables in: $BUNDLE" + codesign --force --deep --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "${identity}" "$BUNDLE" + codesign --verify --verbose "$BUNDLE" +else + echo "Signing with empty key: $BUNDLE" + codesign --force --deep -s - $BUNDLE +fi -mkdir bundle -echo "moving to ./bundle/$APP_FILE" -mv $APP_FILE ./bundle/$APP_FILE +echo "Creating app disk image: $DMG_FILE" +mkdir Libation +mv $BUNDLE ./Libation/$BUNDLE +mv Libation_DS_Store Libation/.DS_Store +mkdir Libation/.background +mv background.png Libation/.background/ +ln -s /Applications "./Libation/ " +mkdir ./bundle +hdiutil create -srcFolder ./Libation -o "./bundle/$DMG_FILE" -rm -r $BUNDLE +if [ "$SIGN_WITH_KEY" == "true" ]; then + echo "Signing $DMG_FILE" + codesign --deep --sign "${identity}" "./bundle/$DMG_FILE" +fi echo "Done!" diff --git a/Scripts/Bundle_Redhat.sh b/Scripts/Bundle_Redhat.sh index 05d27ac6..e79009f9 100644 --- a/Scripts/Bundle_Redhat.sh +++ b/Scripts/Bundle_Redhat.sh @@ -28,14 +28,6 @@ then exit fi -contains() { case "$1" in *"$2"*) true ;; *) false ;; esac } - -if ! contains "$BIN_DIR" "$ARCH" -then - echo "This script must be called with a Libation binaries for ${ARCH}." - exit -fi - BASEDIR=$(pwd) delfiles=('LinuxConfigApp' 'LinuxConfigApp.deps.json' 'LinuxConfigApp.runtimeconfig.json') diff --git a/Source/LoadByOS/MacOSConfigApp/Info.plist b/Source/LoadByOS/MacOSConfigApp/Info.plist index b9d85062..9452340a 100644 --- a/Source/LoadByOS/MacOSConfigApp/Info.plist +++ b/Source/LoadByOS/MacOSConfigApp/Info.plist @@ -1,7 +1,6 @@ - CFBundleExecutable Libation @@ -19,17 +18,5 @@ libation.icns CFBundleVersion VERSION_STRING - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.disable-library-validation - - com.apple.security.cs.disable-executable-page-protection - - com.apple.security.automation.apple-events - \ No newline at end of file diff --git a/Source/LoadByOS/MacOSConfigApp/Libation.entitlements b/Source/LoadByOS/MacOSConfigApp/Libation.entitlements new file mode 100644 index 00000000..61d4c457 --- /dev/null +++ b/Source/LoadByOS/MacOSConfigApp/Libation.entitlements @@ -0,0 +1,20 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.automation.apple-events + + + diff --git a/Source/LoadByOS/MacOSConfigApp/Libation_DS_Store b/Source/LoadByOS/MacOSConfigApp/Libation_DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8134a5e7328c75e185dc4c9776f56524506fb3a2 GIT binary patch literal 14340 zcmeHNUu;`f8UL>9EOyf+wv#TY+I3g*K#_?5&dt9~!f~98Kv}A|?HbxH@t+&l#J<=R4{3i#tTv(cws_fLI?%zfk;TSNIdLeLP$d(9(h_N1VW+$e&4<4#LkUf zQlMzC`zhz1-*^6>@7#0G`F=4GDXFzWj3`P(9t4hkCy0i7h*X4D;d~B<}gomP-y(3*Ui<6SHV&~~tz_Gw#3&7{cUJI{hYI@nwi>5}@Lt)BMmh!Yp zMXHfOYot?Qu59Ej51)6b>prUb|89!eaEDsCje1qo`bn-@F4Y^+=&uylF?ZKf-JWhw zkLP;khOv=pWE*SsRJL}NwTp&P&PkljT`p-GOTK|=LvLhDx>hqQlnNS(Tzj>o7mSUR zv8EU5X5EaH;qiLBOTJTETj%2ABWf&`*d9^0Vu(l7vFOD1w%2nq7Q|+mFM-8(P$Wz14EdrWQ*EVxsZM2rO^y6xNtu>XrX=4MsD_f}ZfjJzRyi|u3 zCo8$Ne707a+|Qk~4X2mRQg6F`h}~Jmek@WS1#oU&0&Y+Vp-dVTkoHNlhluDQvfo3* z)BTvt|r1Wp3~Qec-#^nKAl7qBX@4>&5YA9z{d0B};^ ze&7oNtH5^zjsiaLMRV$eSzyl&(d9PXC2h6q?(&25low>)ct5>Lw9lVaf zJGyQ^ad8q8E$~-He0NUJdF*>Wsd@h!s1*jTQuW|TjU7z%#iP_K7h{>cQK|CCPYl+- z#Zjj|Dn>dj&UJoSUVbZgZ|c$I3y)R4dZT45&pklXjyM)@EZ|tcv4CR%#{&Nm3-E1O zA@$&WLHQw4S6l82U4zk7vm@w6!%Bn;20O6Q&n`?%ddj z8XtdQd)w3M#EV-t-z-hBJMrw~Vq{ z_Px)Sa#^Md%q2MdNIg;CyVqs&y?eq0CBQ5RP9dGI)@h)N%haWSB z5CaQQF?q;&$^hr-2DBPD4)%3);7z37q)|$sbOB{Mb0W!3oXC;KYhz2;2MZ<_Evp5S zQ49E7L22zaJe5gqfo542Wh|QI3vm1lFaU4R+w^0)50d5g^k>DRJfjGj#hrA|xfk3Q z-Phf(xea&Kz2;uGTIfWxxNjlf@&6tF-z2Zv`TzViizY**E_Ep0T>i6dJe~ z@nW;mQTFhv$+r#ds*-IJpE!$sLSJ&P@lOu;oNoC<{>$uJ-LQrw87#?uN&S{ckou0$ zeLRLovv05beC*v_$!5uGMPC~$F#C3j+iPLi?4NgLyW|*1^)cDlWZCZJ=RX^`+y6Yb zfsRtMqZ6r#@tM$6JQ@!r#?!N*soD5cC_OtfJwBRRwZ55jW3A7!?a8B1n6c}-Z@X3TcFF&`FYJFf|BXFD4ro!QPad~b(zsYI{K^1ycm z_5;5sFteTS2+VBfp1>;bLxJsV=WVit*-lkd( xVcrW6o97=CzMPFC> + + Always + Always Always + + Always + + + Always + Always + + Always + \ No newline at end of file diff --git a/Source/LoadByOS/MacOSConfigApp/background.png b/Source/LoadByOS/MacOSConfigApp/background.png new file mode 100644 index 0000000000000000000000000000000000000000..c74f1ae57b9c2ee85f74c5939ed4b927281371f4 GIT binary patch literal 12463 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 LRj%aeoA>_<8yuhB literal 0 HcmV?d00001