diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a82cd980..058c060df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -101,222 +101,131 @@ jobs: if-no-files-found: error retention-days: 1 -# name: Ship CLI -# on: -# push: -# branches: -# - main -# - 'preview/**' -# tags: -# - test* -# - v* - -# jobs: -# package: -# runs-on: ${{ matrix.os }} -# env: -# TERM: xterm -# strategy: -# matrix: -# os: -# - ubuntu-20.04 -# node-version: -# - '14' -# variant: -# - linux-x64 -# - linux-arm64 -# - macos-x64 -# - macos-arm64 -# - win-x64 -# steps: -# # Install deps and cache -# # Eventually it would be great if these steps could live in a separate YAML file -# # that could be included in line to avoid code duplication -# - name: Checkout code -# uses: actions/checkout@v2 -# with: -# fetch-depth: 0 -# - name: Install node ${{ matrix.node-version }} -# uses: actions/setup-node@v2 -# with: -# node-version: ${{ matrix.node-version }} -# - name: Get Yarn cache directory -# id: yarn-cache-dir-path -# run: echo "::set-output name=dir::$(yarn cache dir)" -# - name: Use Yarn cache -# id: yarn-cache -# uses: actions/cache@v2 -# with: -# path: ${{ steps.yarn-cache-dir-path.outputs.dir }} -# key: ${{ runner.os }}-yarn-${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }} -# - name: Install Yarn dependencies -# run: yarn install --prefer-offline --frozen-lockfile - -# # Package and upload the cli -# # @NOTE: We cross-compile on Linux because _right now_ this seems to be -# # the only place we can reliably build all the variants. We use actions/upload -# # so move assets between jobs -# - name: Package ${{ matrix.variant }} CLI -# run: | -# node ./scripts/dev-version.js -# node ./bin/lando.js version -# yarn pkg --target=node${{ matrix.node-version }}-${{ matrix.variant }} --no-version -# - name: Upload lando-build-${{ matrix.variant }}-${{ github.sha }} -# uses: actions/upload-artifact@v2 -# with: -# name: lando-build-${{ matrix.variant }}-${{ github.sha }} -# path: dist/ -# if-no-files-found: error -# retention-days: 1 - -# ship: -# runs-on: ${{ matrix.os }} -# needs: -# - package -# env: -# TERM: xterm -# strategy: -# matrix: -# os: -# - macos-10.15 -# - ubuntu-20.04 -# - windows-2019 -# arch: -# - x64 -# - arm64 -# exclude: -# - os: windows-2019 -# arch: arm64 -# steps: -# # Set things up for signing, notarizing, uploading etc -# - name: Checkout code -# uses: actions/checkout@v2 -# with: -# fetch-depth: 0 -# - name: Set other variables -# id: vars -# shell: bash -# run: | -# # Set generic source ref vars -# echo "::set-output name=SOURCE_NAME::${GITHUB_REF#refs/*/}" -# echo "::set-output name=SOURCE_BRANCH::${GITHUB_REF#refs/heads/}" -# echo "::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/}" -# # Unset vars if it makes sense to do so -# if [ "$GITHUB_REF" == "${GITHUB_REF#refs/tags/}" ]; then echo "::set-output name=SOURCE_TAG::"; fi -# if [ "$GITHUB_REF" == "${GITHUB_REF#refs/heads/}" ]; then echo "::set-output name=SOURCE_BRANCH::"; fi - -# # Set os specific vars -# if [ "$RUNNER_OS" == "Linux" ]; then -# echo '::set-output name=OS::linux' -# echo '::set-output name=PKG_ENDING::' -# elif [ "$RUNNER_OS" == "Windows" ]; then -# echo '::set-output name=OS::win' -# echo '::set-output name=PKG_ENDING::.exe' -# else -# echo '::set-output name=OS::macos' -# echo '::set-output name=PKG_ENDING::' -# fi -# - name: Set SOURCE_PKG -# id: pkg -# shell: bash -# run: echo '::set-output name=SOURCE_PKG::lando-${{ steps.vars.outputs.OS }}-${{ matrix.arch }}${{ steps.vars.outputs.PKG_ENDING }}' -# - name: Test user defined variables -# shell: bash -# run: | -# echo "The OS is ${{ steps.vars.outputs.OS }}" -# echo "The SOURCE_NAME is ${{ steps.vars.outputs.SOURCE_NAME }}" -# echo "The SOURCE_BRANCH is ${{ steps.vars.outputs.SOURCE_BRANCH }}" -# echo "The SOURCE_TAG is ${{ steps.vars.outputs.SOURCE_TAG }}" -# echo "The SOURCE_PKG is ${{ steps.pkg.outputs.SOURCE_PKG }}" -# - name: Download lando-build-${{ steps.vars.outputs.OS }}-${{ matrix.arch }}-${{ github.sha }} -# uses: actions/download-artifact@v2 -# with: -# name: lando-build-${{ steps.vars.outputs.OS }}-${{ matrix.arch }}-${{ github.sha }} -# path: dist - -# # Codesign macOS binaries -# # NOTE: We cannot currently do this on macOS because of below issue -# # https://github.com/vercel/pkg/issues/128 -# # However, the logic is here and ready to go once that is resolved -# # NOTE: We also should add notarization logic here? -# - name: Codesign macOS binaries -# env: -# APPLE_CERT_DATA: ${{ secrets.APPLE_CERT_DATA }} -# APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }} -# APPLE_TEAM_ID: FY8GAUX282 -# if: ${{ steps.vars.outputs.OS == 'macos' }} -# run: | -# ./scripts/sign-macos.sh ./dist/${{ steps.pkg.outputs.SOURCE_PKG }} -# echo "::warning:: Codesign currently disabled because of https://github.com/vercel/pkg/issues/128" -# # Codesign WiNdOzE binaries -# - name: Codesign Windoze binaries -# env: -# WINDOZE_CERT_DATA: ${{ secrets.WINDOZE_CERT_DATA }} -# WINDOZE_CERT_PASSWORD: ${{ secrets.WINDOZE_CERT_PASSWORD }} -# if: ${{ steps.vars.outputs.OS == 'win' }} -# shell: powershell -# run: ./scripts/sign-win.ps1 ./dist/${{ steps.pkg.outputs.SOURCE_PKG }} - -# # Depending on the type of commit eg tagged, etc create the releases we need -# - name: Create releases -# env: -# SOURCE_BRANCH: ${{ steps.vars.outputs.SOURCE_BRANCH }} -# SOURCE_TAG: ${{ steps.vars.outputs.SOURCE_TAG }} -# PKG_PREFIX: "lando-${{ steps.vars.outputs.OS }}-${{ matrix.arch }}" -# PKG_SUFFIX: ${{ steps.vars.outputs.PKG_ENDING }} -# shell: bash -# run: | -# # Create release directories -# mkdir -p ./releases ./dev-builds - -# # Snapshot release -# cp -f ./dist/${{ steps.pkg.outputs.SOURCE_PKG }} "./dev-builds/$PKG_PREFIX-build-${{ github.sha }}$PKG_SUFFIX" - -# # Branch releases -# if [ -z "$SOURCE_TAG" ]; then cp -f ./dist/${{ steps.pkg.outputs.SOURCE_PKG }} "./releases/$PKG_PREFIX-$SOURCE_BRANCH-latest$PKG_SUFFIX"; fi -# # Latest dev release -# if [[ "$SOURCE_BRANCH" == "main" ]]; then cp -f ./dist/${{ steps.pkg.outputs.SOURCE_PKG }} "./releases/$PKG_PREFIX-latest$PKG_SUFFIX"; fi -# # Tag releases -# if [ ! -z "$SOURCE_TAG" ]; then cp -f ./dist/${{ steps.pkg.outputs.SOURCE_PKG }} "./releases/$PKG_PREFIX-$SOURCE_TAG$PKG_SUFFIX"; fi -# # Latest stable release -# if [ ! -z "$SOURCE_TAG" ]; then cp -f ./dist/${{ steps.pkg.outputs.SOURCE_PKG }} "./releases/$PKG_PREFIX-stable$PKG_SUFFIX"; fi + # Sign the binaries as needed with the given OS tools + sign-n-seal: + runs-on: ${{ matrix.os }} + needs: + - package + env: + TERM: xterm + strategy: + matrix: + os: + - macos-10.15 + - ubuntu-20.04 + - windows-2019 -# # Print what we end up with -# ls -lsa ./releases -# ls -lsa ./dev-builds + steps: + # Set things up for signing, notarizing, uploading etc + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Download lando-cli-unsigned-build-${{ github.sha }} + uses: actions/download-artifact@v2 + with: + name: lando-cli-unsigned-build-${{ github.sha }} + path: dist/@lando/unsigned + - name: Setup dist + shell: bash + run: mkdir -p dist/@lando/signed + + # Codesign and notarize macOS binaries + - name: Codesign the macOS binaries + env: + APPLE_CERT_DATA: ${{ secrets.APPLE_CERT_DATA }} + APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }} + APPLE_TEAM_ID: FY8GAUX282 + if: ${{ runner.os == 'macOS' }} + run: | + # Import certs + ./scripts/import-macos-certs.sh + # x64 + ./scripts/sign-macos.sh dist/@lando/unsigned/lando-macos-x64 --force --options runtime --entitlements entitlements.xml + # arm64 + ./scripts/sign-macos.sh dist/@lando/unsigned/lando-macos-arm64 --force --options runtime --entitlements entitlements.xml + + # Create zip for notarization + mkdir -p /tmp/notarize + mv -f dist/@lando/unsigned/lando-macos-x64 /tmp/notarize/lando-macos-x64 + mv -f dist/@lando/unsigned/lando-macos-arm64 /tmp/notarize/lando-macos-arm64 + zip -rjX dist/@lando/unsigned/notarize.zip /tmp/notarize/* + - name: Notarize the macOS binaries + if: ${{ runner.os == 'macOS' }} + uses: devbotsxyz/xcode-notarize@v1 + with: + appstore-connect-username: ${{ secrets.APPLE_NOTARY_USER }} + appstore-connect-password: ${{ secrets.APPLE_NOTARY_PASSWORD }} + primary-bundle-id: dev.lando.cli + product-path: dist/@lando/unsigned/notarize.zip + verbose: true + - name: Move the macOS binaries + if: ${{ runner.os == 'macOS' }} + run: unzip -o dist/@lando/unsigned/notarize.zip -d dist/@lando/signed + - name: Verify the macOS binaries + if: ${{ runner.os == 'macOS' }} + run: | + codesign -vvvv -R="notarized" --check-notarization dist/@lando/signed/lando-macos-x64 + codesign -vvvv -R="notarized" --check-notarization dist/@lando/signed/lando-macos-arm64 + chmod +x dist/@lando/signed/lando-macos-x64 + ./dist/@lando/signed/lando-macos-x64 version + chmod -x dist/@lando/signed/lando-macos-x64 + + # Codesign WiNdOzE binaries + - name: Codesign the Windoze binaries + env: + WINDOZE_CERT_DATA: ${{ secrets.WINDOZE_CERT_DATA }} + WINDOZE_CERT_PASSWORD: ${{ secrets.WINDOZE_CERT_PASSWORD }} + if: ${{ runner.os == 'Windows' }} + shell: powershell + run: | + # Import certs + ./scripts/import-win-certs.ps1 + # x64 + ./scripts/sign-win.ps1 dist/@lando/unsigned/lando-win-x64.exe + # arm64 + ./scripts/sign-win.ps1 dist/@lando/unsigned/lando-win-arm64.exe + - name: Move the Windoze binaries + if: ${{ runner.os == 'Windows' }} + shell: bash + run: | + cp -f dist/@lando/unsigned/lando-win-x64.exe dist/@lando/signed/lando-win-x64.exe + cp -f dist/@lando/unsigned/lando-win-arm64.exe dist/@lando/signed/lando-win-arm64.exe + - name: Verify the Windoze binaries + if: ${{ runner.os == 'Windows' }} + shell: bash + run: | + chmod +x dist/@lando/signed/lando-win-x64 + ./dist/@lando/signed/lando-win-x64 version + chmod -x dist/@lando/signed/lando-win-x64 + + # Codesign linux binaries + # @TODO: Eventually we should figure out how to do this on Linux but right now there + # is no requirement to do so + - name: Codesign the Linux binaries + if: ${{ runner.os == 'Linux' }} + run: | + echo "::warning:: Eventually we should figure out how to do codesign on Linux but right now there is no requirement to do so" + # ./scripts/sign-linux.sh dist/@lando/unsigned/lando-linux-x64 + # ./scripts/sign-linux.sh dist/@lando/unsigned/lando-linux-arm64 + - name: Move the Linux binaries + if: ${{ runner.os == 'Linux' }} + run: | + cp -f dist/@lando/unsigned/lando-linux-x64 dist/@lando/signed/lando-linux-x64 + cp -f dist/@lando/unsigned/lando-linux-arm64 dist/@lando/signed/lando-linux-arm64 + - name: Verify the Linux binaries + if: ${{ runner.os == 'Linux' }} + run: | + chmod +x dist/@lando/signed/lando-linux-x64 + ./dist/@lando/signed/lando-linux-x64 version + chmod -x dist/@lando/signed/lando-linux-x64 -# # Replace previously posted unsigned raw artifacts with signed build snapshots -# - name: Remove unsigned artifacts -# uses: geekyeggo/delete-artifact@v1 -# with: -# name: lando-build-${{ steps.vars.outputs.OS }}-${{ matrix.arch }}-${{ github.sha }} -# - name: Upload build snapshot as Actions artifact -# uses: actions/upload-artifact@v2 -# with: -# name: lando-${{ steps.vars.outputs.OS }}-${{ matrix.arch }}-${{ github.sha }}${{ steps.vars.outputs.PKG_ENDING }} -# path: dev-builds/ -# if-no-files-found: error -# retention-days: 30 -# # Upload releases to S3 -# - name: Configure S3 Credentials -# uses: aws-actions/configure-aws-credentials@v1 -# with: -# aws-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }} -# aws-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }} -# aws-region: us-east-1 -# - name: Upload releases to S3 -# shell: bash -# run: | -# aws s3 sync ./releases s3://files.lando.dev/cli --acl public-read -# # Upload releases to GitHub Releases -# - name: Upload releases to GitHub Releases -# uses: softprops/action-gh-release@v1 -# if: startsWith(github.ref, 'refs/tags/') -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# with: -# draft: true -# files: ./releases/lando-${{ steps.vars.outputs.OS }}-${{ matrix.arch }}-${{ steps.vars.outputs.SOURCE_TAG }}${{ steps.vars.outputs.PKG_ENDING }} -# # @TODO: Handle autochangelog stuff here eventaully -# # body_path: ${{ github.workflow }}-CHANGELOG.txt + # Upload the signed artifacts to a different bucket + - name: Upload lando-cli-build-${{ github.sha }} + uses: actions/upload-artifact@v2 + with: + name: lando-cli-build-${{ github.sha }} + path: dist/@lando/signed + if-no-files-found: error + retention-days: 1 diff --git a/entitlements.xml b/entitlements.xml new file mode 100644 index 000000000..a1c430a57 --- /dev/null +++ b/entitlements.xml @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.allow-unsigned-executable-memory + + + diff --git a/scripts/import-macos-certs.sh b/scripts/import-macos-certs.sh new file mode 100755 index 000000000..4c55ab631 --- /dev/null +++ b/scripts/import-macos-certs.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -eo pipefail + +# Verify we have the envvars we need +if [ -z "$APPLE_CERT_DATA" ]; then + echo "APPLE_CERT_DATA needs to be set with a base64 encoded p12!" + exit 2 +fi +if [ -z "$APPLE_CERT_PASSWORD" ]; then + echo "APPLE_CERT_PASSWORD needs to be set with your p12 password!" + exit 3 +fi +if [ -z "$APPLE_TEAM_ID" ]; then + echo "APPLE_TEAM_ID needs to be set with your cert user id!" + exit 4 +fi + +# Export certs +echo "$APPLE_CERT_DATA" | base64 --decode > /tmp/certs.p12 + +# Create keychain +security create-keychain -p actions macos-build.keychain +security default-keychain -s macos-build.keychain +security unlock-keychain -p actions macos-build.keychain +security set-keychain-settings -t 3600 -u macos-build.keychain + +# Import certs to keychain +security import /tmp/certs.p12 -k ~/Library/Keychains/macos-build.keychain -P "$APPLE_CERT_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign +# Key signing +security set-key-partition-list -S apple-tool:,apple: -s -k actions macos-build.keychain +# Verify the things +security find-identity -v macos-build.keychain | grep "$APPLE_TEAM_ID" | grep "Developer ID Application" +security find-identity -v macos-build.keychain | grep "$APPLE_TEAM_ID" | grep "Developer ID Installer" diff --git a/scripts/import-win-certs.ps1 b/scripts/import-win-certs.ps1 new file mode 100755 index 000000000..f01ff5287 --- /dev/null +++ b/scripts/import-win-certs.ps1 @@ -0,0 +1,36 @@ +#!/ + +$ErrorActionPreference = "Stop" + +# Verify we have the envvars we need +if ([string]::IsNullOrEmpty($env:WINDOZE_CERT_DATA)) +{ + throw "WINDOZE_CERT_DATA needs to be set with a base64 encoded p12!" +} +if ([string]::IsNullOrEmpty($env:WINDOZE_CERT_PASSWORD)) +{ + throw "WINDOZE_CERT_PASSWORD needs to be set with your p12 password!" +} + +# Get some things for cert opts +$temp_dir = $env:TMP +$cert_data = $env:WINDOZE_CERT_DATA +$cert_path = "$temp_dir\lando.windoze.p12" +$cert_password = $env:WINDOZE_CERT_PASSWORD +$cert_secure_password = $null + +# Export certs +Write-Output "Cert detected!" +# Decode and dump to temp file +If (!(Test-Path $cert_path)) { + Write-Output "Dumping cert to $cert_path..." + $bytes = [Convert]::FromBase64String($cert_data) + [IO.File]::WriteAllBytes($cert_path, $bytes) +} + +# Verify the cert and password are good +Write-Output "Verifying cert is good to go..." +$cert_secure_password = ConvertTo-SecureString $cert_password -AsPlainText -Force +Import-PfxCertificate -FilePath "$cert_path" -Password $cert_secure_password -CertStoreLocation "Cert:\LocalMachine\My" +# If we get this far we should be good! +Write-Output "We can sign!" diff --git a/scripts/sign-macos.sh b/scripts/sign-macos.sh index 37dc7a977..6fe35599c 100755 --- a/scripts/sign-macos.sh +++ b/scripts/sign-macos.sh @@ -1,46 +1,23 @@ #!/bin/bash +set -eo pipefail # Get our file FILE="$(pwd)/$1" +# Shift file and pass through anything else +shift +OPTIONS="$@" # Throw error if file does not exist if [ ! -f "$FILE" ]; then echo "$FILE does not exist!" exit 1 fi - -# Verify we have the envvars we need -if [ -z "$APPLE_CERT_DATA" ]; then - echo "APPLE_CERT_DATA needs to be set with a base64 encoded p12!" - exit 2 -fi -if [ -z "$APPLE_CERT_PASSWORD" ]; then - echo "APPLE_CERT_PASSWORD needs to be set with your p12 password!" - exit 3 -fi if [ -z "$APPLE_TEAM_ID" ]; then echo "APPLE_TEAM_ID needs to be set with your cert user id!" exit 4 fi -# Export certs -echo "$APPLE_CERT_DATA" | base64 --decode > /tmp/certs.p12 - -# Create keychain -security create-keychain -p actions macos-build.keychain -security default-keychain -s macos-build.keychain -security unlock-keychain -p actions macos-build.keychain -security set-keychain-settings -t 3600 -u macos-build.keychain - -# Import certs to keychain -security import /tmp/certs.p12 -k ~/Library/Keychains/macos-build.keychain -P "$APPLE_CERT_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign -# Key signing -security set-key-partition-list -S apple-tool:,apple: -s -k actions macos-build.keychain -# Verify the things -security find-identity -v macos-build.keychain | grep "$APPLE_TEAM_ID" | grep "Developer ID Application" - -# NOTE: We cannot currently do this on macOS because of below issue -# https://github.com/vercel/pkg/issues/128 -# However, the logic is here and ready to go once that is resolved -# codesign --force --options runtime -s "$APPLE_TEAM_ID" "$FILE" || true -# @TODO: verify the codesignature +# Force the codesignature +codesign $OPTIONS -s "$APPLE_TEAM_ID" "$FILE" +# Verify the code signature +codesign -v "$FILE" --verbose diff --git a/scripts/sign-win.ps1 b/scripts/sign-win.ps1 old mode 100644 new mode 100755 index 0e2fe2c85..5c909083d --- a/scripts/sign-win.ps1 +++ b/scripts/sign-win.ps1 @@ -12,39 +12,23 @@ if (!(Test-Path "$file")) } # Verify we have the envvars we need -if ([string]::IsNullOrEmpty($env:WINDOZE_CERT_DATA)) -{ - throw "WINDOZE_CERT_DATA needs to be set with a base64 encoded p12!" -} if ([string]::IsNullOrEmpty($env:WINDOZE_CERT_PASSWORD)) { throw "WINDOZE_CERT_PASSWORD needs to be set with your p12 password!" } # Get some things for cert opts -$cert_data = $env:WINDOZE_CERT_DATA +$temp_dir = $env:TMP $cert_path = "$temp_dir\lando.windoze.p12" $cert_password = $env:WINDOZE_CERT_PASSWORD -$cert_secure_password = $null $signtool = "${env:ProgramFiles(x86)}\Windows Kits\10\bin\x64\signtool.exe" -$temp_dir = $env:TMP -# Export certs -Write-Output "Cert detected!" # Decode and dump to temp file -If (!(Test-Path $cert_path)) { - Write-Output "Dumping cert to $cert_path..." - $bytes = [Convert]::FromBase64String($cert_data) - [IO.File]::WriteAllBytes($cert_path, $bytes) +If (!(Test-Path $cert_path)) +{ + throw "Expected cert at $cert_path. Try running import-win-certs.ps1 first!" } -# Verify the cert and password are good -Write-Output "Verifying cert is good to go..." -$cert_secure_password = ConvertTo-SecureString $cert_password -AsPlainText -Force -Import-PfxCertificate -FilePath "$cert_path" -Password $cert_secure_password -CertStoreLocation "Cert:\LocalMachine\My" -# If we get this far we should be good! -Write-Output "We can sign!" - # Sign and verify Write-Output "Trying to sign the $file binary with $signtool..." & $signtool sign -f "$cert_path" -p "$cert_password" -fd sha256 -tr "http://timestamp.comodoca.com/?td=sha256" -td sha256 -as -v "$file"