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

Homebrew cask #1068

Open
jfenske89 opened this issue Dec 5, 2024 · 10 comments
Open

Homebrew cask #1068

jfenske89 opened this issue Dec 5, 2024 · 10 comments
Labels
enhancement New feature or request

Comments

@jfenske89
Copy link

Is your feature request related to a problem? Please describe.
Libation is not available on Homebrew. This is very nice to manage updates.

Describe the solution you'd like
Add a Homebrew cask.

Describe alternatives you've considered
Manual install :(

Additional context
I started a Cask. But the brew audit didn't seem to "like" the pre-releases. Also the app is not signed. I searched and saw some comments about the Apple extortion lol What if there was a donation to cover that?

cask "libation" do
  arch arm: "arm64", intel: "x64"

  version "11.6.2"
  sha256 arm: "966a7fd9104248ff266d6a1d84674c39009ba8ed7f1818daec455af2b9d7f6bf",
         intel: "7659791b4712aaa24b1e4b47be7567f138f74856f03ea564a278e3d6a9e91adb"

  url "https://github.com/rmcrackan/Libation/releases/download/v#{version}/Libation.#{version}-macOS-chardonnay-#{arch}.tgz"
  name "Libation"
  desc "Libation is a free, open source audible library manager. Decrypt, backup, organize, and search your audible library."
  homepage "https://github.com/rmcrackan/Libation"

  livecheck do
    url :url
    regex(/^Libation\.v?(\d+(?:\.\d+)+)-*macOS.*#{arch}.*tgz$/i)
    strategy :github_releases do |json, regex|
      json.map do |release|
        next if release["draft"]

        release["assets"]&.map do |asset|
          match = asset["name"]&.match(regex)
          next if match.blank?

          match[1]
        end
      end.flatten
    end
  end

  auto_updates true
  depends_on macos: ">= :catalina"

  app "Libation.app"
end

Audit results:

audit for libation: failed
 - Version '11.6.2' differs from '11.1.0' retrieved by livecheck.
 - Version '11.6.2' differs from '11.1.0' retrieved by livecheck.
 - Signature verification failed:
/private/tmp/cask-audit20241205-97988-h9rst4/Libation.app: rejected

macOS on ARM requires software to be signed.
Please contact the upstream developer to let them know they should sign and notarize their software.

 - v11.6.2 is a GitHub pre-release.
libation
  * Version '11.6.2' differs from '11.1.0' retrieved by livecheck.
  * line 8, col 2: Signature verification failed:
    /private/tmp/cask-audit20241205-97988-h9rst4/Libation.app: rejected
    
    macOS on ARM requires software to be signed.
    Please contact the upstream developer to let them know they should sign and notarize their software.
  * line 8, col 2: v11.6.2 is a GitHub pre-release.
Error: 3 problems in 1 cask detected
@jfenske89 jfenske89 added the enhancement New feature or request label Dec 5, 2024
@jfenske89
Copy link
Author

I created a shell script to update from Github. So I will use that for now.

https://gist.github.com/jfenske89/e1b0d69eb2f9a7f3ef738386bba4d8db

@rmcrackan
Copy link
Owner

I'll be happy to be the one to push the button if someone else will do the work. For example, I offer docker builds but no part of that was actually done by me and it's not officially supported. This is a community supported feature which I'm happy to offer along side the official apps. If you can do the PRs for the homebrew casks, I can approve them. I love how the community has taken ownership of the increasingly specific technologies which help spread Libation around.

RE Apple's extortion/fee: I'm not opposed to this either with the same stipulations and if there are some people to help fund it. The logistics of this one get ugly since I'm not on a mac. I don't even know how to sign an app for apple. I assume xcode is involved. What really needs to happen is for an actual knowledgeable apple/mac developer to take interest. I don't think simply collecting $99/yr is going to cut it -- I just don't have the tools or knowledge.

@jfenske89
Copy link
Author

jfenske89 commented Dec 7, 2024

I will experiment with some cloud services, such as CircleCI - which might be able to build and sign with a provided key, without the need for a Mac device.

Edit - actually should be able to continue using Github actions, and add a section to the existing build config for signing the MacOS app. Still researching and experimenting...

@jfenske89
Copy link
Author

Need to $ubscribe as an Apple developer first. Then create and download a certificate. Use a guide like this to create a p12 file from that - https://calvium.com/how-to-make-a-p12-file/

Next add some action secrets to the repository:

  • CERTIFICATES_P12 (base64 version of the p12 file)
  • CERTIFICATES_P12_PASSWORD (password used to create the p12 file)
  • APPLE_TEAM_ID (from the Apple Developer account page)

Next update the Github workflow to use https://github.com/Apple-Actions/import-codesign-certs for importing that p12 key.

Afterwards the Scripts/Bundle_MacOS.sh file needs to be updated to run codesign with the key file. It needs to zip the bundle instead of creating a tarball. Then it should notarize and staple the zip file.

I was having issues with this, obviously doing something wrong. This lead to a frustrating day. I will try to pick this up again sometime later.

@rmcrackan
Copy link
Owner

Thank you very much for funding the apple dev subscription. December is a nutty time for everyone so I'm not going to jump on this immediately. I don't want to start the first subscription year and then watch a month or more slip by because I was too busy to complete these steps.

@jfenske89
Copy link
Author

No problem. There isn't any rush on this. I will have some time to give this another shot. I was hoping this was going to be an easy learning experience for me 😆

@LeeNX
Copy link

LeeNX commented Jan 10, 2025

Something I might be able to help with, where you stuck?

@rmcrackan
Copy link
Owner

Something I might be able to help with, where you stuck?

@LeeNX

To be perfectly blunt: this isn't something I want to do; I want someone else to do it. (I don't even know what a homebrew cask is aside from the fact that it's something to do with macos, which I also don't use.) Ideally, that person would do everything themselves that they can (preferably with a PR), and would write explicit step-by-step instructions for the pieces that I must perform myself. Also, I don't intend to add more manual steps to my build habits, so if something needs to be done during every build of Libation, they're going to need to figure out how to create/modify the build workflow to automate it. Oh yeah, and adding documentation to help other mac users know what to do with this.

Other complicating factors: since I don't own a mac, it's possible that I can't run some of the required setup. I also don't have an apple developer subscription -- I have money ear-marked for this purpose though if needed.

In the best case scenario, everything above gets sorted out and this all works and I'd add a disclaimer similar to docker's that it's not officially supported. (Since there's no way for me to do so. Again: no mac) Even with the docker disclaimer, I get tons of docker questions; I'm sure this will be similar.

