Skip to content

Build OpenSSL 3.5.7 via workflow_dispatch #101

Build OpenSSL 3.5.7 via workflow_dispatch

Build OpenSSL 3.5.7 via workflow_dispatch #101

Workflow file for this run

name: Build OpenSSL
run-name: Build OpenSSL ${{ inputs.version }} via ${{ github.event_name }}
on:
workflow_dispatch:
inputs:
build_type:
description: 'Build Source: OpenSSL Release or OpenSSL Branch/OpenSSL fork'
required: true
type: choice
options:
- release
- branch
default: release
version:
description: 'OpenSSL Release Version, OpenSSL Branch Name or OpenSSL Fork Repo(e.g. 3.4.0, master, or user/repo/branch)'
required: true
type: string
ignore_eol:
description: 'Ignore EOL Check'
required: false
type: boolean
default: false
keep_raw_artifacts:
description: 'Keep raw build artifacts'
required: false
type: boolean
default: false
workflow_call:
inputs:
build_type:
required: false
type: string
default: release
version:
required: true
type: string
ignore_eol:
required: false
type: boolean
default: false
keep_raw_artifacts:
required: false
type: boolean
default: false
jobs:
# =========================================================================
# 0. VALIDATE VERSION & EOL
# =========================================================================
validate-version:
name: Validate Inputs
runs-on: ubuntu-latest
permissions:
actions: write
outputs:
version: ${{ steps.check.outputs.version }}
target_repo: ${{ steps.check.outputs.target_repo }}
ref: ${{ steps.check.outputs.ref }}
sha: ${{ steps.check.outputs.sha }}
artifact_version: ${{ steps.check.outputs.artifact_version }}
slugified_version: ${{ steps.check.outputs.slugified_version }}
is_fork: ${{ steps.check.outputs.is_fork }}
steps:
- name: Check EOL or Branch Existence
id: check
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ inputs.version }}"
BUILD_TYPE="${{ inputs.build_type }}"
IGNORE_EOL="${{ inputs.ignore_eol }}"
TARGET_REPO="openssl/openssl"
IS_FORK="false"
if [ "$BUILD_TYPE" == "release" ]; then
MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2)
EOL_DATE=$(curl -s https://raw.githubusercontent.com/openssl/release-metadata/refs/heads/main/data.json | jq -r ".[\"$MAJOR_MINOR\"].eol")
EOL_DATE=$(echo "$EOL_DATE" | date -d "$EOL_DATE" +%s 2>/dev/null || date -d "01 $EOL_DATE" +%s 2>/dev/null || echo 0)
if [ -z "$EOL_DATE" ] || [ "$EOL_DATE" == "null" ]; then
echo "⚠️ Could not determine EOL date for $MAJOR_MINOR. Proceeding cautiously."
else
TODAY=$(date +%s)
if [[ "$TODAY" > "$EOL_DATE" ]]; then
echo "❌ OpenSSL $MAJOR_MINOR reached EOL on $(date -d "@$EOL_DATE" +%Y-%m-%d) ."
if [ "$IGNORE_EOL" != "true" ]; then
echo "Aborting build. Check 'Ignore EOL' to override."
exit 1
fi
echo "⚠️ Ignore EOL is checked. Proceeding anyway."
fi
fi
TARGET_REF="openssl-$VERSION"
echo "🔍 Resolving SHA for tag '$TARGET_REF'..."
SHA=$(git ls-remote --tags https://github.com/$TARGET_REPO.git "$TARGET_REF" | awk '{print $1}')
if [ -z "$SHA" ]; then
echo "❌ Tag '$TARGET_REF' not found in $TARGET_REPO."
exit 1
fi
ARTIFACT_VERSION="$VERSION"
SLUGIFIED_VERSION="$VERSION"
else
# Branch Mode
if [[ "$VERSION" == */*/* ]]; then
# Format: user/repo/branch
TARGET_REPO=$(echo "$VERSION" | cut -d'/' -f1,2)
TARGET_REF=$(echo "$VERSION" | cut -d'/' -f3-)
IS_FORK="true"
else
TARGET_REF="$VERSION"
fi
echo "🔍 Resolving SHA for branch/ref '$TARGET_REF' in repository '$TARGET_REPO'..."
SHA=$(git ls-remote https://github.com/$TARGET_REPO.git "$TARGET_REF" | awk '{print $1}')
if [ -z "$SHA" ]; then
# Check if it's already a SHA
if [[ "$TARGET_REF" =~ ^[0-9a-f]{40}$ ]]; then
SHA="$TARGET_REF"
else
echo "❌ Reference '$TARGET_REF' does not exist in $TARGET_REPO."
exit 1
fi
fi
TIMESTAMP=$(date -u +%Y%m%dT%H%M%SZ)
# Slugify the whole version input (e.g. user/repo/branch -> user_repo_branch)
SLUGIFIED_VERSION=$(echo "$VERSION" | sed 's/\//_/g')
# Truncate for filename safety
SAFE_PART=$(echo "$SLUGIFIED_VERSION" | cut -c 1-100)
ARTIFACT_VERSION="${SAFE_PART}_${TIMESTAMP}"
fi
# Output resolved information
echo "target_repo=$TARGET_REPO" >> $GITHUB_OUTPUT
echo "is_fork=$IS_FORK" >> $GITHUB_OUTPUT
echo "ref=$TARGET_REF" >> $GITHUB_OUTPUT
echo "sha=$SHA" >> $GITHUB_OUTPUT
echo "artifact_version=$ARTIFACT_VERSION" >> $GITHUB_OUTPUT
echo "slugified_version=$SLUGIFIED_VERSION" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
# =========================================================================
# 1. BUILD COMMON ASSETS (Headers & Docs)
# =========================================================================
build-common-assets:
name: Build Headers & Docs
needs: validate-version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
repository: ${{ needs.validate-version.outputs.target_repo }}
ref: ${{ needs.validate-version.outputs.sha }}
- name: Build Common Assets
run: |
./Configure linux-x86_64 no-tests --prefix=/usr/local
make -j$(nproc) install_dev DESTDIR=$PWD/common-assets
make install_html_docs DESTDIR=$PWD/common-assets || true
# Include License
cp LICENSE.txt common-assets/usr/local/
# --- Generate README ---
cat << 'EOF' > common-assets/usr/local/README.txt
OpenSSL Distribution Package
============================
This package contains the OpenSSL executable, shared libraries, static libraries (stripped), C headers, and documentation.
Package Layout:
---------------
* version.txt - OpenSSL version in this package [non-redistributable]
* openssl - The OpenSSL command-line utility [redistributable/optional]
* libcrypto / libssl - Shared libraries [redistributable/required]
* install_symlinks.sh - (POSIX only) Script to restore shared library symlinks [redistributable/optional]
* engines/ - OpenSSL engines [redistributable/optional]
* providers/ - OpenSSL providers [redistributable/optional]
* doc/ - Developers Documentation [non-redistributable]
* include/ - C Header files [non-redistributable]
* lib/import/ - Import libraries (Windows only) [non-redistributable]
* lib/static/ - Static libraries (.lib / .a) [non-redistributable]
Linking Instructions:
---------------------
* Windows Dynamic: Link against the import libraries in `lib/import/` (which point to the DLLs in the root).
* Windows Static: Link against the static libraries in `lib/static/` (Compiled with /MD Dynamic CRT).
* POSIX Dynamic: Link directly against the shared libraries (.so / .dylib) in the root directory.
* POSIX Static: Link against the static archives (.a) in `lib/static/`.
Deployment Instructions (Linux / macOS / Unix):
-----------------------------------------------
Windows file systems fail to extract Unix symbolic links. To ensure cross-platform compatibility, this archive contains only the physical shared library files.
If this package includes the 'install_symlinks.sh' script, you MUST run it from the root of the extracted directory to recreate the required library symlinks (e.g., libcrypto.so -> libcrypto.so.X).
$ cd <extracted_directory>
$ sh ./install_symlinks.sh
Windows Users:
--------------
Windows does not use symlinks for OpenSSL DLLs. You can safely ignore or delete the shell script.
EOF
# Remove unnecessary large directories
rm -rf common-assets/usr/local/lib common-assets/usr/local/lib64 common-assets/usr/local/bin common-assets/usr/local/ssl
- name: Upload Common Assets
uses: actions/upload-artifact@v7
with:
name: openssl-common-assets-${{ github.run_id }}
path: common-assets/usr/local
retention-days: 1
# =========================================================================
# 2. COMPILE BINARIES (Fan-Out Matrix)
# =========================================================================
compile-binaries:
name: Compile (${{ matrix.platform.label }} ${{ matrix.platform.arch }} ${{ matrix.linkage }})
needs: validate-version
strategy:
fail-fast: false
matrix:
linkage: [shared, static]
platform:
- { label: Windows, os: windows-latest, arch: x64, target: VC-WIN64A, vcvars: amd64 }
- { label: Windows, os: windows-latest, arch: x86, target: VC-WIN32, vcvars: x86 }
- { label: Windows, os: windows-latest, arch: arm64ec, target: VC-ARM64EC, vcvars: amd64_arm64 }
- { label: Linux, os: ubuntu-latest, arch: x64, target: linux-x86_64 }
- { label: Linux, os: ubuntu-latest, arch: arm64, target: linux-aarch64 }
- { label: macOS, os: macos-14, arch: x64, target: darwin64-x86_64-cc, minos: "10.14" }
- { label: macOS, os: macos-14, arch: arm64, target: darwin64-arm64-cc, minos: "11.0" }
- { label: Android, os: ubuntu-latest, arch: arm64, target: android-arm64, api: 21 }
- { label: Android, os: ubuntu-latest, arch: arm, target: android-arm, api: 21 }
- { label: iOS, os: macos-14, arch: arm64, target: ios64-cross }
- { label: iOS, os: macos-14, arch: sim-arm64, target: iossimulator-xcrun, minos: "11.0" }
exclude:
- linkage: shared
platform: { label: iOS } # iOS is static only
runs-on: ${{ matrix.platform.os }}
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v6
with:
repository: ${{ needs.validate-version.outputs.target_repo }}
ref: ${{ needs.validate-version.outputs.sha }}
- name: Validate Azure Code Signing Secrets
if: matrix.platform.label == 'Windows'
shell: pwsh
run: |
$missing = @()
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CLIENT_ID }}')) { $missing += "AZURE_CLIENT_ID" }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CLIENT_SECRET }}')) { $missing += "AZURE_CLIENT_SECRET" }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_TENANT_ID }}')) { $missing += "AZURE_TENANT_ID" }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_SUBSCRIPTION_ID }}')) { $missing += "AZURE_SUBSCRIPTION_ID" }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_SIGNING_ACCOUNT_NAME }}')) { $missing += "AZURE_SIGNING_ACCOUNT_NAME" }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}')) { $missing += "AZURE_CERTIFICATE_PROFILE_NAME" }
if ($missing.Count -gt 0) {
Write-Error "Required Azure Code Signing secret(s) missing: $($missing -join ', ')"
exit 1
}
- name: Prepare Windows Targets
if: matrix.platform.label == 'Windows'
shell: bash
run: |
cat << 'EOF' > Configurations/99-win-hybridcrt.conf
my %targets = (
# =========================================================================
# x64 HybridCRT Targets
# =========================================================================
"VC-WIN64A-SHARED" => {
inherit_from => [ "VC-WIN64A" ],
disable => [ "tests", "makedepend", "__DOCS__" ],
cflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MDd?\b//g; # Remove Dynamic CRT
return "$f /MT /Zi"; # Force Static CRT + Debug Symbols
},
lflags => sub {
my $f = join(" ", @_);
return "$f /debug /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib";
},
},
"VC-WIN64A-STATIC" => {
inherit_from => [ "VC-WIN64A" ],
disable => [ "shared", "module", "tests", "makedepend", "__DOCS__" ],
cflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MDd?\b//g;
return "$f /MT /Zi";
},
lflags => sub {
my $f = join(" ", @_);
return "$f /debug /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib";
},
},
# =========================================================================
# x86 HybridCRT Targets
# =========================================================================
"VC-WIN32-SHARED" => {
inherit_from => [ "VC-WIN32" ],
disable => [ "tests", "makedepend", "__DOCS__" ],
cflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MDd?\b//g;
return "$f /MT /Zi";
},
lflags => sub {
my $f = join(" ", @_);
return "$f /debug /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib";
},
},
"VC-WIN32-STATIC" => {
inherit_from => [ "VC-WIN32" ],
disable => [ "shared", "module", "tests", "makedepend", "__DOCS__" ],
cflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MDd?\b//g;
return "$f /MT /Zi";
},
lflags => sub {
my $f = join(" ", @_);
return "$f /debug /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib";
},
},
# =========================================================================
# ARM64EC HybridCRT Targets
# =========================================================================
"VC-ARM64EC-SHARED" => {
inherit_from => [ "VC-WIN64-ARM" ],
disable => [ "asm", "tests", "makedepend", "__DOCS__" ],
CFLAGS => "/W3 /wd4090 /wd4267 /wd4244 /nologo /O1 /Zi",
ARFLAGS => "/nologo /MACHINE:ARM64EC",
cflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MDd?\b//g; # Remove Dynamic CRT
$f =~ s/\/arm64\b//ig; # Remove standard ARM64 flag
return "$f /MT /arm64EC /D_WIN32_WINNT=0x0A00";
},
lflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MACHINE:ARM64\b//ig; # Remove conflicting machine type
return "$f /debug /MACHINE:ARM64EC /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib";
},
},
"VC-ARM64EC-STATIC" => {
inherit_from => [ "VC-WIN64-ARM" ],
disable => [ "shared", "module", "asm", "tests", "makedepend", "__DOCS__" ],
CFLAGS => "/W3 /wd4090 /wd4267 /wd4244 /nologo /O1 /Zi",
ARFLAGS => "/nologo /MACHINE:ARM64EC",
cflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MDd?\b//g;
$f =~ s/\/arm64\b//ig;
return "$f /MT /arm64EC /D_WIN32_WINNT=0x0A00";
},
lflags => sub {
my $f = join(" ", @_);
$f =~ s/\/MACHINE:ARM64\b//ig;
return "$f /debug /MACHINE:ARM64EC /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib";
},
},
);
EOF
# Check if the 'no-docs' option is documented in INSTALL.md (introduced in 3.2.0)
if grep -q "no-docs" INSTALL.md; then
echo "Feature 'docs' is supported. Disabling it in config."
sed -i 's/"__DOCS__"/"docs"/g' Configurations/99-win-hybridcrt.conf
else
echo "Feature 'docs' is NOT supported (likely OpenSSL 3.0.x or 3.1.x). Removing from config."
sed -i 's/"__DOCS__"//g' Configurations/99-win-hybridcrt.conf
fi
- name: Compile and Stage Windows Binaries
if: matrix.platform.label == 'Windows'
shell: cmd
run: |
:: Dynamically locate the latest Visual Studio installation path
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath`) do set "VS_PATH=%%i"
:: Call vcvarsall.bat using the dynamically discovered path
call "%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform.vcvars }}
set "INSTALL_TEMP=%GITHUB_WORKSPACE%\temp_install"
:: Use the original raw_artifact\dist path so it matches POSIX perfectly
set "STAGED=%GITHUB_WORKSPACE%\raw_artifact\dist"
mkdir "%STAGED%\lib\static" "%STAGED%\lib\import" "%STAGED%\engines" "%STAGED%\providers"
:: Construct Target Name dynamically (e.g., VC-WIN64A-SHARED)
set "LINK_UPPER=${{ matrix.linkage }}"
if "%LINK_UPPER%"=="shared" (set "TARGET_NAME=${{ matrix.platform.target }}-SHARED") else (set "TARGET_NAME=${{ matrix.platform.target }}-STATIC")
cd openssl-src
perl Configure %TARGET_NAME% --prefix="%INSTALL_TEMP%"
nmake && nmake install_sw
:: Organize into Staged Structure (Matching the ORIGINAL layout)
if "${{ matrix.linkage }}"=="shared" (
:: Copy exe and dlls to the ROOT of the artifact, not a bin/ folder!
if exist "%INSTALL_TEMP%\bin\openssl.exe" copy "%INSTALL_TEMP%\bin\openssl.exe" "%STAGED%\"
copy "%INSTALL_TEMP%\bin\*.dll" "%STAGED%\"
copy "%INSTALL_TEMP%\lib\*.lib" "%STAGED%\lib\import\"
if exist "%INSTALL_TEMP%\lib\engines-3" copy "%INSTALL_TEMP%\lib\engines-3\*.dll" "%STAGED%\engines\"
if exist "%INSTALL_TEMP%\lib\ossl-modules" copy "%INSTALL_TEMP%\lib\ossl-modules\*.dll" "%STAGED%\providers\"
) else (
copy "%INSTALL_TEMP%\lib\*.lib" "%STAGED%\lib\static\"
)
- name: Check for Windows Binaries to Sign
if: matrix.platform.label == 'Windows'
id: check_binaries
shell: pwsh
run: |
$files = Get-ChildItem -Path "${{ github.workspace }}\raw_artifact\dist" -Recurse -Include *.exe,*.dll
if ($files.Count -gt 0) {
Write-Host "Found $($files.Count) binary file(s) to sign."
Add-Content -Path $env:GITHUB_OUTPUT -Value "has_binaries=true"
} else {
Write-Host "No .exe or .dll files found to sign."
Add-Content -Path $env:GITHUB_OUTPUT -Value "has_binaries=false"
}
- name: Azure Login
if: matrix.platform.label == 'Windows' && steps.check_binaries.outputs.has_binaries == 'true'
uses: azure/login@v3
with:
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
- name: Sign Windows Binaries (Azure Artifact Signing)
if: matrix.platform.label == 'Windows' && steps.check_binaries.outputs.has_binaries == 'true'
uses: azure/artifact-signing-action@v2
with:
endpoint: ${{ secrets.AZURE_CODESIGNING_ENDPOINT || 'https://eus.codesigning.azure.net/' }}
signing-account-name: ${{ secrets.AZURE_SIGNING_ACCOUNT_NAME }}
certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}
files-folder: ${{ github.workspace }}\raw_artifact\dist
files-folder-filter: exe,dll
files-folder-recurse: true
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Verify Signed Windows Binaries
if: matrix.platform.label == 'Windows' && steps.check_binaries.outputs.has_binaries == 'true'
shell: pwsh
run: |
$files = Get-ChildItem -Path "${{ github.workspace }}\raw_artifact\dist" -Recurse -Include *.exe,*.dll
if ($files.Count -eq 0) {
Write-Host "No .exe or .dll files found to verify."
exit 0
}
$failed = $false
foreach ($file in $files) {
Write-Host "Verifying $($file.FullName)..."
$sig = Get-AuthenticodeSignature -FilePath $file.FullName
Write-Host " Status: $($sig.Status)"
Write-Host " StatusMessage: $($sig.StatusMessage)"
if ($sig.SignerCertificate) {
Write-Host " Subject: $($sig.SignerCertificate.Subject)"
Write-Host " Issuer: $($sig.SignerCertificate.Issuer)"
}
if ($sig.Status -ne 'Valid') {
Write-Error "Signature status for $($file.Name) is invalid: $($sig.Status)"
$failed = $true
}
}
if ($failed) {
exit 1
}
- name: Install Linux Dependencies
if: matrix.platform.label == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libsctp-dev
if [ "${{ matrix.platform.arch }}" == "arm64" ]; then
sudo apt-get install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross
fi
- name: Compile Unix (POSIX)
if: matrix.platform.label != 'Windows'
shell: bash
run: |
TARGET="${{ matrix.platform.target }}"
LINKAGE="${{ matrix.linkage }}"
LABEL="${{ matrix.platform.label }}"
PREFIX="${{ github.workspace }}/raw_artifact/usr/local"
EXTRA_FLAGS=""
# --- Platform Specific Setup ---
if [ "$LABEL" == "macOS" ] ; then
EXTRA_FLAGS="-mmacosx-version-min=${{ matrix.platform.minos }}"
elif [ "$LABEL" == "Linux" ]; then
EXTRA_FLAGS="enable-sctp -Wl,-rpath,'\$\$ORIGIN'"
if [ "$TARGET" == "linux-aarch64" ]; then
export CROSS_COMPILE=aarch64-linux-gnu-
fi
elif [ "$LABEL" == "Android" ]; then
sed -i 's/-fPIC/-fPIC -Wl,-z,max-page-size=16384/g' Configurations/15-android.conf
export ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME
export PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
elif [ "$LABEL" == "iOS" ]; then
if [[ "$TARGET" == *"simulator"* ]]; then
export CROSS_TOP=$(xcode-select -print-path)/Platforms/iPhoneSimulator.platform/Developer
export CROSS_SDK=iPhoneSimulator.sdk
EXTRA_FLAGS="-mios-simulator-version-min=${{ matrix.platform.minos }}"
else
export CROSS_TOP=$(xcode-select -print-path)/Platforms/iPhoneOS.platform/Developer
export CROSS_SDK=iPhoneOS.sdk
fi
fi
# --- Configure & Build ---
if [ "$LINKAGE" == "shared" ]; then
./Configure $TARGET shared no-tests $EXTRA_FLAGS --prefix="$PREFIX"
else
if ! ./Configure $TARGET no-shared no-apps no-module no-tests $EXTRA_FLAGS --prefix="$PREFIX"; then
./Configure $TARGET no-shared no-module no-tests $EXTRA_FLAGS --prefix="$PREFIX"
fi
fi
make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu)
make install_sw DESTDIR="/"
- name: Organize Unix Binaries
if: matrix.platform.label != 'Windows'
shell: bash
run: |
LABEL="${{ matrix.platform.label }}"
LINKAGE="${{ matrix.linkage }}"
PREFIX="${{ github.workspace }}/raw_artifact/usr/local"
mkdir -p raw_artifact/dist/{engines,providers,lib/static}
if [ "$LINKAGE" == "shared" ]; then
# Executable
find "$PREFIX/bin" -type f -name "openssl" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true
# Shared Libs
if [ "$LABEL" == "Android" ]; then
find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "*.so" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true
else
# Versioned libs only: libcrypto.so.X, libssl.so.X or libcrypto.X.dylib, libssl.X.dylib
find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libcrypto.so.*" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true
find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libssl.so.*" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true
find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libcrypto.*.dylib" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true
find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libssl.*.dylib" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true
fi
# Engines & Providers
find "$PREFIX" -path "*/engines-*/*.so" -exec cp {} raw_artifact/dist/engines/ \; 2>/dev/null || true
find "$PREFIX" -path "*/engines-*/*.dylib" -exec cp {} raw_artifact/dist/engines/ \; 2>/dev/null || true
find "$PREFIX" -path "*/ossl-modules*/*.so" -exec cp {} raw_artifact/dist/providers/ \; 2>/dev/null || true
find "$PREFIX" -path "*/ossl-modules*/*.dylib" -exec cp {} raw_artifact/dist/providers/ \; 2>/dev/null || true
# Stripping (Non-macOS)
if [ "$LABEL" != "macOS" ]; then
find raw_artifact/dist -maxdepth 1 -type f \( -name "openssl" -o -name "*.so*" \) -exec strip {} + 2>/dev/null || true
find raw_artifact/dist/engines raw_artifact/dist/providers -type f -name "*.so" -exec strip {} + 2>/dev/null || true
fi
# Symlinks script (Linux/macOS)
if [ "$LABEL" == "Linux" ] || [ "$LABEL" == "macOS" ]; then
echo "#!/bin/sh" > raw_artifact/dist/install_symlinks.sh
echo "echo \"Restoring shared library symlinks...\"" >> raw_artifact/dist/install_symlinks.sh
cd raw_artifact/dist
for lib in libcrypto libssl; do
if [ "$LABEL" == "Linux" ]; then
REAL_FILE=$(ls ${lib}.so.* 2>/dev/null | head -n 1)
if [ -n "$REAL_FILE" ]; then
echo "ln -sf $REAL_FILE ${lib}.so" >> install_symlinks.sh
fi
else
REAL_FILE=$(ls ${lib}.*.dylib 2>/dev/null | head -n 1)
if [ -n "$REAL_FILE" ]; then
echo "ln -sf $REAL_FILE ${lib}.dylib" >> install_symlinks.sh
fi
fi
done
chmod +x install_symlinks.sh
cd - > /dev/null
fi
else
# Static linkage
mkdir -p raw_artifact/dist/lib/static
find "$PREFIX" -type f -name "*.a" -exec cp {} raw_artifact/dist/lib/static/ \; 2>/dev/null || true
# Stripping (Non-macOS)
if [ "$LABEL" != "macOS" ]; then
find raw_artifact/dist/lib/static -type f -name "*.a" -exec strip -S {} + 2>/dev/null || true
fi
fi
find raw_artifact/dist -type d -empty -delete || true
- name: Upload Raw Artifact
uses: actions/upload-artifact@v7
with:
name: raw-${{ matrix.platform.label }}-${{ matrix.platform.arch }}-${{ matrix.linkage }}-${{ github.run_id }}
path: raw_artifact/dist
retention-days: 1
# =========================================================================
# 3a. BUILD WINDOWS MULTI-ARCH INSTALLER — Release Builds Only
# =========================================================================
InnoSetup-windows-installer:
name: Inno Setup Windows Multi-Arch Installer
needs: [validate-version, build-common-assets, compile-binaries]
if: needs.validate-version.outputs.is_fork == 'false' && inputs.build_type == 'release'
runs-on: windows-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v6
- name: Validate Signing Secrets
shell: pwsh
run: |
$missing = @()
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CLIENT_ID }}')) { $missing += 'AZURE_CLIENT_ID' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CLIENT_SECRET }}')) { $missing += 'AZURE_CLIENT_SECRET' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_TENANT_ID }}')) { $missing += 'AZURE_TENANT_ID' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_SUBSCRIPTION_ID }}')) { $missing += 'AZURE_SUBSCRIPTION_ID' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_SIGNING_ACCOUNT_NAME }}')) { $missing += 'AZURE_SIGNING_ACCOUNT_NAME' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}')) { $missing += 'AZURE_CERTIFICATE_PROFILE_NAME' }
if ($missing.Count -gt 0) {
Write-Error "Missing required secret(s): $($missing -join ', ')"
exit 1
}
- name: Download x64 Shared Artifact
uses: actions/download-artifact@v8
with:
name: raw-Windows-x64-shared-${{ github.run_id }}
path: raw-shared-x64
- name: Download x86 Shared Artifact
uses: actions/download-artifact@v8
with:
name: raw-Windows-x86-shared-${{ github.run_id }}
path: raw-shared-x86
- name: Download ARM64EC Shared Artifact
uses: actions/download-artifact@v8
with:
name: raw-Windows-arm64ec-shared-${{ github.run_id }}
path: raw-shared-arm64ec
- name: Download Common Assets
uses: actions/download-artifact@v8
with:
name: openssl-common-assets-${{ github.run_id }}
path: common-assets
- name: Stage Multi-Arch Redistributables
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$redist = "$env:GITHUB_WORKSPACE\redist"
foreach ($arch in @('x64', 'x86', 'arm64ec')) {
$archDir = "$redist\$arch"
New-Item -ItemType Directory -Force -Path $archDir, "$archDir\providers", "$archDir\engines" | Out-Null
$src = "$env:GITHUB_WORKSPACE\raw-shared-$arch"
Copy-Item "$src\openssl.exe" $archDir -ErrorAction SilentlyContinue
Get-ChildItem $src -Filter 'libcrypto-*.dll' | Copy-Item -Destination $archDir
Get-ChildItem $src -Filter 'libssl-*.dll' | Copy-Item -Destination $archDir
if (Test-Path "$src\providers") {
Get-ChildItem "$src\providers" -Filter '*.dll' | Copy-Item -Destination "$archDir\providers"
}
if (Test-Path "$src\engines") {
Get-ChildItem "$src\engines" -Filter '*.dll' | Copy-Item -Destination "$archDir\engines"
}
}
Copy-Item "common-assets\LICENSE.txt" $redist -ErrorAction SilentlyContinue
Write-Host "=== Multi-Arch Redistributables Staged ==="
Get-ChildItem $redist -Recurse | Select-Object -ExpandProperty FullName
- name: Install InnoSetup
shell: pwsh
run: |
choco install innosetup --no-progress -y
if ($LASTEXITCODE -ne 0) { Write-Error 'Failed to install InnoSetup'; exit 1 }
- name: Generate and Compile Multi-Arch Installer
shell: pwsh
env:
APP_PUBLISHER: ${{ vars.PUBLISHER_DISPLAY_NAME || 'TaurusTLS Developers' }}
APP_PUBLISHER_URL: ${{ vars.PUBLISHER_URL || 'https://github.com/TaurusTLS-Developers/OpenSSL-Distribution' }}
run: |
$ErrorActionPreference = 'Stop'
$version = '${{ needs.validate-version.outputs.version }}'
$appId = 'B3E8F2A1-C4D7-4E9F-B6A2-F7E9D4C7B0A5'
$wsDir = $env:GITHUB_WORKSPACE
$redistDir = "$wsDir\redist"
$assetsDir = "$wsDir\assets"
$pubName = $env:APP_PUBLISHER
$pubUrl = $env:APP_PUBLISHER_URL
New-Item -ItemType Directory -Force -Path "$wsDir\installers" | Out-Null
# Substitute template parameters
$templatePath = "$wsDir\config\openssl-installer.iss.template"
$outFilename = "openssl-$version-Windows-installer"
$iss = Get-Content $templatePath -Raw
$iss = $iss.Replace('{{APP_ID}}', "{{$appId}")
$iss = $iss.Replace('{{VERSION}}', $version)
$iss = $iss.Replace('{{APP_PUBLISHER}}', $pubName)
$iss = $iss.Replace('{{PUBLISHER_DISPLAY_NAME}}', $pubName)
$iss = $iss.Replace('{{APP_PUBLISHER_URL}}', $pubUrl)
$iss = $iss.Replace('{{OUTPUT_DIR}}', "$wsDir\installers")
$iss = $iss.Replace('{{OUTPUT_BASE_FILENAME}}', $outFilename)
$iss = $iss.Replace('{{REDIST_DIR}}', $redistDir)
$iss = $iss.Replace('{{ASSETS_DIR}}', $assetsDir)
$issPath = "$wsDir\openssl-installer.iss"
[IO.File]::WriteAllText($issPath, $iss, [Text.UTF8Encoding]::new($false))
Write-Host "=== Generated Multi-Arch .iss ==="
Get-Content $issPath
$iscc = Get-ChildItem 'C:\Program Files (x86)\Inno Setup*' -Filter 'ISCC.exe' -Recurse -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty FullName -First 1
if (-not $iscc) {
$isccCmd = Get-Command iscc.exe -ErrorAction SilentlyContinue
if ($isccCmd) { $iscc = $isccCmd.Source }
}
if (-not $iscc) { Write-Error 'ISCC.exe not found'; exit 1 }
Write-Host "ISCC: $iscc"
& $iscc $issPath
if ($LASTEXITCODE -ne 0) { Write-Error "InnoSetup failed (exit $LASTEXITCODE)"; exit 1 }
Write-Host "✅ Multi-Arch InnoSetup installer compiled."
- name: Azure Login
uses: azure/login@v3
with:
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
- name: Sign Installer (Azure Artifact Signing)
uses: azure/artifact-signing-action@v2
with:
endpoint: ${{ secrets.AZURE_CODESIGNING_ENDPOINT || 'https://eus.codesigning.azure.net/' }}
signing-account-name: ${{ secrets.AZURE_SIGNING_ACCOUNT_NAME }}
certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}
files-folder: ${{ github.workspace }}\installers
files-folder-filter: exe
files-folder-recurse: false
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Verify Signed Installer
shell: pwsh
run: |
$files = Get-ChildItem "$env:GITHUB_WORKSPACE\installers\*" -Include *.exe
if ($files.Count -eq 0) { Write-Error 'No installer file found to verify.'; exit 1 }
foreach ($file in $files) {
Write-Host "Verifying $($file.FullName)..."
$sig = Get-AuthenticodeSignature -FilePath $file.FullName
Write-Host " Status: $($sig.Status)"
Write-Host " Subject: $($sig.SignerCertificate.Subject)"
if ($sig.Status -ne 'Valid') { Write-Error "Invalid signature: $($sig.Status)"; exit 1 }
}
- name: Upload Multi-Arch Installer
uses: actions/upload-artifact@v7
with:
name: openssl-${{ needs.validate-version.outputs.artifact_version }}-Windows-installer
path: ${{ github.workspace }}\installers\openssl-${{ needs.validate-version.outputs.version }}-Windows-installer.exe
archive: false
retention-days: 5
# =========================================================================
# 3b. BUILD WINDOWS MSIX FRAMEWORK PACKAGES (Matrix) — Release Builds Only
# =========================================================================
msix-windows-installers:
name: Windows MSIX Framework (${{ matrix.arch }})
needs: [validate-version, build-common-assets, compile-binaries]
if: needs.validate-version.outputs.is_fork == 'false' && inputs.build_type == 'release'
strategy:
fail-fast: false
matrix:
include:
- { arch: x64, msix_arch: x64 }
- { arch: x86, msix_arch: x86 }
- { arch: arm64ec, msix_arch: arm64 }
runs-on: windows-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v6
- name: Validate Signing Secrets
shell: pwsh
run: |
$missing = @()
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CLIENT_ID }}')) { $missing += 'AZURE_CLIENT_ID' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CLIENT_SECRET }}')) { $missing += 'AZURE_CLIENT_SECRET' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_TENANT_ID }}')) { $missing += 'AZURE_TENANT_ID' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_SUBSCRIPTION_ID }}')) { $missing += 'AZURE_SUBSCRIPTION_ID' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_SIGNING_ACCOUNT_NAME }}')) { $missing += 'AZURE_SIGNING_ACCOUNT_NAME' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}')) { $missing += 'AZURE_CERTIFICATE_PROFILE_NAME' }
if ([string]::IsNullOrWhiteSpace('${{ secrets.AZURE_MSIX_PUBLISHER }}')) { $missing += 'AZURE_MSIX_PUBLISHER' }
if ($missing.Count -gt 0) {
Write-Error "Missing required secret(s): $($missing -join ', ')"
exit 1
}
- name: Download Shared Artifact
uses: actions/download-artifact@v8
with:
name: raw-Windows-${{ matrix.arch }}-shared-${{ github.run_id }}
path: raw-shared
- name: Download Common Assets
uses: actions/download-artifact@v8
with:
name: openssl-common-assets-${{ github.run_id }}
path: common-assets
- name: Build Framework MSIX Package
shell: powershell
env:
MSIX_PUBLISHER: ${{ secrets.AZURE_MSIX_PUBLISHER }}
APP_PUBLISHER: ${{ vars.PUBLISHER_DISPLAY_NAME || 'TaurusTLS Developers' }}
run: |
$ErrorActionPreference = 'Stop'
$version = '${{ needs.validate-version.outputs.version }}'
$arch = '${{ matrix.arch }}'
$msixArch = '${{ matrix.msix_arch }}'
$publisher = $env:MSIX_PUBLISHER
$pubName = $env:APP_PUBLISHER
$parts = $version -split '\.'
$msixVer = "$($parts[0]).$($parts[1]).$($parts[2]).0"
$wsDir = $env:GITHUB_WORKSPACE
$staging = "$wsDir\msix-staging"
$src = "$wsDir\raw-shared"
# Locate MakeAppx.exe from Windows SDK
$makeAppx = Get-ChildItem 'C:\Program Files (x86)\Windows Kits\10\bin' `
-Filter 'MakeAppx.exe' -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.DirectoryName -match '\\x64$' } |
Select-Object -ExpandProperty FullName -First 1
if (-not $makeAppx) { Write-Error 'MakeAppx.exe not found in Windows SDK'; exit 1 }
New-Item -ItemType Directory -Force -Path "$staging\Assets", "$wsDir\installers" | Out-Null
# Copy assets folder directly from repository (openssl-150x150.png, openssl-44x44.png, openssl-50x50.png)
if (Test-Path "$wsDir\assets") {
Copy-Item -Recurse -Force "$wsDir\assets" "$staging\"
} else {
Write-Error "Assets folder not found at $wsDir\assets"; exit 1
}
# Copy redistributable binaries & license
Copy-Item "$src\openssl.exe" $staging -ErrorAction SilentlyContinue
Get-ChildItem $src -Filter 'libcrypto-*.dll' | Copy-Item -Destination $staging
Get-ChildItem $src -Filter 'libssl-*.dll' | Copy-Item -Destination $staging
if (Test-Path "$src\providers") {
New-Item -ItemType Directory -Force -Path "$staging\providers" | Out-Null
Get-ChildItem "$src\providers" -Filter '*.dll' | Copy-Item -Destination "$staging\providers"
}
if (Test-Path "$src\engines") {
New-Item -ItemType Directory -Force -Path "$staging\engines" | Out-Null
Get-ChildItem "$src\engines" -Filter '*.dll' | Copy-Item -Destination "$staging\engines"
}
Copy-Item "common-assets\LICENSE.txt" $staging -ErrorAction SilentlyContinue
# Substitute AppxManifest template tokens
$xmlPublisher = [System.Security.SecurityElement]::Escape($publisher)
$xmlPubName = [System.Security.SecurityElement]::Escape($pubName)
$templatePath = "$wsDir\config\AppxManifest.xml.template"
$xml = Get-Content $templatePath -Raw
$xml = $xml.Replace('{{MSIX_PUBLISHER}}', $xmlPublisher)
$xml = $xml.Replace('{{MSIX_VERSION}}', $msixVer)
$xml = $xml.Replace('{{MSIX_ARCH}}', $msixArch)
$xml = $xml.Replace('{{VERSION}}', $version)
$xml = $xml.Replace('{{ARCH}}', $arch)
$xml = $xml.Replace('{{PUBLISHER_DISPLAY_NAME}}', $xmlPubName)
[IO.File]::WriteAllText("$staging\AppxManifest.xml", $xml, [Text.UTF8Encoding]::new($false))
# Pack individual Framework .msix
$msixOut = "$wsDir\installers\openssl-$version-Windows-$arch.msix"
& $makeAppx pack /d $staging /p $msixOut /o
if ($LASTEXITCODE -ne 0) { Write-Error "MakeAppx pack failed for $arch"; exit 1 }
Write-Host "✅ Framework MSIX created: $msixOut"
- name: Azure Login
uses: azure/login@v3
with:
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
- name: Sign MSIX Package (Azure Artifact Signing)
uses: azure/artifact-signing-action@v2
with:
endpoint: ${{ secrets.AZURE_CODESIGNING_ENDPOINT || 'https://eus.codesigning.azure.net/' }}
signing-account-name: ${{ secrets.AZURE_SIGNING_ACCOUNT_NAME }}
certificate-profile-name: ${{ secrets.AZURE_CERTIFICATE_PROFILE_NAME }}
files-folder: ${{ github.workspace }}\installers
files-folder-filter: msix
files-folder-recurse: false
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Verify Signed MSIX Package
shell: pwsh
run: |
$files = Get-ChildItem "$env:GITHUB_WORKSPACE\installers\*" -Include *.msix
if ($files.Count -eq 0) { Write-Error 'No .msix file found to verify.'; exit 1 }
foreach ($file in $files) {
Write-Host "Verifying $($file.FullName)..."
$sig = Get-AuthenticodeSignature -FilePath $file.FullName
Write-Host " Status: $($sig.Status)"
Write-Host " Subject: $($sig.SignerCertificate.Subject)"
if ($sig.Status -ne 'Valid') { Write-Error "Invalid signature on $($file.Name): $($sig.Status)"; exit 1 }
}
- name: Upload MSIX Framework Artifact
uses: actions/upload-artifact@v7
with:
name: openssl-${{ needs.validate-version.outputs.artifact_version }}-Windows-${{ matrix.arch }}-msix
path: ${{ github.workspace }}\installers\openssl-${{ needs.validate-version.outputs.version }}-Windows-${{ matrix.arch }}.msix
archive: false
retention-days: 5
# =========================================================================
# 4. PACKAGE RELEASE (Fan-In Matrix)
# =========================================================================
package-release:
name: Package (${{ matrix.label }} ${{ matrix.arch }})
needs: [validate-version, build-common-assets, compile-binaries]
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
strategy:
fail-fast: false
matrix:
include:
# Windows packaging moved to ubuntu-latest for speed and native 'zip' support
- { label: Windows, arch: x64, runner: ubuntu-latest }
- { label: Windows, arch: x86, runner: ubuntu-latest }
- { label: Windows, arch: arm64ec, runner: ubuntu-latest }
# Linux & Android
- { label: Linux, arch: x64, runner: ubuntu-latest }
- { label: Linux, arch: arm64, runner: ubuntu-latest }
- { label: Android, arch: arm64, runner: ubuntu-latest }
- { label: Android, arch: arm, runner: ubuntu-latest }
# Apple platforms MUST use macOS runners for lipo, otool, install_name_tool, and Apple strip
- { label: macOS, arch: universal, runner: macos-14 }
- { label: iOS, arch: arm64, runner: macos-14 }
- { label: iOS, arch: sim-arm64, runner: macos-14 }
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v6
- name: Download Common Assets
uses: actions/download-artifact@v8
with:
name: openssl-common-assets-${{ github.run_id }}
path: common-assets
- name: Download Raw Binaries (Standard)
if: matrix.label != 'macOS'
uses: actions/download-artifact@v8
with:
pattern: raw-${{ matrix.label }}-${{ matrix.arch }}-*-${{ github.run_id }}
path: raw-binaries
merge-multiple: false
- name: Download Raw Binaries (macOS Universal)
if: matrix.label == 'macOS'
uses: actions/download-artifact@v8
with:
pattern: raw-macOS-*-${{ github.run_id }}
path: raw-binaries
merge-multiple: false
- name: Merge Binaries and Assets
if: matrix.label != 'macOS'
shell: bash
run: |
# Merge contents of downloaded raw artifacts into dist/
# Standard behavior: download-artifact creates subdirectories named after artifacts.
# Flattened behavior: If only one artifact exists, it may be extracted directly.
HAS_RAW_SUBDIRS=false
for d in raw-binaries/raw-*/; do
if [ -d "$d" ]; then
HAS_RAW_SUBDIRS=true
break
fi
done
if [ "$HAS_RAW_SUBDIRS" = true ]; then
echo "Detected nested artifact structure. Merging subdirectories..."
for d in raw-binaries/raw-*/; do
if [ -d "$d" ]; then
echo "Merging $d contents into dist/"
cp -R "$d". dist/
fi
done
else
echo "Detected flattened artifact structure. Merging raw-binaries/ directly..."
cp -R raw-binaries/. dist/
fi
- name: Rename macOS artifacts (remove run_id suffix)
if: matrix.label == 'macOS'
shell: bash
run: |
cd raw-binaries
for d in raw-macOS-*-${{ github.run_id }}; do
if [ -d "$d" ]; then
mv "$d" "${d%-*}"
fi
done
- name: Organize & Lipo (macOS Universal)
if: matrix.label == 'macOS'
shell: bash
run: |
# 1. Relocate and Strip individual architectures
for arch in x64 arm64; do
BASE_DIR="raw-binaries/raw-macOS-$arch-shared"
find "$BASE_DIR" -type f \( -name "*.dylib" -o -name "*.so" -o -name "openssl" \) | while read -r target_file; do
if [[ "$target_file" == *"openssl" ]]; then
strip "$target_file" || true
else
strip -x "$target_file" || true
fi
if [[ "$target_file" == *".dylib" ]]; then
install_name_tool -id "@rpath/$(basename "$target_file")" "$target_file" || true
fi
DEPS=$(otool -L "$target_file" 2>/dev/null | awk '/\/usr\/local\/lib\/lib/ {print $1}')
for dep in $DEPS; do
depname=$(basename "$dep")
if [[ "$target_file" == *"engines"* ]] || [[ "$target_file" == *"providers"* ]]; then
install_name_tool -change "$dep" "@loader_path/../$depname" "$target_file" || true
else
install_name_tool -change "$dep" "@loader_path/$depname" "$target_file" || true
fi
done
install_name_tool -add_rpath "@executable_path" "$target_file" 2>/dev/null || true
install_name_tool -add_rpath "@loader_path" "$target_file" 2>/dev/null || true
done
find "raw-binaries/raw-macOS-$arch-static" -type f -name "*.a" -exec strip -S {} + 2>/dev/null || true
done
# 2. Combine with Lipo
mkdir -p dist/{engines,providers,lib/static}
lipo_file() {
local rel_path=$1
local dest_path=$2
local f_x86="raw-binaries/raw-macOS-x64-shared/$rel_path"
local f_arm="raw-binaries/raw-macOS-arm64-shared/$rel_path"
if [ ! -f "$f_x86" ]; then
f_x86="raw-binaries/raw-macOS-x64-static/$rel_path"
f_arm="raw-binaries/raw-macOS-arm64-static/$rel_path"
fi
if [ ! -f "$f_x86" ] || [ ! -f "$f_arm" ]; then return 0; fi
lipo -create -output "$dest_path" "$f_x86" "$f_arm"
}
lipo_file "openssl" "dist/openssl"
find raw-binaries/raw-macOS-x64-shared -maxdepth 1 -type f -name "*.dylib" | while read -r f; do
lipo_file "$(basename "$f")" "dist/$(basename "$f")"
done
[ -d "raw-binaries/raw-macOS-x64-shared/engines" ] && find raw-binaries/raw-macOS-x64-shared/engines -type f -name "*.dylib" | while read -r f; do
lipo_file "engines/$(basename "$f")" "dist/engines/$(basename "$f")"
done
[ -d "raw-binaries/raw-macOS-x64-shared/providers" ] && find raw-binaries/raw-macOS-x64-shared/providers -type f -name "*.dylib" | while read -r f; do
lipo_file "providers/$(basename "$f")" "dist/providers/$(basename "$f")"
done
find raw-binaries/raw-macOS-x64-static/lib/static -type f -name "*.a" | while read -r f; do
lipo_file "lib/static/$(basename "$f")" "dist/lib/static/$(basename "$f")"
done
cp raw-binaries/raw-macOS-x64-shared/install_symlinks.sh dist/ 2>/dev/null || true
- name: Finalize Package
shell: bash
run: |
# Copy Common Assets
mkdir -p dist/include dist/doc
cp -R common-assets/include/* dist/include/ 2>/dev/null || true
cp -R common-assets/share/doc/* dist/doc/ 2>/dev/null || true
# Copy License and README from common assets
cp common-assets/LICENSE.txt dist/ 2>/dev/null || true
cp common-assets/README.txt dist/ 2>/dev/null || true
# Create Metadata
if [ "${{ inputs.build_type }}" == "branch" ]; then
echo "branch: ${{ needs.validate-version.outputs.slugified_version }}" > dist/version.txt
else
echo "${{ needs.validate-version.outputs.slugified_version }}" > dist/version.txt
fi
# Create Symlink Script (POSIX only, if not already present)
if [ ! -f dist/install_symlinks.sh ]; then
if [ "${{ matrix.label }}" == "Linux" ] || [ "${{ matrix.label }}" == "macOS" ]; then
echo "#!/bin/sh" > dist/install_symlinks.sh
echo "echo \"Restoring shared library symlinks...\"" >> dist/install_symlinks.sh
cd dist
for lib in libcrypto libssl; do
if [ "${{ matrix.label }}" == "Linux" ]; then
REAL_FILE=$(ls ${lib}.so.* 2>/dev/null | head -n 1)
if [ -n "$REAL_FILE" ]; then
echo "ln -sf $REAL_FILE ${lib}.so" >> install_symlinks.sh
fi
else
REAL_FILE=$(ls ${lib}.*.dylib 2>/dev/null | head -n 1)
if [ -n "$REAL_FILE" ]; then
echo "ln -sf $REAL_FILE ${lib}.dylib" >> install_symlinks.sh
fi
fi
done
chmod +x install_symlinks.sh
cd - > /dev/null
fi
fi
find dist -type d -empty -delete
ARCHIVE_NAME="openssl-${{ needs.validate-version.outputs.artifact_version }}-${{ matrix.label }}-${{ matrix.arch }}.zip"
cd dist
zip -r -y "../$ARCHIVE_NAME" .
cd ..
echo "ARCHIVE_FILE=$ARCHIVE_NAME" >> $GITHUB_ENV
- name: Upload Final Archive
uses: actions/upload-artifact@v7
with:
name: openssl-${{ needs.validate-version.outputs.artifact_version }}-${{ matrix.label }}-${{ matrix.arch }}
path: ${{ env.ARCHIVE_FILE }}
archive: false
retention-days: 5
- name: Upload Build Metadata (Once)
if: matrix.label == 'Linux' && matrix.arch == 'x64' && needs.validate-version.outputs.is_fork == 'false'
uses: actions/upload-artifact@v7
with:
name: build-metadata
path: dist/version.txt
retention-days: 5
# =========================================================================
# 5. CLEANUP RAW ARTIFACTS
# =========================================================================
cleanup-artifacts:
name: Cleanup Intermediate Artifacts
needs: [package-release, InnoSetup-windows-installer, msix-windows-installers]
runs-on: ubuntu-latest
if: |
always() &&
inputs.keep_raw_artifacts != true &&
!contains(needs.*.result, 'failure') &&
!contains(needs.*.result, 'cancelled')
permissions:
actions: write
steps:
- name: Delete Raw and Common Artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Fetching artifacts for run ${{ github.run_id }}..."
# Use gh api to list artifacts specifically for THIS run to avoid conflicts
ARTIFACTS=$(gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts --paginate)
# Filter for IDs of artifacts that start with 'raw-' or are 'openssl-common-assets'
# We also verify the name ends with the run_id for triple-redundancy
IDS=$(echo "$ARTIFACTS" | jq -r ".artifacts[] | select (.name | (startswith(\"raw-\") and endswith(\"-${{ github.run_id }}\")) or . == \"openssl-common-assets-${{ github.run_id }}\") | .id")
if [ -z "$IDS" ] || [ "$IDS" == "null" ]; then
echo "No intermediate artifacts found to delete."
exit 0
fi
for id in $IDS; do
echo "Deleting artifact ID: $id"
gh api -X DELETE repos/${{ github.repository }}/actions/artifacts/$id || echo "Failed to delete artifact ID: $id" ; true # Continue even if deletion fails
done
echo "✅ Cleanup complete."