Sign and notarize directly in build-helper (#389)

* Sign and notarize in CI

* add dmg

* remove flag

* fix env var

* add team id

* conditionally set apple specific env vars

* publish to a staging location

* upload unzipped

* add script to publish to staging, update publish url

* turn off autodiscovery again

* update scripts

* deprecate old method

* move stuff

* remove autodiscovery
This commit is contained in:
Evan Simkowitz 2024-03-06 16:07:48 -08:00 committed by GitHub
parent 2735b03cb8
commit 33fc3518c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 78 additions and 38 deletions

View File

@ -25,7 +25,7 @@ jobs:
with: with:
repository: scripthaus-dev/scripthaus repository: scripthaus-dev/scripthaus
path: scripthaus path: scripthaus
- name: Install Linux Build Dependencies - name: Install Linux Build Dependencies (Linux only)
if: matrix.platform == 'linux' if: matrix.platform == 'linux'
run: | run: |
sudo apt-get update sudo apt-get update
@ -58,6 +58,11 @@ jobs:
run: ./scripthaus/scripthaus run ${{ matrix.scripthaus }} run: ./scripthaus/scripthaus run ${{ matrix.scripthaus }}
env: env:
GOARCH: ${{ matrix.arch }} GOARCH: ${{ matrix.arch }}
CSC_LINK: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_CERTIFICATE}}
CSC_KEY_PASSWORD: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_CERTIFICATE_PWD }}
APPLE_ID: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_NOTARIZATION_PWD }}
APPLE_TEAM_ID: ${{ matrix.platform == 'darwin' && secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: waveterm-build-${{ matrix.platform }} name: waveterm-build-${{ matrix.platform }}
@ -75,10 +80,8 @@ jobs:
- name: Set `version.txt` - name: Set `version.txt`
run: | run: |
echo "${{ needs.runbuild.outputs.WAVETERM_VERSION }}" >> buildtemp/version.txt echo "${{ needs.runbuild.outputs.WAVETERM_VERSION }}" >> buildtemp/version.txt
- name: Zip Builds
run: (cd buildtemp; zip -q ../waveterm-builds.zip *)
- name: Upload to S3 - name: Upload to S3
run: aws s3 cp waveterm-builds.zip s3://waveterm-github-artifacts/ run: aws s3 cp buildtemp/ s3://waveterm-github-artifacts/staging/${{ needs.runbuild.outputs.WAVETERM_VERSION }}/ --recursive --exclude "builder-*.yml"
env: env:
AWS_ACCESS_KEY_ID: "${{ secrets.S3_USERID }}" AWS_ACCESS_KEY_ID: "${{ secrets.S3_USERID }}"
AWS_SECRET_ACCESS_KEY: "${{ secrets.S3_SECRETKEY }}" AWS_SECRET_ACCESS_KEY: "${{ secrets.S3_SECRETKEY }}"

3
buildres/.gitignore vendored
View File

@ -1,3 +1,4 @@
*/ *builds/
*-staged/
*.zip *.zip
*.dmg *.dmg

View File

@ -2,7 +2,7 @@
## Build Helper workflow ## Build Helper workflow
Our release builds are managed by the "Build Helper" GitHub Action, which is defined Our release builds are managed by the "Build Helper" GitHub Action, which is defined
in [`build-helper.yml`](../.github/workflows/build-helper.yml). in [`build-helper.yml`](../.github/workflows/build-helper.yml).
Under the hood, this will call the `build-package` and `build-package-linux` scripts in Under the hood, this will call the `build-package` and `build-package-linux` scripts in
@ -11,29 +11,42 @@ WebPack and then the `wavesrv` and `mshell` binaries, then it will call `electro
to generate the distributable app packages. The configuration for `electron-builder` to generate the distributable app packages. The configuration for `electron-builder`
is [`electron-builder.config.js`](../electron-builder.config.js). is [`electron-builder.config.js`](../electron-builder.config.js).
We are working to fully automate the building of release artifacts. For now, This will also sign and notarize the macOS app package.
manual steps are still required to sign and notarize the macOS artifacts. The
Linux artifacts do not require additional modification before being published.
## Local signing and notarizing for macOS Once a build is complete, it will be placed in `s3://waveterm-github-artifacts/staging/<version>`.
It can be downloaded for testing using the [`download-staged-artifact.sh`](./download-staged-artifact.sh)
script. When you are ready to publish the artifacts to the public release feed, use the
[`publish-from-staging.sh`](./publish-from-staging.sh) script to directly copy the artifacts from
the staging bucket to the releases bucket.
The [`prepare-macos.sh`](./prepare-macos.sh) script will download the latest build ## Automatic updates
Thanks to `electron-updater`, we are able to provide automatic app updates for macOS and Linux,
as long as the app was distributed as a DMG, AppImage, RPM, or DEB file.
With each release, `latest-mac.yml` and `latest-linux.yml` files will be produced that point to the
newest release. These also include file sizes and checksums to aid in validating the packages. The app
will check these files in our S3 bucket every hour to see if a new version is available.
## Local signing and notarizing for macOS (Deprecated)
The [`prepare-macos.sh`](./deprecated/prepare-macos.sh) script will download the latest build
artifacts from S3 and sign and notarize the macOS binaries within it. It will then artifacts from S3 and sign and notarize the macOS binaries within it. It will then
generate a DMG and a new ZIP archive with the new signed app. generate a DMG and a new ZIP archive with the new signed app.
This will call a few different JS scripts to perform more complicated operations. This will call a few different JS scripts to perform more complicated operations.
[`osx-sign.js`](./osx-sign.js) and [`osx-notarize.js`](./osx-notarize.js) call [`osx-sign.js`](./deprecated/osx-sign.js) and [`osx-notarize.js`](./deprecated/osx-notarize.js) call
underlying Electron APIs to sign and notarize the package. underlying Electron APIs to sign and notarize the package.
[`update-latest-mac.js`](./update-latest-mac.js) will then update the `latest-mac.yml` [`update-latest-mac.js`](./deprecated/update-latest-mac.js) will then update the `latest-mac.yml`
file with the SHA512 checksum and file size of the new signed and notarized installer. This file with the SHA512 checksum and file size of the new signed and notarized installer. This
is important for the `electron-updater` auto-update mechanism to then find and validate new releases. is important for the `electron-updater` auto-update mechanism to then find and validate new releases.
## Uploading release artifacts for distribution ## Uploading release artifacts for distribution (Deprecated)
### Upload script ### Upload script
Once the build has been fully validated and is ready to be released, the Once the build has been fully validated and is ready to be released, the
[`upload-release.sh`](./upload-release.sh) script is then used to grab the completed [`upload-release.sh`](./deprecated/upload-release.sh) script is then used to grab the completed
artifacts and upload them to the `dl.waveterm.dev` S3 bucket for distribution. artifacts and upload them to the `dl.waveterm.dev` S3 bucket for distribution.
### Homebrew ### Homebrew
@ -56,12 +69,3 @@ command. More information can be found
We also exclude most of our `node_modules` from packaging, as WebPack handles packaging We also exclude most of our `node_modules` from packaging, as WebPack handles packaging
of any dependencies for us. The one exception is `monaco-editor`. of any dependencies for us. The one exception is `monaco-editor`.
## Automatic updates
Thanks to `electron-updater`, we are able to provide automatic app updates for macOS and Linux,
as long as the app was distributed as a DMG, AppImage, RPM, or DEB file.
With each release, `latest-mac.yml` and `latest-linux.yml` files will be produced that point to the
newest release. These also include file sizes and checksums to aid in validating the packages. The app
will check these files in our S3 bucket every hour to see if a new version is available.

View File

@ -0,0 +1,16 @@
# Downloads the artifacts for the specified version from the staging bucket for local testing.
# Usage: download-staged-artifact.sh <version>
# Example: download-staged-artifact.sh 0.1.0
# Retrieve version from the first argument
VERSION=$1
if [ -z "$VERSION" ]; then
echo "Usage: $0 <version>"
exit
fi
# Download the artifacts for the specified version from the staging bucket
DOWNLOAD_DIR=$VERSION-staged
rm -rf $DOWNLOAD_DIR
mkdir -p $DOWNLOAD_DIR
aws s3 cp s3://waveterm-github-artifacts/staging/$VERSION/ $DOWNLOAD_DIR/ --recursive

View File

@ -0,0 +1,12 @@
# Takes a release from our staging bucket and publishes it to the public download bucket.
# Usage: publish-from-staging.sh <version>
# Example: publish-from-staging.sh 0.1.0
# Takes the version as an argument
VERSION=$1
if [ -z "$VERSION" ]; then
echo "Usage: $0 <version>"
exit
fi
aws s3 cp s3://waveterm-github-artifacts/staging/$VERSION/ s3://dl.waveterm.dev/releases/ --recursive

View File

@ -46,13 +46,24 @@ const config = {
}, },
asarUnpack: ["bin/**/*"], asarUnpack: ["bin/**/*"],
mac: { mac: {
target: { target: [
target: "zip", {
arch: "universal", target: "zip",
}, arch: "universal",
},
{
target: "dmg",
arch: "universal",
},
],
icon: "public/waveterm.icns", icon: "public/waveterm.icns",
category: "public.app-category.developer-tools", category: "public.app-category.developer-tools",
minimumSystemVersion: "10.15.0", minimumSystemVersion: "10.15.0",
notarize: process.env.APPLE_TEAM_ID
? {
teamId: process.env.APPLE_TEAM_ID,
}
: false,
binaries: fs binaries: fs
.readdirSync("bin", { recursive: true, withFileTypes: true }) .readdirSync("bin", { recursive: true, withFileTypes: true })
.filter((f) => f.isFile()) .filter((f) => f.isFile())
@ -77,7 +88,7 @@ const config = {
}, },
publish: { publish: {
provider: "generic", provider: "generic",
url: "https://waveterm-test-autoupdate.s3.us-west-2.amazonaws.com/autoupdate", url: "https://dl.waveterm.dev/releases",
}, },
}; };