Sorry if this sounds pissy; I don't intend it to be. It's just that this is other people's nice-to-have which I'll never see any personal benefit from (albeit this would presumably be good for other users) so I'm not in any hurry to carve out time to figure it out. This ticket's author seems very knowledgeable and would likely be a good resource.

@jfenske89
Copy link
Author

@LeeNX I meant to get back to this, but haven't yet. I added a step to sign with an Apple team certificate and "staple" whatever that means lol

I was having issues with the secrets. I am new to Github actions. I tried with "repository secrets" and lastly with a "production" environment that I created in the repository. The secrets seem to be empty no matter what I tried.

Besides that, I don't know if the bundle changes actually work. I am sure someone with $99 to spare and more experience can figure it out faster than me 😂

Required secrets:

  • CERTIFICATES_P12
  • CERTIFICATES_P12_PASSWORD
  • APPLE_TEAM_ID
  • APPLE_TEAM_EMAIL

New file, build-mac.yaml (with debugging at the top which should be removed):

# build-mac.yml
# Reusable workflow that builds the MacOS (x64 and arm64) versions of Libation.
---
name: build

on:
  workflow_call:
    inputs:
      version_override:
        type: string
        description: "Version number override"
        required: false
      run_unit_tests:
        type: boolean
        description: "Skip running unit tests"
        required: false
        default: true
      runs_on:
        type: string
        description: "The GitHub hosted runner to use"
        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: "MacOS-${{ inputs.architecture }}"
    runs-on: ${{ inputs.runs_on }}
    environment: production
    steps:
      - name: Print environment variables
        run: |
          echo "DOTNET_CONFIGURATION=${{ env.DOTNET_CONFIGURATION }}"
          echo "DOTNET_VERSION=${{ env.DOTNET_VERSION }}"
          echo "RELEASE_NAME=${{ env.RELEASE_NAME }}"
          echo "CERTIFICATES_P12 length=${#CERTIFICATES_P12}"
          echo "CERTIFICATES_P12_PASSWORD length=${#CERTIFICATES_P12_PASSWORD}"
          echo "APPLE_TEAM_ID length=${#APPLE_TEAM_ID}"
          echo "APPLE_TEAM_EMAIL ${APPLE_TEAM_EMAIL}"
        env:
          CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
          CERTIFICATES_P12_PASSWORD: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          APPLE_TEAM_EMAIL: ${{ secrets.APPLE_TEAM_EMAIL }}

      - uses: actions/checkout@v4
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}
        env:
          NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Import Code-Signing Certificates
        uses: apple-actions/import-codesign-certs@v3
        with: 
          p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
          p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}

      - name: Get version
        id: get_version
        run: |
          inputVersion="${{ inputs.version_override }}"
          if [[ "${#inputVersion}" -gt 0 ]]
          then
            version="${inputVersion}"
          else
            version="$(grep -Eio -m 1 '<Version>.*</Version>' ./Source/AppScaffolding/AppScaffolding.csproj | sed -r 's/<\/?Version>//g')"
          fi
          echo "version=${version}" >> "${GITHUB_OUTPUT}"

      - name: Unit test
        if: ${{ inputs.run_unit_tests }}
        working-directory: ./Source
        run: dotnet test

      - name: Publish
        id: publish
        working-directory: ./Source
        run: |
          display_os="macOS"
          RUNTIME_ID="osx-${{ inputs.architecture }}"

          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

      - 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_MacOS.sh
          chmod +rx ${SCRIPT}
          ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ inputs.architecture }}" "${{ secrets.APPLE_TEAM_ID }}" "${{ secrets.APPLE_TEAM_EMAIL }}"
          artifact=$(ls ./bundle)
          echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"

      - name: Publish bundle
        uses: actions/upload-artifact@v4
        with:
          name: ${{ steps.bundle.outputs.artifact }}
          path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }}
          if-no-files-found: error
          retention-days: 7

