エレクトロンアプリの自動更新を配信した後、リリースページが公開され、最初のサポートチケットが到着する前にコーヒーメーカーが終了するまで。1つのユーザーはアプリがアップデートを見つけることができなかった。もう1人はダウンロードしたがインストールすることができなかった。3番目のユーザーは古いバイナリを実行し、認証フローが破損している。ログにはほとんど有用な情報が表示されていない。
それは、 Electron アプリの自動更新. updater API は、1 つのコンポーネントのみです。生産用リリースも、プラットフォームの署名、トランスポートポリシー、マニフェスト、ホスティング、ライフサイクルイベント、観察性、ロールアウト制御、およびロールバックパスに依存します。 1 つを任意のものとして扱い、定期的なパッチは 1 夜の出来事になります。
目次
- 2 時間の夜の更新インシデントがこのガイドの始まり
- Electron アップデータの適切なパスを選択する
- メインプロセスで自動更新フローを実装する
- 署名されたリリースとマニフェストのためのCI/CDを組み込む
- ロールアウト、チャネル、およびロールバック戦略
- 自動更新をセキュリティコントロールとして扱う
- プロダクションアップデートの実行計画とチェックリスト
2時8分のアップデートインシデントがこのガイドの始まり
リリースはCIを通過し、通常のもののように見えました。金曜日の夜遅く、開発者は署名されていないElectronビルドをプッシュし、公開ジョブはリリースが完了しているように見えるようにアセットをアップロードしました。アプリケーションはテストで起動しましたが、誰もインストール済みのプロダクションビルドからアップデートパスを実行していませんでした。
2時8分、PagerDutyはオンコールエンジニアに警告を送りました。新しい認証フローは一部の艦隊で失敗し、アップデートを受けたユーザーはサインインを完了できませんでした。ユーザーはアップデートを検証またはインストールできなかったため、前のバージョンに留まりました。顧客は一部が破損したリリースを使用し、残りの艦隊は異なるバージョンを実行し、明確な説明がなかった。
調査は5つのチェックに従った:
- リリースフィードを確認する バイナリは存在しましたが、期待どおりのメタデータは、どのクライアントが受け取るべきか明確に示していませんでした。マニフェストは、リリースパイプラインとインストール済みクライアントとの契約であり、オプションのアップロード詳細ではありません。
- 署名を検査してください。 署名が正しくないため、影響を受けるプラットフォームで検証が失敗しました。署名が欠落している場合または無効な場合、署名は出版をブロックする必要があります。
- クライアントログを比較してください。 アップデートエラーは、中央のテレメトリに届かなかった。アプリケーションはイベントを飲み込んで実行を続け、チームには信頼できる証拠が得られませんでした。
- ロールアウト制御を確認してください。 内部チャネルまたはステージドコホートが存在していませんでした。すべての有効なクライアントは同じフィードを使用していたため、失敗は拡散し、隔離ポイントが存在していませんでした。
- ロールバックを探してください。 チームには、前のバージョンを再公開したり、クライアントを破損したリリースから遠ざけるためのテスト済み手順が存在していませんでした。
Electronの公式ドキュメントでは、プラットフォームの制限が明確に示されています。 Linuxには、自動アップデートのサポートが組み込まれていません。、macOSのアップデート要求は、 App Transport Security の要件ドキュメントでは、macOS の更新とリリースの検証のために署名が必須であることも明記されています。 Electron の autoUpdater ドキュメント API の制約を定義し、リリースシステムは周辺の運用制御を強制する必要があります。
Postmortem の教訓: アップデートが何が起こったのか説明できないアップデートは、不完全なテレメトリと共にリモートのインストール試行とみなされます。
コストはエンジニアリング時間だけではなく、拡大しました。顧客はデスクトップクライアントに対して信頼を失い、サポートは不一致な動作を説明し、チームはインシデントが発生する前に存在するはずだったリリースプロセスを再構築するために翌日を費やしました。
アップデートを運用システムとして扱う 署名はリリースゲート、manifests はクライアント契約を定義し、ロールアウトチャネルは露出を制限し、ロールバックはテスト済みのパスであるべきです。Electron のアップデータの選択肢
2 時間後の間違ったアップデータの選択肢は運用上の問題となります。ネイティブバイナリのアップデートは署名、manifests、インストーラー、ロールバックを処理する必要があります。レンダラー専用の JavaScript または CSS の変更は異なるパスを辿ります。ホスティング制約も考慮すべきです: 小規模な __CAPGO_KEEP_0__ ホストされたプロジェクトには、エンタープライズ配布サービスと同じリリース制御が必要ではありません。
At 2 a.m., the wrong updater choice becomes an operational problem. A native binary update must handle signing, manifests, installers, and rollback. A renderer-only JavaScript or CSS change follows a different path. Hosting constraints also matter: a small GitHub-hosted project does not need the same release controls as an enterprise distribution service.
Electron Builder を使用するプロジェクトの場合、署名アーティファクトの公開とともに、 electron-updater 通常は実用的なデフォルトです。 Electron updater integration for Capgo アーティファクトのダウンロード、
update-electron-app suits teams that want a small integration around GitHub Releases. It checks at startup and then on a recurring interval, which keeps the setup simple but leaves less room for advanced channel selection, staged traffic, and custom rollback rules. The package is reasonable for a small release process, provided GitHub Releases and its availability match your operational requirements.
| 複数のホスティングモデルをサポートしていますが、 | チームは署名、 | フィードの可用性、 | チャンネルポリシー、 | ロールアウトの制御、 |
|---|---|---|---|---|
| 監視を所有しています。 | S3、GitHub、汎用HTTPS、他社の公開先 | リリースされたパッケージと統合された署名 | 強固な基盤、カスタムポリシーは通常フィードに囲まれている | 中 |
| update-electron-app | 主にシンプルなGitHubリリースワークフロー | 下位のElectron署名モデルを使用 | 制限が少ない、サーヴィスを追加するまで | 低 |
| Squirrel.WindowsまたはSquirrel.Mac | プラットフォームに特化した配布フロー | プラットフォームの署名要件に依存 | 可能ですが、通常は追加のリリースインフラが必要です。 | レガシーアプリケーション向けのモジュレート |
| カスタムサービス | マニフェスト、認証、コホート、フィードの完全な制御 | 検証設計とキー管理を自社で行う | 最大限の柔軟性 | 高 |
| Capgo ライブアップデート | ウェブ層のバンドル用のマネージド配信 | アップデータと配信モデルを使用 | ターゲットアウディエンスとチャネルベースの配信 | ネイティブバイナリアップデートから独立した運用モデル |
Azure Functions、Hazel、Nutsなどのカスタムサービスが、リリースの承認、テナントのターゲット設定、監査レコード、または規制されたデプロイのルールが実装コストを正当化する場合に適合します。トレードオフは、継続的な所有権です。チームはマニフェストの意味を定義し、署名キーを保護し、クライアントの互換性を維持し、ダウンロードの失敗、リリースの拒否、ロールバックの動作をテストする必要があります。
ライブアップデートは、レンダラーのみの変更を送信できますが、ネイティブシェルの再構築は必要ありません。Electron、ネイティブモジュール、パーミッション、またはインストーラーの動作が変更された場合、バイナリアップデートは置き換えられません。 electron-updaterを使用する場合は、カスタムロールアウトロジックが必要ない限りです。 カスタムロジックが必要な場合は、既存のマニフェストとアーティファクトの慣習を基に構築するのではなく、ダウンロードと差分アップデートの動作を再現するのではなく、依存できるパスを選択してください。チームは、プレッシャー下でも観察、ステージ、逆行できるようにする必要があります。
メインプロセスでAuto-Updateフローを実装する
メインプロセスはアップデートのチェックとインストールを所有する必要があります。レンダラーはステータスを表示できますが、実行可能なアップデートを信頼するか、またはアプリケーションが終了するときに決定することはできません。
まず、公開先を設定してください。
最小限のelectron-builderの構成は次のようになります。
{
"build": {
"appId": "com.example.desktop",
"publish": [
{
"provider": "s3",
"bucket": "example-electron-releases",
"channel": "stable"
}
],
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true
}
}
}
ベータとステーブルフィードを分離してください。チャンネルはUIのラベルではなくリリースポリシーです。各チャンネルは正しい署名されたアーティファクトとマニフェストに解決する必要があります。
チェックのスケジュールとライフサイクルイベントの公開
コール checkForUpdates() 起動時のみの更新は、一般的なプロダクションのミスです。ユーザーはアプリケーションを開いたままにし、数日間続けることができるため、メインプロセスには制御された間隔とリトライ戦略が必要であり、オフラインオペレーションを尊重する必要があります。
const { app, BrowserWindow, ipcMain } = require('electron');
const { autoUpdater } = require('electron-updater');
let mainWindow;
let isQuitting = false;
let retryDelay = 60 * 1000;
function sendUpdateStatus(status, payload = {}) {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('update-status', { status, ...payload });
}
}
function scheduleUpdateCheck() {
setTimeout(async () => {
try {
await autoUpdater.checkForUpdates();
retryDelay = 60 * 1000;
} catch (error) {
sendUpdateStatus('error', { message: error.message });
retryDelay = Math.min(retryDelay * 2, 30 * 60 * 1000);
}
scheduleUpdateCheck();
}, retryDelay);
}
app.whenReady().then(() => {
mainWindow = new BrowserWindow({
webPreferences: {
preload: require('path').join(__dirname, 'preload.js')
}
});
autoUpdater.autoDownload = true;
autoUpdater.autoInstallOnAppQuit = false;
autoUpdater.on('checking-for-update', () => {
sendUpdateStatus('checking');
});
autoUpdater.on('update-available', info => {
sendUpdateStatus('available', { version: info.version });
});
autoUpdater.on('download-progress', progress => {
sendUpdateStatus('progress', { percent: progress.percent });
});
autoUpdater.on('update-downloaded', info => {
sendUpdateStatus('downloaded', { version: info.version });
});
autoUpdater.on('error', error => {
sendUpdateStatus('error', { message: error.message });
});
autoUpdater.checkForUpdates().catch(error => {
sendUpdateStatus('error', { message: error.message });
});
scheduleUpdateCheck();
});
ipcMain.handle('install-update', () => {
isQuitting = true;
autoUpdater.quitAndInstall(false, true);
});
app.on('before-quit', event => {
if (!isQuitting) {
return;
}
});
更新イベントの正確な動作はプラットフォームとパッケージング設定によって異なります。開発モードではなく、インストールされたアーティファクトからテストすることが推奨されます。Electronのドキュメントでは、Windowsの起動タイミングに関する懸念を指摘しています、特にSquirrelの初回起動ケースです。アプリケーションが必要なプラットフォーム固有の初期化を完了する前に、更新チェックをトリガーしないでください。
ワークをブロックせずにレンダラーに情報を伝えます。
プリロードブリッジは、狭いAPIを公開する必要があります。
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('updates', {
onStatus(callback) {
ipcRenderer.on('update-status', (_event, status) => callback(status));
},
install() {
return ipcRenderer.invoke('install-update');
}
});
レンダラー側の進行状況バーは、意図的に単純なままにしておくことができます。
window.updates.onStatus(status => {
const progress = document.querySelector('#update-progress');
const message = document.querySelector('#update-message');
if (status.status === 'progress') {
progress.hidden = false;
progress.value = status.percent;
message.textContent = `Downloading update, ${Math.round(status.percent)}%`;
}
if (status.status === 'downloaded') {
message.textContent = `Version ${status.version} is ready to install`;
}
if (status.status === 'error') {
message.textContent = 'The update could not be downloaded. We will retry later.';
}
});
プロダクションでは、ユーザーの同意なしにインストールをゲートすることは避けるべきです。ただし、すぐに再起動する必要があるアプリケーションがあれば除きます。セットする旗は isQuitting 、通常のウィンドウクローズハンドラーがインストーラーがオーバーを取るのを防ぐのを防ぐため、 quitAndInstall()https://raw.githubusercontent.com/electron-userland/electron-builder/master/docs/electron-builder-autoupdate.png からスクリーンショット

