chore(release): wire signing and npm publish secrets

This commit is contained in:
Kayshen-X 2026-07-08 22:47:21 +08:00
parent e25dbbe1bf
commit a71d97e7b9
2 changed files with 78 additions and 33 deletions

View file

@ -2,7 +2,8 @@ name: Rust release artifacts
# Triggered on tag push (v*) — builds release binaries across desktop targets,
# packages real installers per platform, builds the web Docker image and SDK
# tarballs, and publishes a GitHub prerelease.
# tarballs, publishes the web SDK packages to npm, and publishes a GitHub
# prerelease.
#
# Artifact matrix (per platform; <v> = tag version, arch token = x64/arm64 to
# match electron-builder's `${productName}-${version}-${arch}-…` convention
@ -82,8 +83,9 @@ jobs:
runs-on: ${{ matrix.runner }}
if: github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v')
env:
HAS_APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_P12 != '' && 'true' || 'false' }}
HAS_WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERT_BASE64 != '' && 'true' || 'false' }}
HAS_APPLE_CERTIFICATE: ${{ secrets.CSC_LINK != '' && secrets.CSC_KEY_PASSWORD != '' && secrets.APPLE_ID != '' && secrets.APPLE_TEAM_ID != '' && secrets.APPLE_APP_SPECIFIC_PASSWORD != '' && 'true' || 'false' }}
HAS_WINDOWS_CERTIFICATE: ${{ secrets.WIN_CSC_LINK != '' && secrets.WIN_CSC_KEY_PASSWORD != '' && 'true' || 'false' }}
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
strategy:
fail-fast: false
matrix:
@ -177,6 +179,12 @@ jobs:
Compress-Archive `
-Path target\${{ matrix.target }}\release\op.exe `
-DestinationPath op-cli-${{ matrix.label }}.zip
- name: Import codesign certificate (macos)
if: runner.os == 'macOS' && env.HAS_APPLE_CERTIFICATE == 'true'
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.CSC_LINK }}
p12-password: ${{ secrets.CSC_KEY_PASSWORD }}
- name: Package DMG (macos)
if: runner.os == 'macOS'
shell: bash
@ -188,12 +196,11 @@ jobs:
# what this workflow built (and embeds the op CLI in Contents/MacOS).
OPENPENCIL_BINARY: ${{ github.workspace }}/target/${{ matrix.target }}/release/openpencil-desktop
OPENPENCIL_CLI_BINARY: ${{ github.workspace }}/target/${{ matrix.target }}/release/op
# Optional real-signing hook. No signing secrets exist today, so
# bundle-macos.sh falls back to ad-hoc ("-") signing. When a
# Developer ID cert lands, uncomment and add keychain import +
# notarization steps:
# MACOS_SIGN_IDENTITY: ${{ secrets.MACOS_SIGN_IDENTITY }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
if [ "$HAS_APPLE_CERTIFICATE" = "true" ]; then
export MACOS_SIGN_IDENTITY="Developer ID Application ($APPLE_TEAM_ID)"
fi
bash scripts/bundle-macos.sh
APP="target/${{ matrix.target }}/release/bundle/osx/OpenPencil.app"
STAGE="$(mktemp -d)"
@ -215,41 +222,40 @@ jobs:
# action needed to turn signing on.
#
# Required macOS secrets (Developer ID + notarization):
# APPLE_CERTIFICATE_P12 base64 of the Developer ID Application
# CSC_LINK base64 of the Developer ID Application
# .p12 export
# APPLE_CERTIFICATE_PASSWORD password for that .p12
# CSC_KEY_PASSWORD password for that .p12
# APPLE_TEAM_ID 10-char Apple Developer Team ID
# APPLE_ID Apple ID email used for notarization
# APPLE_APP_PASSWORD app-specific password for notarytool
# APPLE_APP_SPECIFIC_PASSWORD app-specific password for notarytool
#
# Required Windows secrets (Authenticode):
# WINDOWS_CERT_BASE64 base64 of the code-signing .pfx
# WINDOWS_CERT_PASSWORD password for that .pfx
- name: Import codesign certificate (macos)
if: runner.os == 'macOS' && env.HAS_APPLE_CERTIFICATE == 'true'
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE_P12 }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
# WIN_CSC_LINK base64/data URL/URL of the code-signing
# .pfx
# WIN_CSC_KEY_PASSWORD password for that .pfx
#
# Optional downstream publish secrets consumed by release packaging:
# NPM_TOKEN npm registry token for SDK publishing
# TAP_GITHUB_TOKEN GitHub token for tap/formula publishing
- name: Codesign + notarize DMG (macos)
if: runner.os == 'macOS' && env.HAS_APPLE_CERTIFICATE == 'true'
shell: bash
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
run: |
DMG="OpenPencil-$OP_VERSION-${{ matrix.arch }}-mac.dmg"
# The .app inside the DMG was ad-hoc signed by bundle-macos.sh;
# re-sign the DMG container with the real Developer ID identity,
# then notarize + staple so Gatekeeper accepts the download.
# The .app inside the DMG was signed by bundle-macos.sh after the
# Developer ID cert import above. Sign the DMG container too, then
# notarize + staple so Gatekeeper accepts the download.
IDENTITY="Developer ID Application ($APPLE_TEAM_ID)"
codesign --force --timestamp --options runtime \
--sign "$IDENTITY" "$DMG"
xcrun notarytool submit "$DMG" \
--apple-id "$APPLE_ID" \
--team-id "$APPLE_TEAM_ID" \
--password "$APPLE_APP_PASSWORD" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--wait
xcrun stapler staple "$DMG"
- name: Package NSIS installer (windows)
@ -273,12 +279,20 @@ jobs:
if: runner.os == 'Windows' && env.HAS_WINDOWS_CERTIFICATE == 'true'
shell: pwsh
env:
WINDOWS_CERT_BASE64: ${{ secrets.WINDOWS_CERT_BASE64 }}
WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
run: |
# Materialize the .pfx from the base64 secret into a temp file.
# Materialize the .pfx from a base64/data-url/url secret into a temp file.
$pfx = Join-Path $env:RUNNER_TEMP "codesign.pfx"
[IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($env:WINDOWS_CERT_BASE64))
$link = $env:WIN_CSC_LINK
if ($link -match '^https?://') {
Invoke-WebRequest -Uri $link -OutFile $pfx
} else {
if ($link -match '^data:.*;base64,(.+)$') {
$link = $Matches[1]
}
[IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($link))
}
$exe = "OpenPencil-$env:OP_VERSION-${{ matrix.arch }}-win-setup.exe"
# signtool ships with the Windows SDK preinstalled on
# windows-latest. RFC-3161 timestamp so signatures outlive the
@ -287,7 +301,7 @@ jobs:
Sort-Object FullName -Descending | Select-Object -First 1).FullName
& $signtool sign `
/f $pfx `
/p $env:WINDOWS_CERT_PASSWORD `
/p $env:WIN_CSC_KEY_PASSWORD `
/fd SHA256 `
/tr http://timestamp.digicert.com `
/td SHA256 `
@ -386,9 +400,11 @@ jobs:
tags: ${{ steps.meta.outputs.tag }}
sdk-packages:
name: Build web SDK npm tarballs
name: Build and publish web SDK npm packages
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
@ -420,6 +436,16 @@ jobs:
- name: Install package workspace dependencies
working-directory: packages
run: bun install --frozen-lockfile
- name: Configure npm auth
shell: bash
run: |
set -euo pipefail
if [ -z "${NPM_TOKEN:-}" ]; then
echo "::error::NPM_TOKEN is required to publish web SDK packages"
exit 1
fi
printf '//registry.npmjs.org/:_authToken=%s\n' "$NPM_TOKEN" > ~/.npmrc
npm whoami
- name: Build wasm-backed SDK packages
shell: bash
run: |
@ -440,6 +466,23 @@ jobs:
(cd "packages/${pkg}" && bun pm pack --destination "${GITHUB_WORKSPACE}/sdk-packages")
done
ls -la sdk-packages
- name: Publish npm packages
shell: bash
run: |
set -euo pipefail
version="${GITHUB_REF_NAME#v}"
publish_pkg() {
local name="$1"
local tarball="$2"
if npm view "${name}@${version}" version >/dev/null 2>&1; then
echo "::notice::${name}@${version} is already published; skipping"
return
fi
npm publish "$tarball" --access public --tag next
}
publish_pkg "@zseven-w/op-web-sdk" "sdk-packages/zseven-w-op-web-sdk-${version}.tgz"
publish_pkg "@zseven-w/op-web-sdk-react" "sdk-packages/zseven-w-op-web-sdk-react-${version}.tgz"
publish_pkg "@zseven-w/op-web-sdk-vue" "sdk-packages/zseven-w-op-web-sdk-vue-${version}.tgz"
- name: Upload SDK tarballs
uses: actions/upload-artifact@v4
with:
@ -452,6 +495,8 @@ jobs:
needs: [build, web-docker, sdk-packages]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
env:
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4

View file

@ -7,7 +7,7 @@
- Rust desktop app is now the primary OpenPencil experience, with installer artifacts for macOS, Windows, and Linux.
- `op` CLI ships as standalone release artifacts for the same desktop target matrix.
- Rust web host is published as a GHCR Docker image for tagged releases.
- Web SDK tarballs are attached for `@zseven-w/op-web-sdk`, `@zseven-w/op-web-sdk-react`, and `@zseven-w/op-web-sdk-vue`.
- Web SDK packages are published to npm and attached as tarballs for `@zseven-w/op-web-sdk`, `@zseven-w/op-web-sdk-react`, and `@zseven-w/op-web-sdk-vue`.
- Desktop update checks can discover pre-release GitHub releases, so `v0.8.0` can be offered before it is promoted to a stable release.
## Release Artifacts
@ -15,7 +15,7 @@
- macOS: `OpenPencil-0.8.0-<arch>-mac.dmg`, plus raw desktop and `op` CLI archives.
- Windows: `OpenPencil-0.8.0-<arch>-win-setup.exe`, plus portable desktop and `op` CLI archives.
- Linux: `OpenPencil-0.8.0-<arch>-linux.AppImage`, `OpenPencil-0.8.0-<arch>-linux.deb`, plus raw desktop and `op` CLI archives.
- Web SDK: npm tarballs for the base SDK, React adapter, and Vue adapter.
- Web SDK: published npm packages and attached npm tarballs for the base SDK, React adapter, and Vue adapter.
## Docker
@ -25,7 +25,7 @@ The release workflow publishes the web image to GHCR as:
docker pull ghcr.io/zseven-w/openpencil-web:v0.8.0
```
Because this is a pre-release, the workflow does not publish or update a `latest` tag.
Because this is a pre-release, the workflow does not publish or update a Docker `latest` tag. The npm packages are published with the `next` dist-tag.
## Notes