remove openvpn management protocol; add key auth types #108
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Sign | |
| on: | |
| push: | |
| branches: | |
| - master | |
| tags: | |
| - 'v*' | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-app: | |
| runs-on: macos-14 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Select Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: "16.1" | |
| - name: Cache DerivedData | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/Library/Developer/Xcode/DerivedData | |
| ~/.swiftpm | |
| key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }} | |
| - name: Cache BoringSSL build | |
| uses: actions/cache@v4 | |
| with: | |
| path: pkcs11/vendor/boringssl/build | |
| key: ${{ runner.os }}-boringssl-${{ hashFiles('pkcs11/vendor/boringssl/CMakeLists.txt', 'pkcs11/vendor/boringssl/crypto/**') }} | |
| - name: Install certificate and provisioning profile | |
| env: | |
| MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} | |
| MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| PROVISIONING_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }} | |
| INSTALLER_CERTIFICATE: ${{ secrets.INSTALLER_CERTIFICATE }} | |
| INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.INSTALLER_CERTIFICATE_PASSWORD }} | |
| run: | | |
| echo "$MACOS_CERTIFICATE" | base64 --decode > signing.p12 | |
| security create-keychain -p "" build.keychain | |
| security import signing.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign | |
| rm signing.p12 | |
| if [ -n "$INSTALLER_CERTIFICATE" ]; then | |
| echo "$INSTALLER_CERTIFICATE" | base64 --decode > installer.p12 | |
| security import installer.p12 -k build.keychain -P "$INSTALLER_CERTIFICATE_PASSWORD" -T /usr/bin/productsign | |
| rm installer.p12 | |
| fi | |
| security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "" build.keychain | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/nailed.provisionprofile | |
| echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode > build_profile.provisionprofile | |
| - name: Build PKCS#11 dylib | |
| run: | | |
| cd pkcs11 | |
| make clean || true | |
| make -j$(sysctl -n hw.ncpu) | |
| echo "Built dylib:" | |
| ls -la libnailed_pkcs11.dylib | |
| file libnailed_pkcs11.dylib | |
| - name: Sign PKCS#11 dylib | |
| env: | |
| CODE_SIGN_IDENTITY: ${{ vars.CODE_SIGN_IDENTITY }} | |
| run: | | |
| DYLIB="pkcs11/libnailed_pkcs11.dylib" | |
| codesign --force --options runtime --timestamp \ | |
| --sign "$CODE_SIGN_IDENTITY" \ | |
| "$DYLIB" | |
| codesign --verify --verbose=2 "$DYLIB" | |
| echo "Dylib signature info:" | |
| codesign -dvv "$DYLIB" | |
| - name: Build app (Release, unsigned) | |
| run: | | |
| set -e | |
| xcodebuild \ | |
| -project nailed.xcodeproj \ | |
| -scheme nailed \ | |
| -configuration Release \ | |
| -archivePath $PWD/build/nailed.xcarchive \ | |
| CODE_SIGN_IDENTITY="-" \ | |
| CODE_SIGNING_REQUIRED=NO \ | |
| CODE_SIGNING_ALLOWED=NO \ | |
| clean archive | xcpretty && exit ${PIPESTATUS[0]} | |
| - name: Export and sign .app | |
| env: | |
| CODE_SIGN_IDENTITY: ${{ vars.CODE_SIGN_IDENTITY }} | |
| DEVELOPMENT_TEAM: ${{ vars.DEVELOPMENT_TEAM }} | |
| run: | | |
| mkdir -p build/export | |
| ditto build/nailed.xcarchive/Products/Applications/nailed.app build/export/nailed.app | |
| APP="build/export/nailed.app" | |
| cp build_profile.provisionprofile "$APP/Contents/embedded.provisionprofile" | |
| sed "s/\$(AppIdentifierPrefix)/${DEVELOPMENT_TEAM}./g" \ | |
| nailed/nailed.entitlements > build/entitlements.plist | |
| echo "Resolved entitlements:" | |
| cat build/entitlements.plist | |
| find "$APP/Contents/Resources" -name "*.bundle" -type d | while read bundle; do | |
| echo "Signing bundle: $bundle" | |
| codesign --force --options runtime --timestamp \ | |
| --sign "$CODE_SIGN_IDENTITY" \ | |
| "$bundle" | |
| done | |
| if [ -d "$APP/Contents/Frameworks" ]; then | |
| find "$APP/Contents/Frameworks" -name "*.framework" -type d | while read framework; do | |
| echo "Signing framework: $framework" | |
| codesign --force --options runtime --timestamp \ | |
| --sign "$CODE_SIGN_IDENTITY" \ | |
| "$framework" | |
| done | |
| fi | |
| codesign --force --options runtime --timestamp \ | |
| --entitlements build/entitlements.plist \ | |
| --sign "$CODE_SIGN_IDENTITY" \ | |
| "$APP" | |
| codesign --verify --verbose=2 "$APP" | |
| echo "Signature info:" | |
| codesign -dvv "$APP" | |
| echo "Embedded entitlements:" | |
| codesign -d --entitlements - "$APP" 2>/dev/null || true | |
| echo "Signature verification passed" | |
| - name: Create installer package | |
| env: | |
| INSTALLER_SIGN_IDENTITY: ${{ vars.INSTALLER_SIGN_IDENTITY }} | |
| run: | | |
| chmod +x scripts/build-pkg.sh | |
| if [[ "$GITHUB_REF" == refs/tags/v* ]]; then | |
| VERSION="${GITHUB_REF#refs/tags/v}" | |
| else | |
| VERSION="0.0.0-dev" | |
| fi | |
| scripts/build-pkg.sh \ | |
| "build/export/nailed.app" \ | |
| "pkcs11/libnailed_pkcs11.dylib" \ | |
| "build/nailed.pkg" \ | |
| "$INSTALLER_SIGN_IDENTITY" \ | |
| "$VERSION" | |
| echo "Package created:" | |
| ls -la build/nailed.pkg | |
| if [ -n "$INSTALLER_SIGN_IDENTITY" ]; then | |
| pkgutil --check-signature build/nailed.pkg | |
| fi | |
| - name: Upload app PKG artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: nailed-pkg | |
| path: build/nailed.pkg | |
| - name: Submit for notarization | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} | |
| APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} | |
| run: | | |
| mkdir -p ~/private_keys | |
| echo "$APPLE_API_KEY_BASE64" | base64 --decode > ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 | |
| xcrun notarytool submit build/nailed.pkg \ | |
| --key ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 \ | |
| --key-id "$APPLE_API_KEY_ID" \ | |
| --issuer "$APPLE_API_KEY_ISSUER" \ | |
| --output-format json | tee notarization-result.json | |
| SUBMISSION_ID=$(cat notarization-result.json | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") | |
| echo "Submission ID: $SUBMISSION_ID" | |
| echo "$SUBMISSION_ID" > build/submission-id.txt | |
| - name: Wait for notarization and staple | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} | |
| run: | | |
| SUBMISSION_ID=$(cat build/submission-id.txt) | |
| echo "Waiting for notarization (up to 2 minutes)..." | |
| if xcrun notarytool wait "$SUBMISSION_ID" \ | |
| --key ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 \ | |
| --key-id "$APPLE_API_KEY_ID" \ | |
| --issuer "$APPLE_API_KEY_ISSUER" \ | |
| --timeout 2m; then | |
| echo "Notarization completed, stapling..." | |
| xcrun stapler staple build/nailed.pkg | |
| xcrun stapler validate build/nailed.pkg | |
| else | |
| echo "error: Notarization not completed within timeout" | |
| exit 1 | |
| fi | |
| rm -rf ~/private_keys | |
| - name: Upload stapled PKG | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: nailed-pkg-stapled | |
| path: build/nailed.pkg | |
| - name: Upload submission ID | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: notarization-submission | |
| path: build/submission-id.txt | |
| build-openvpn: | |
| runs-on: macos-14 | |
| env: | |
| OPENSSL_VERSION: "3.5.5" | |
| LZO_VERSION: "2.10" | |
| LZ4_VERSION: "1.10.0" | |
| PKCS11_HELPER_VERSION: "1.30.0" | |
| OPENVPN_VERSION: "2.7.0" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install certificate | |
| env: | |
| MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} | |
| MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| INSTALLER_CERTIFICATE: ${{ secrets.INSTALLER_CERTIFICATE }} | |
| INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.INSTALLER_CERTIFICATE_PASSWORD }} | |
| run: | | |
| echo "$MACOS_CERTIFICATE" | base64 --decode > signing.p12 | |
| security create-keychain -p "" build.keychain | |
| security import signing.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign | |
| rm signing.p12 | |
| if [ -n "$INSTALLER_CERTIFICATE" ]; then | |
| echo "$INSTALLER_CERTIFICATE" | base64 --decode > installer.p12 | |
| security import installer.p12 -k build.keychain -P "$INSTALLER_CERTIFICATE_PASSWORD" -T /usr/bin/productsign | |
| rm installer.p12 | |
| fi | |
| security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "" build.keychain | |
| - name: Cache source tarballs | |
| uses: actions/cache@v4 | |
| with: | |
| path: openvpn-build/_work/sources | |
| key: openvpn-sources-${{ env.OPENSSL_VERSION }}-${{ env.LZO_VERSION }}-${{ env.LZ4_VERSION }}-${{ env.PKCS11_HELPER_VERSION }}-${{ env.OPENVPN_VERSION }} | |
| - name: Cache static libraries | |
| uses: actions/cache@v4 | |
| with: | |
| path: openvpn-build/_work/staging | |
| key: openvpn-staging-${{ runner.os }}-${{ runner.arch }}-${{ env.OPENSSL_VERSION }}-${{ env.LZO_VERSION }}-${{ env.LZ4_VERSION }}-${{ env.PKCS11_HELPER_VERSION }} | |
| - name: Build OpenVPN | |
| env: | |
| CODESIGN_IDENTITY: ${{ vars.CODE_SIGN_IDENTITY }} | |
| INSTALLER_IDENTITY: ${{ vars.INSTALLER_SIGN_IDENTITY }} | |
| run: | | |
| cd openvpn-build | |
| chmod +x build-openvpn.sh | |
| ./build-openvpn.sh | |
| - name: Verify build | |
| run: | | |
| openvpn-build/output/openvpn --version | |
| otool -L openvpn-build/output/openvpn | |
| codesign -dvv openvpn-build/output/openvpn 2>&1 | |
| pkgutil --check-signature openvpn-build/output/*.pkg | |
| - name: Upload OpenVPN package | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: openvpn-pkg | |
| path: openvpn-build/output/*.pkg | |
| - name: Submit for notarization | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} | |
| APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} | |
| run: | | |
| mkdir -p ~/private_keys | |
| echo "$APPLE_API_KEY_BASE64" | base64 --decode > ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 | |
| xcrun notarytool submit openvpn-build/output/*.pkg \ | |
| --key ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 \ | |
| --key-id "$APPLE_API_KEY_ID" \ | |
| --issuer "$APPLE_API_KEY_ISSUER" \ | |
| --output-format json | tee notarization-result.json | |
| SUBMISSION_ID=$(python3 -c "import sys,json; print(json.load(sys.stdin)['id'])" < notarization-result.json) | |
| echo "Submission ID: $SUBMISSION_ID" | |
| echo "$SUBMISSION_ID" > openvpn-submission-id.txt | |
| - name: Wait for notarization and staple | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} | |
| run: | | |
| SUBMISSION_ID=$(cat openvpn-submission-id.txt) | |
| echo "Waiting for notarization..." | |
| xcrun notarytool wait "$SUBMISSION_ID" \ | |
| --key ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 \ | |
| --key-id "$APPLE_API_KEY_ID" \ | |
| --issuer "$APPLE_API_KEY_ISSUER" \ | |
| --timeout 10m | |
| echo "Notarization completed, stapling..." | |
| xcrun stapler staple openvpn-build/output/*.pkg | |
| xcrun stapler validate openvpn-build/output/*.pkg | |
| rm -rf ~/private_keys | |
| - name: Upload stapled OpenVPN package | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: openvpn-pkg-stapled | |
| path: openvpn-build/output/*.pkg | |
| - name: Upload submission ID | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: openvpn-notarization-submission | |
| path: openvpn-submission-id.txt | |
| release: | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: [build-app, build-openvpn] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download nailed package | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: nailed-pkg-stapled | |
| path: release-assets | |
| - name: Download OpenVPN package | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: openvpn-pkg-stapled | |
| path: release-assets | |
| - name: List release assets | |
| run: ls -lh release-assets/ | |
| - name: Create release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| VERSION="${GITHUB_REF#refs/tags/}" | |
| mv release-assets/nailed.pkg "release-assets/nailed-${VERSION}.pkg" | |
| PRERELEASE_FLAG="" | |
| if [[ "$VERSION" == *-rc* ]]; then | |
| PRERELEASE_FLAG="--prerelease" | |
| fi | |
| gh release create "$VERSION" \ | |
| --title "$VERSION" \ | |
| --generate-notes \ | |
| $PRERELEASE_FLAG \ | |
| release-assets/* |