のスケジュールに呼び出す必要があります。起動時のみではありません。2 番目に、 checkForUpdates() イベントはログとテレメトリに到達する必要があります。アプリケーションが報告しない場合、 error イベントを無視することは、 アプリケーション トラブルシューティング ワークフロー 証拠ではなく推測から始まる
CI/CD を有効にするには署名されたリリースとマニフェスト
リリース パイプラインはユーザーがインストールするものの元となる情報です。ローカル ビルドが 1 つの開発者のマシンで動作することは、公開されたバイナリ、 マニフェスト、署名、チャネルがすべて同じリリースを表すことを証明するものではありません。
Electron-builder の publish モデルでは、リリース メタデータとアップデートのターゲットが一緒に移動することを期待しています。多くの構成では、リリース メタデータとアップデートのターゲットが一緒に移動することを期待しています。多くの構成では、バイナリ、 マニフェスト、署名、チャネルがすべて同じリリースを表すことを証明するものではありません。 latest.yml Windows と macOS のそれぞれのプラットフォーム固有のパッケージとブロックマップ ファイルのセットです。マニフェストが欠けている場合、完全に有効なバイナリはクライアントに表示されません。 latest-mac.yml 署名を CI で明示的に行う
Actions のシンプル化されたパターンは次のようになります:
A simplified GitHub Actions pattern looks like this:
name: release
on:
push:
tags:
- "v*"
jobs:
build:
strategy:
matrix:
os: [macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run test
- run: npm run build
- name: Build and publish
shell: bash
env:
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: npx electron-builder --publish always
変数
| 目的 | ページ/エリア: Capgo マーケティング ウェブサイト。役割: ショート UI ラベルまたはナビゲーション アイテム。メッセージ キー `subprocessors_table_purpose` (Subprocessors Table Purpose)。 |
|---|---|
CSC_LINK |
macOS証明書または証明書参照 |
CSC_KEY_PASSWORD |
macOS署名材料のパスワード |
WIN_CSC_LINK |
Windows証明書または証明書参照 |
AWS_ACCESS_KEY_ID |
限定されたアクセスを有する公開資格情報 |
AWS_SECRET_ACCESS_KEY |
公開資格情報のシークレット |
公開設定では、プロバイダーとチャネルを一貫して識別するようにする必要があります:
{
"build": {
"publish": {
"provider": "s3",
"bucket": "example-electron-releases",
"channel": "stable",
"publishAutoUpdate": true,
"updaterCacheDirName": "example-desktop-updater"
}
}
}
公開前に、パッケージバージョン、タグ、コミットSHA、smokeテスト結果でジョブをゲートする。公開後、フィードに期待どおりのマニフェストが含まれていることを確認し、マニフェストが生成したジョブによって生成された正確なアーティファクトに指示していることを確認する。 継続的インテグレーション設定ガイド チェックを正式化する際に役立つ場合があり、pipelineオーケストレーションを比較するチームも、JenkinsとAnsibleを組み合わせる際のタイミングを理解することで利益を得ることができる 一般的に不完全なリリースを露呈するコマンドは意図的に面白みがない:.
チェックは署名インストールテストを置き換えるものではない。アップロードされたバイナリに必要なメタデータを検出するために必要なクライアントが存在しないことを操作上のミスとして捉える。
npx electron-builder --publish never
test -f dist/latest.yml
test -f dist/latest-mac.yml
find dist -name "*.blockmap" -print
Those checks don’t replace a signed installation test. They do catch the operational mistake of uploading a binary without the metadata clients need to discover it.
ロールアウト、チャンネル、ロールバック戦略
リリースフィードは、展開先としてではなくダウンロードフォルダとして振舞うべきです。内部 内部, ベータ、 最新 チャンネルを分離し、各チャンネルは独自のマニフェストと署名アーティファクトセットによって裏付けられます。プロモーションは、テストされたリリースをポリシー間で移動するのではなく、クライアントがダウンロード中のファイルを上書きしないようにするべきです。
チャンネル分離は、誤ってテストビルドが生産環境に流れ込まないように保護します。アップデーターは、クライアントが内部コホート、ベータアウディエンス、または安定した人口に属しているかを判断する前に、フィードを評価する必要があります。
コホートを使用する前に広範な露出
カスタムマニフェストフィールドは、ステージングされた配信を表現できます:
version: 4.8.0
path: Example-Setup-4.8.0.exe
sha512: signed-artifact-hash
rolloutPercentage: 10
メインプロセスは安定したユーザーごとのバケットを割り当て、次にそのバケットを rolloutPercentageと比較します。安定した割り当ては重要です。ユーザーが毎回有効または無効の状態に切り替わると、予期せぬ動作を受け、サポートの報告が難しくなります。
リリースが観測ウィンドウを通過した後、コホートを拡大する。ウィンドウの精度は、使用パターンに基づいて反映されるべきですが、決定はシグナルに基づいて行われるべきであり、カレンダーだけに頼るべきではありません。アップデートチェック結果、ダウンロード完了、起動健全性、クラッシュ、レンダラー例外、認証成功を追跡する。
| シグナル | アクション | 理由 |
|---|---|---|
| フィードまたは署名エラーがチームの承認制限を超えている | ロールアウトを保留 | クライアントがリリースを検証または検出できない |
| ポストアップデート起動チェックが失敗 | フィードを戻す | バイナリがインストールされるが起動中に失敗 |
| レンダラー例外がプロモーション後にも増加 | 現在のコホートで保留する | ネイティブのインストーラーは正常な状態のままですが、新しいアプリケーションcodeは正常ではありません。 |
| 信号はリリース予算内に残っています。 | コホートを拡大する。 | 証拠はより広範な露出を裏付けます。 |
ロールバックとアーティファクトの削除を混同しないでください。既存のクライアントにはキャッシュされたメタデータが存在し、既に悪いバージョンを実行しているクライアントも存在する可能性があります。ロールバック計画には前の署名済みリリース、フィードの変更、およびクライアントの動作が必要です。これにより、元のバージョンに復元できます。
運用ルール: ロールバックは、インシデント発生時にアプリケーションを再構築せずに、オンコールエンジニアが実行できるようにする必要があります。
実際には、ランブックは影響を受けたチャネルに前のリリースマニフェストをプロモートし、ステージングマーカーを無効化し、新しいチェックが安全なバージョンに解決されることを確認する必要があります。問題がレンダラーcodeではなくネイティブシェルにある場合、ターゲットされたWeb層ロールバックが速くなります。 Capgo phased rollouts Auto-Updateをセキュリティコントロールとして扱う。
Electronのアップデートツールは実行可能__CAPGO_KEEP_0__をダウンロードし、ユーザーが少ない操作でインストールすることができます。そのため、更新パスは
An Electron updater downloads executable code and can install it with little user interaction. That makes the update path a セキュリティ境界セキュリティ上の問題であり、単に便利な機能ではありません。Electronの公式ドキュメントでは、macOS ATSなどのプラットフォーム制約について説明されており、セキュリティカバレッジは2022年のシナリオを文書化しており、攻撃者が更新インフラストラクチャを制御している場合、まだcode署名チェックを通過する可能性がある悪意のあるパッケージを提供することができました。これについては、 Electron Builderの自動更新セキュリティドキュメント.
Code署名は基本的なものですが、信頼モデル全体ではありません。すべてのリリースを署名し、CIで証明書とアイデンティティを検証し、ドキュメント化されたキーローテーション手順を維持してください。macOSでは署名と認証を組み合わせ、適切なアプリケーションにハード化されたランタイムを使用してください。Windowsでは、証明書の所有権、更新、ビルドへのアクセスを監査してください。Linuxでは、Electronが提供する統一的なアップデータを使用できないため、ディストリビューション固有の戦略が必要です。
メタデータをバイナリと同じように保護する
署名されたバイナリは、メタデータチャネルが侵害または不正設定されている場合に、間違ったリリースと関連付けられる可能性があります。パブリックキーをアプリケーションに埋め込んだものと検証されたマニフェスト署名を追加し、最低許可されたバージョンを強制し、予期せぬダウングレードを拒否することを検討してください。ただし、承認された回復パスが明示的に許可する場合を除き。
フィードにも生産管理が必要です:
- 公開アクセスを制限する CIにリリースアセットを公開する権限を与えるだけにします。
- 署名シークレットを保護する 証明書と秘密鍵をマネージドシークレットストレージに保管し、リポジトリファイルにはしないでください。
- 依存関係を固定する: CIでElectron、electron-builder、依存関係を固定する。
- アーティファクトを確認する: 生成されたパッケージをスキャンし、意図したコミットとバージョンとを比較する。
- 安全なトランスポートを要求する: ATSと厳格なHTTPS要件に従ってアップデート要求を実行する。
- 検証失敗を監視する: 署名またはマニフェストの繰り返し失敗をセキュリティイベントとして扱い、通常のネットワークノイズとして扱わない。
Electronのメンテナンスされたツールキットは、パッケージングとアップデートのカバレッジを追加していますが、脅威モデリングの必要性は維持されます。実際の目標は、攻撃者がバケット、CDN、またはビルドステップを乗っ取っても、クライアントが承認されていないリリースを受け入れないようにすることです。 署名検証ガイドライン 脅威モデリングの追加検証層を設計するための有用なコンテキストを提供します。

生産用更新実行書とチェックリスト
リリースは、他のエンジニアがプレッシャー下でも操作できるようになるまで待たなければなりません。チェックリストは、デプロイジョブとインシデントチャンネルに近く保ちましょう。
プレリリースゲート
- バージョン識別 パッケージバージョン、リリースタグ、コミットSHA、変更履歴が一致していることを確認してください。
- 署名 すべてのプラットフォームアーティファクトが署名され、認証または同等の検証が完了していることを確認してください。
- マニフェスト契約 確認
latest.yml,latest-mac.ymlアップロードされたアーティファクトのハッシュ、パス、ブロックマップと一致していることを確認してください。 - チャンネル安全 内部またはベータフィードに公開する前にリリースチャンネルを昇格することを確認してください。
- メトリクス: 確認更新チェック、ダウンロード進捗、インストール完了、起動正常性、エラーの到着はあります。
カニバリとフルロールアウト
- コホート制御: 内部またはベータ版の意図的に小さな内部またはベータ版のユーザーから始めます。
- 健康予算: リリースの失敗、更新ダウンロードの失敗、レンダラー例外、または認証の失敗がチームの承認された制限を超えると、プロモーションを保留します。
- プロモーション承認: リリースを安定フィードに移動する前に、明確な「進む」または「止める」決定を要求します。
- 顧客への影響: 広範な配布前に、最初のインシデント後にサポートメッセージを準備します。
インシデント対応
新ビニヤリが起動しない場合、プロセス生成が途切れ、またはアップデートのダウンロードが完了しない場合、即座にプロモーションを停止してください。前の署名されたマニフェストを復元し、ステージングマーカーを無効化し、最新のクライアントが前のバージョンに解決されることを確認し、次に、テレメトリを通じて艦隊が回復していることを確認する。最後に、クロージャーを伝える前に確認してください。
プロバイダーによっては、ロールバックコマンドが異なる場合がありますが、シーケンスは常にドキュメントされるべきです: チャネルマニフェストを前のバージョンに切り替え、ステージングタグを無効化し、回復が必要な場合は強制アップデートマーカーをプッシュし、ライブテレメトリを通じてダウングレードパスを検証します。テストされていないロールバックはただの希望です。

Capgoは、各レンダラー変更に対してネイティブシェルを再構築することなく、署名されたウェブ層の変更を提供するためのElectronのアップデートツールです。ターゲットチャンネル、ロールアウト制御、更新観察性を提供します。ネイティブバイナリーリリースを制御されたJavaScriptとCSSの配信から分離したい場合は、以下のURLを訪問してください。 Capgo __CAPGO_KEEP_0__