fix: Sign & notarize on Apple platforms

Changelog:

- Sign & notarize Recyclarr on macOS platforms (arm64, x64)
- Use `tar.xz` instead of `zip` on mac & linux platforms
- Compile linux binaries on the ubuntu-latest Github runner
- Compile macOS binaries on the macos-latest Github runner
- Executable size reduced by disabling ReadyToRun

Fixes #39
snyk
Robert Dailey 1 year ago
parent 08e7323835
commit 6ed4c7ca42

@ -20,83 +20,66 @@ on:
- "docker/**"
- "ci/**"
env:
dotnetVersion: "7.0.x"
jobs:
test:
name: Test
build-win:
name: Build Windows
secrets: inherit
uses: ./.github/workflows/reusable-build.yml
strategy:
fail-fast: true
matrix:
os:
- windows-latest
- ubuntu-latest
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Source Code
uses: actions/checkout@v3
with:
fetch-depth: 0 # avoid shallow clone for GitVersion
- name: Setup .NET Core SDK ${{ env.dotnetVersion }}
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ env.dotnetVersion }}
runtime: [win-x64, win-arm64]
with:
platform: windows-latest
runtime: ${{ matrix.runtime }}
- name: Test
run: dotnet test src --configuration Release --logger GitHubActions
build-linux:
name: Build Linux
secrets: inherit
uses: ./.github/workflows/reusable-build.yml
strategy:
matrix:
runtime: [linux-x64, linux-arm64, linux-arm]
with:
platform: ubuntu-latest
runtime: ${{ matrix.runtime }}
build:
name: Build Non-MUSL
needs: test
build-osx:
name: Build Mac OS
secrets: inherit
uses: ./.github/workflows/reusable-build.yml
strategy:
matrix:
runtime: [osx-x64, osx-arm64]
with:
platform: macos-latest
runtime: ${{ matrix.runtime }}
# Compression cannot be used on MacOS due to this issue:
# https://github.com/dotnet/runtime/issues/79267
publish-args: -NoCompress
build-musl:
name: Build MUSL
secrets: inherit
uses: ./.github/workflows/reusable-build.yml
strategy:
matrix:
runtime: [linux-musl-x64, linux-musl-arm, linux-musl-arm64]
with:
platform: ubuntu-latest
runtime: ${{ matrix.runtime }}
publish-args: -NoSingleFile
skip-test: true
codesign:
name: Apple Signing
runs-on: macos-latest
if: github.event_name != 'pull_request'
needs: [build-osx]
strategy:
fail-fast: true
matrix:
runtime:
- win-x64
- win-arm64
- linux-x64
- linux-arm
- linux-arm64
- osx-x64
- osx-arm64
# Must run on Windows so that version info gets properly set in host EXE. See:
# https://github.com/dotnet/runtime/issues/3828
runs-on: windows-latest
steps:
- name: Checkout Source Code
uses: actions/checkout@v3
with:
fetch-depth: 0 # avoid shallow clone for GitVersion
- name: Setup .NET Core SDK ${{ env.dotnetVersion }}
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ env.dotnetVersion }}
- name: Publish
shell: pwsh
run: ci/Publish.ps1 -Runtime ${{ matrix.runtime }}
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: recyclarr-${{ matrix.runtime }}
path: publish/${{ matrix.runtime }}/*
smoke:
name: Smoke
needs: build
strategy:
fail-fast: false
matrix:
include:
- { os: windows-latest, runtime: win-x64 }
- { os: ubuntu-latest, runtime: linux-x64 }
- { os: macos-latest, runtime: osx-x64 }
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
@ -104,58 +87,66 @@ jobs:
- name: Download Artifacts
uses: actions/download-artifact@v3
with:
name: recyclarr-${{ matrix.runtime }}
- name: Run Smoke Test
shell: pwsh
run: ci/SmokeTest.ps1 ./recyclarr
name: ${{ matrix.runtime }}
path: publish
# NOTE: This is duplicated from the 'build' job. Sadly, reusable workflows cannot be invoked from
# matrix jobs. See here:
# https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations
musl:
name: Build MUSL
needs: test
strategy:
fail-fast: true
matrix:
runtime:
- linux-musl-x64
- linux-musl-arm
- linux-musl-arm64
runs-on: windows-latest
steps:
- name: Checkout Source Code
uses: actions/checkout@v3
- name: Add Cert to Keychain
uses: apple-actions/import-codesign-certs@v1
with:
fetch-depth: 0 # avoid shallow clone for GitVersion
p12-file-base64: ${{ secrets.MAC_CERT_BASE64 }}
p12-password: ${{ secrets.MAC_CERT_PASSWORD }}
- name: Setup .NET Core SDK ${{ env.dotnetVersion }}
uses: actions/setup-dotnet@v3
- name: Code Sign
env:
CODESIGN_IDENTITY: ${{ secrets.MAC_CODESIGN_IDENTITY }}
run: >
codesign --timestamp --no-strict --force
--options=runtime
--entitlements ci/codesign/entitlements.plist
--sign "$CODESIGN_IDENTITY"
"publish/recyclarr"
- name: Notarize
uses: recyclarr/xcode-notarize@main
with:
dotnet-version: ${{ env.dotnetVersion }}
product-path: publish/recyclarr
appstore-connect-username: ${{ secrets.MAC_DEV_USERNAME }}
appstore-connect-password: ${{ secrets.MAC_DEV_PASSWORD }}
primary-bundle-id: dev.recyclarr.cli
- name: Publish
shell: pwsh
run: ci/Publish.ps1 -Runtime ${{ matrix.runtime }} -NoSingleFile
# Cannot staple directly to a binary:
# https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow?language=objc#3087720
# - name: Staple
# run: xcrun stapler staple -v publish/recyclarr
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: recyclarr-${{ matrix.runtime }}
path: publish/${{ matrix.runtime }}/*
name: ${{ matrix.runtime }}
path: publish/*
docker:
name: Docker
needs: [build-musl]
uses: ./.github/workflows/reusable-docker.yml
secrets: inherit
release:
name: Release
needs: [smoke, musl]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs:
- build-win
- build-linux
- codesign # Depends on build-osx
- docker # Only for preventing a release if docker build & publish fails
env:
XZ_OPT: "-T0 -9"
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0 # avoid shallow clone for GitVersion
# token: ${{ secrets.GITHUB_TOKEN }} # Allows git push
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0
@ -171,9 +162,12 @@ jobs:
with:
path: publish
- name: Create Zip Files
- name: Create Archive
shell: pwsh
run: ci/CreateZip.ps1 publish
run: >
ci/CreateArchive.ps1
-PublishDir publish
-OutputDir archive
- name: Extract Changelog
id: changelog
@ -184,28 +178,30 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.DEPLOY_PAT }}
with:
files: publish-zip/recyclarr-*.zip
files: archive/*
body: ${{ steps.changelog.outputs.release_notes }}
tag_name: ${{ github.event.create.ref }}
draft: false
prerelease: ${{ steps.gitversion.outputs.preReleaseTag != '' }}
docker:
name: Docker
needs: musl
uses: ./.github/workflows/docker.yml
secrets: inherit
# The main purpose of this job is to group all the other jobs together into one single job status
# that can be set as a requirement to merge pull requests. This is easier than enumerating all
# jobs in a workflow to ensure they all pass.
check:
if: always()
name: Report Build Status
needs: [build, smoke]
needs:
- build-win
- build-linux
- build-osx
- build-musl
- codesign
- docker
- release
runs-on: ubuntu-latest
steps:
- name: Check if all jobs succeeded
uses: re-actors/alls-green@release/v1
with:
allowed-skips: codesign, release
jobs: ${{ toJSON(needs) }}

@ -11,9 +11,6 @@ on:
- "**.md"
- .github/workflows/markdown-lint.yml
env:
dotnetVersion: "7.0.x"
jobs:
markdownlint:
name: Markdown Lint

@ -0,0 +1,54 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
on:
workflow_call:
inputs:
platform:
type: string
required: true
runtime:
type: string
required: true
publish-args:
type: string
skip-test:
type: boolean
env:
dotnetVersion: "7.0.x"
jobs:
build:
name: Build, Test, Smoke
# Windows version info missing? See this:
# https://github.com/dotnet/runtime/issues/3828
runs-on: ${{ inputs.platform }}
steps:
- name: Checkout Source Code
uses: actions/checkout@v3
with:
fetch-depth: 0 # avoid shallow clone for GitVersion
- name: Setup .NET Core SDK ${{ env.dotnetVersion }}
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ env.dotnetVersion }}
- name: Test
if: endsWith(inputs.runtime, 'x64') && !inputs.skip-test
run: dotnet test src -c Release --logger GitHubActions
- name: Publish
shell: pwsh
run: |
ci/Publish.ps1 -Runtime ${{ inputs.runtime }} ${{ inputs.publish-args }}
- name: Smoke
if: endsWith(inputs.runtime, 'x64') && !inputs.skip-test
shell: pwsh
run: ci/SmokeTest.ps1 publish/${{ inputs.runtime }}/recyclarr
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.runtime }}
path: publish/${{ inputs.runtime }}/*

@ -23,7 +23,7 @@
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"-o",
"${workspaceFolder}/docker/artifacts/recyclarr-${config:recyclarr.runtime}"
"${workspaceFolder}/docker/artifacts/${config:recyclarr.runtime}"
],
"problemMatcher": "$msCompile"
},

@ -11,6 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Docker: Explicit `init` is no longer required in Docker Compose. It is now built into the image.
- Reduced size of the `recyclarr` executable
- macOS & linux are now released as `tar.xz` archives instead of `zip`.
### Fixed
- Fix CoreCLR / "killed" crash on Apple macOS platforms (#39). This was accomplished by properly
signing and notarizing Recyclarr.
## [4.0.0] - 2022-12-11

@ -0,0 +1,36 @@
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string] $PublishDir,
[Parameter(Mandatory = $true)]
[string] $OutputDir,
[string] $ArchiveDirName
)
$ErrorActionPreference = "Stop"
$archiveTargets = @()
if ($ArchiveDirName) {
$archiveTargets += "$PublishDir/$ArchiveDirName"
}
else {
$archiveTargets += Get-ChildItem -Path $PublishDir -Directory -Name
}
New-Item -ItemType Directory -Force -Path $OutputDir
$OutputDir = Resolve-Path $OutputDir
foreach ($dir in $archiveTargets) {
$archiveName = "recyclarr-$dir"
if ($dir.StartsWith("win-")) {
"> Zipping: $dir"
Compress-Archive "$PublishDir/$dir/*" "$OutputDir/$archiveName.zip" -Force
}
else {
"> Tarballing: $dir"
Push-Location "$PublishDir/$dir"
tar cJvf "$archiveName.tar.xz" *
Move-Item "$archiveName.tar.xz" $OutputDir
Pop-Location
}
}

@ -1,16 +0,0 @@
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string] $RootPath
)
$ErrorActionPreference = "Stop"
$ZipPath = "$RootPath-zip"
"Zip the published files to: $ZipPath"
New-Item -ItemType Directory -Force -Path $ZipPath
$dirs = Get-ChildItem -Path $RootPath -Directory -Name
foreach ($dir in $dirs) {
"> Zipping: $RootPath\$dir"
Compress-Archive $RootPath\$dir\* $ZipPath\$dir.zip -Force
}

@ -0,0 +1,15 @@
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string] $Arch
)
if ($IsWindows) {
"win-$Arch"
}
elseif ($IsLinux) {
"linux-$Arch"
}
elseif ($IsMacOS) {
"osx-$Arch"
}

@ -2,42 +2,55 @@
param (
[Parameter(Mandatory = $true)]
[string] $Runtime,
[string] $OutputDir,
[string] $Configuration = "Release",
[string] $BuildPath = "src\Recyclarr.Cli",
[switch] $NoSingleFile
[switch] $NoSingleFile,
[switch] $NoCompress,
[switch] $ReadyToRun
)
$ErrorActionPreference = "Stop"
$extraArgs = @()
if ($ReadyToRun) {
$extraArgs += @(
"-p:PublishReadyToRunShowWarnings=true"
"-p:PublishReadyToRunComposite=true"
"-p:TieredCompilation=false"
)
}
if (-not $NoSingleFile) {
$selfContained = "true"
$singleFileArgs = @(
$extraArgs += @(
"--self-contained=true"
"-p:PublishSingleFile=true"
"-p:IncludeNativeLibrariesForSelfExtract=true"
"-p:PublishReadyToRunComposite=true"
"-p:PublishReadyToRunShowWarnings=true"
"-p:EnableCompressionInSingleFile=true"
)
}
else {
$selfContained = "false"
$extraArgs += @(
"--self-contained=false"
)
}
if (-not $NoCompress) {
$extraArgs += @(
"-p:EnableCompressionInSingleFile=true"
)
}
if (-not $OutputDir) {
$OutputDir = "publish\$Runtime"
}
"Extra Args: $extraArgs"
dotnet publish $BuildPath `
--output $OutputDir `
--configuration $Configuration `
--runtime $Runtime `
--self-contained $selfContained `
$singleFileArgs
@extraArgs
if ($LASTEXITCODE -ne 0) {
throw "dotnet publish failed"

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>

@ -15,7 +15,7 @@ Remove-Item $artifactsDir -Recurse -Force -ErrorAction SilentlyContinue
Push-Location $PSScriptRoot\..
try {
& .\ci\Publish.ps1 -NoSingleFile `
-OutputDir "$artifactsDir\recyclarr-$Runtime" `
-OutputDir "$artifactsDir\$Runtime" `
-Runtime $Runtime
}
finally {

@ -9,7 +9,7 @@ case "$TARGETPLATFORM" in
*) echo >&2 "ERROR: Unsupported target platform: $TARGETPLATFORM"; exit 1 ;;
esac
path="artifacts/recyclarr-$runtime/"
path="artifacts/$runtime/"
mv "$path" publish

Loading…
Cancel
Save