Updated Scripts/Bundle_MacOS.sh (includes debugging that may need to be deleted):

#!/bin/bash

BIN_DIR=$1; shift
VERSION=$1; shift
ARCH=$1; shift
APPLE_TEAM_ID=$1; shift
APPLE_TEAM_EMAIL=$1; shift

if [ -z "$BIN_DIR" ]
then
  echo "This script must be called with a the Libation macos bins directory as an argument."
  exit
fi

if [ ! -d "$BIN_DIR" ]
then
  echo "The directory \"$BIN_DIR\" does not exist."
  exit
fi

if [ -z $VERSION ]
then
  echo "This script must be called with the Libation version number as an argument."
  exit
fi

if [ -z $ARCH ]
then
  echo "This script must be called with the Libation cpu architecture as an argument."
  exit
fi

if [ -z $APPLE_TEAM_ID ] || [ -z $APPLE_TEAM_EMAIL ]
then
  echo "[WARNING] App will fail Gatekeeper verification without valid Apple Team information."
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

BUNDLE=./Libation.app
echo "Bundle dir: $BUNDLE"

if [[ -d $BUNDLE ]]
then
  echo "$BUNDLE directory already exists, aborting."
  exit
fi

BUNDLE_CONTENTS=$BUNDLE/Contents
echo "Bundle Contents dir: $BUNDLE_CONTENTS"

BUNDLE_RESOURCES=$BUNDLE_CONTENTS/Resources
echo "Resources dir: $BUNDLE_RESOURCES"

BUNDLE_MACOS=$BUNDLE_CONTENTS/MacOS
echo "MacOS dir: $BUNDLE_MACOS"

mkdir -p $BUNDLE_CONTENTS
mkdir -p $BUNDLE_RESOURCES
mkdir -p $BUNDLE_MACOS

mv "${BIN_DIR}/"*  $BUNDLE_MACOS

if [ $? -ne 0 ]
 then echo "Error moving ${BIN_DIR} files"
 exit
fi

echo "Make fileicon executable..."
chmod +x $BUNDLE_MACOS/fileicon

echo "Moving icon..."
mv $BUNDLE_MACOS/libation.icns $BUNDLE_RESOURCES/libation.icns

echo "Moving Info.plist file..."
mv $BUNDLE_MACOS/Info.plist $BUNDLE_CONTENTS/Info.plist

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

echo "Set CFBundleVersion to $VERSION"
sed -i -e "s/VERSION_STRING/$VERSION/" $BUNDLE_CONTENTS/Info.plist