View File

@ -819,13 +819,6 @@ function initUpdater(): NodeJS.Timeout {
} }
setAppUpdateStatus("unavailable"); setAppUpdateStatus("unavailable");
let feedURL = `https://dl.waveterm.dev/autoupdate/${unamePlatform}/${unameArch}`;
let serverType: "default" | "json" = "default";
if (unamePlatform == "darwin") {
feedURL += "/RELEASES.json";
serverType = "json";
}
autoUpdater.removeAllListeners(); autoUpdater.removeAllListeners();
@ -865,7 +858,7 @@ function initUpdater(): NodeJS.Timeout {
// check for updates right away and keep checking later // check for updates right away and keep checking later
autoUpdater.checkForUpdates(); autoUpdater.checkForUpdates();
return setInterval(autoUpdater.checkForUpdates, 3600000); // 1 hour in ms return setInterval(() => fireAndForget(autoUpdater.checkForUpdates), 3600000); // 1 hour in ms
} }
/** /**

View File

@ -387,7 +387,7 @@ function ces(s: string) {
* A wrapper function for running a promise and catching any errors * A wrapper function for running a promise and catching any errors
* @param f The promise to run * @param f The promise to run
*/ */
function fireAndForget(f: () => Promise<void>) { function fireAndForget(f: () => Promise<any>) {
f().catch((e) => { f().catch((e) => {
console.log("fireAndForget error", e); console.log("fireAndForget error", e);
}); });