delfiles=( 'libmp3lame.arm64.so' 'libmp3lame.x64.so' 'libmp3lame.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.arm64.so' 'ffmpegaac.x64.so' 'ffmpegaac.x64.dll' 'ffmpegaac.x86.dll' 'MacOSConfigApp' 'MacOSConfigApp.deps.json' 'MacOSConfigApp.runtimeconfig.json')
if [[ "$ARCH" == "arm64" ]]
then
  delfiles+=('libmp3lame.x64.dylib' 'ffmpegaac.x64.dylib')
  mv $BUNDLE_MACOS/ffmpegaac.arm64.dylib  $BUNDLE_MACOS/ffmpegaac.dylib
  mv $BUNDLE_MACOS/libmp3lame.arm64.dylib  $BUNDLE_MACOS/libmp3lame.dylib
else
  delfiles+=('libmp3lame.arm64.dylib' 'ffmpegaac.arm64.dylib')
  mv $BUNDLE_MACOS/ffmpegaac.x64.dylib  $BUNDLE_MACOS/ffmpegaac.dylib
  mv $BUNDLE_MACOS/libmp3lame.x64.dylib  $BUNDLE_MACOS/libmp3lame.dylib
fi


for n in "${delfiles[@]}"
do
  echo "Deleting $n"
  rm $BUNDLE_MACOS/$n
done

APP_FILE=Libation.${VERSION}-macOS-chardonnay-${ARCH}.zip

all_identities=$(security find-identity -v -p codesigning)
identity=$(echo ${all_identities} | sed -n 's/.*"\(.*\)".*/\1/p')

if [ "$APPLE_TEAM_ID" != "" ]; then
  echo "Signing executables in: $BUNDLE"
  # set -e
  set -x
  codesign --force --deep --sign "${identity}" $BUNDLE
  echo "Exit code: $?"
  codesign -dv --verbose=4 $BUNDLE
  echo "Exit code: $?"
  set +x
  # set +e
fi

echo "Creating app bundle: $APP_FILE"
zip -r $APP_FILE $BUNDLE

if [ "$APPLE_TEAM_ID" != "" ]; then
  echo "Notarizing: $APP_FILE"
  # set -e
  set -x
  # xcrun notarytool submit "${APP_FILE}" --wait --team-id ${APPLE_TEAM_ID}
  xcrun notarytool store-credentials --apple-id "${APPLE_TEAM_EMAIL}" --team-id "${APPLE_TEAM_ID}"
  echo "Exit code: $?"
  xcrun stapler staple "${APP_FILE}"
  echo "Exit code: $?"
  set +x
  # set +e
fi

mkdir bundle
echo "moving to ./bundle/$APP_FILE"
mv $APP_FILE ./bundle/$APP_FILE

rm -r $BUNDLE

echo "Done!"

@LeeNX
Copy link

LeeNX commented Jan 13, 2025

Thanks @rmcrackan , I totally get it. I feel the same way about Windows ... ;-).

I don't think you been pissy, I think you are been honest and to the point. Who has time to beat around the bush on how little time we have to give away?

I think most people are offering to help, even as little as they can and where they can. I think that is a big thing for FOSS. Not everybody knows everything and if enough people are interested in something, they can pool their knowledge and resources and hopefully get to a point the mass of people want.

My counter offer to this gives me no benefits but there will be an increase in some people expecting support, securing this app with Apple code signing and notarization, should mean that others could not hijack the app for malware and try blame you, because the app would be secured with your Apple credentials.

My initial post was more geared to @jfenske89 , who looked to have something and I did not want to start from scratch. I have some GitHub actions plus Apple code signing and notarization experience and will to spare some time to help where I can.

So, thanks @jfenske89, any reason not to put this into a PR? I think I saw you say that your GitHub journey is new, I can possible help with this and point you to some helpful tutorials, plus you welcome to ask any questions and hopefully either myself or something else might be able to assist. I can move this into a PR and do some testing, but would not want to take all the credit (I think there is a way to co-author/commit PR, but I have not done this myself before - maybe something to learn?)

Two things that I think need to still be addressed, are their funds for the $99 per year Apple Developer Subscription? Second we have not yet got to the homebrew cask setup (I have not done this before, so I don't know what needs to be done here, but would be something worth investigating).

Looking forward to everybody's feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants