Electronのビルドを出荷したあと、リリースページが公開され、最初のサポートチケットが来る前に、コーヒーメーカーが終わる前に。
そのような状況は Electronアプリの自動更新. The updater API is only one component. A production release also depends on platform signing, transport policy, manifests, hosting, lifecycle events, observability, rollout controls, and a rollback path. Treat any one of those as optional and a routine patch can become an overnight incident.
アップデータの__CAPGO_KEEP_0__は、単なるコンポーネントです。生産的なリリースは、プラットフォームの署名、トランスポートポリシー、マニフェスト、ホスティング、ライフサイクルイベント、オブザビリティ、ロールアウトコントロール、そしてロールバックパスなど、多くの要素に依存しています。どれかを省略すると、定期的なパッチは深夜のインシデントになる可能性があります。
- 目次
- 2時台のアップデートインシデントがこのガイドの始まり
- Electronアップデータの適切なパスを選択する
- CI/CDの設定を自動更新用の署名されたリリースとマニフェストに接続する
- Make signing explicit in CI
- Rollouts, Channels, and Rollback Strategy
- Use cohorts before broad exposure
Protect the metadata as carefully as the binary
バイナリと同様にメタデータを保護する必要がある
2時08分、PagerDutyはオンコールエンジニアに警告した。fleetの一部で新しい認証フローが失敗し、更新を受けたユーザーはサインインを完了できなかった。別のユーザーは前のバージョンに留まっていた。アップデータはアーティファクトを検証またはインストールできなかったためである。
調査は5つのチェックに続いた。
- リリースフィードを確認する。 バイナリは存在したが、期待されるメタデータは明確にクライアントが受け取るべきであることを示していなかった。マニフェストはリリースパイプラインとインストールされたクライアントとの契約であり、オプションのアップロード詳細ではない。
- 署名を検査する。 リリースは正しく署名されていなかったため、影響を受けたプラットフォームで検証が失敗した。署名は欠落または無効の場合に発行をブロックする必要がある。
- クライアントログを比較する。 アップデートエラーは中央のテレメトリに届かなかった。アプリケーションはイベントを飲み込んで実行を続け、チームには信頼できる証拠がなかった。
- ロールアウト制御を確認する。 内部チャネルやステージドコホートは存在しなかった。有効なクライアントはすべて同じフィードを使用していたため、失敗は拡散し、隔離ポイントがなかった。
- ロールバックを探す。 チームにはテスト済みの手順がなかった。前のバージョンを再発行したり、クライアントを破損したリリースから遠ざけたりする方法がなかった。
Electronの公式ドキュメントでは、プラットフォームの制限が明確に示されています。 Linuxには自動アップデートのサポートが組み込まれていません。、およびmacOSのアップデート要求はApp Transport Securityの要件を満たす必要があります。 App Transport Security 要件ElectronのautoUpdaterドキュメントでは Electron 自動更新ドキュメント CapgoはAPIの制約を定義し、リリースシステムは周囲の運用制御を強制する必要があります。
アップデータが何が起こったのか説明できない場合、リモートのインストール試行に欠落しているテレメトリが含まれることになります。 コストはエンジニアリング時間の他に、さらに拡大しました。顧客はデスクトップクライアントに対して信頼を失い、サポートチームは不一致な動作を説明する必要があり、チームはその後1日間をリリースプロセスの再構築に費やしました。そうしたプロセスは事故が発生する前に存在するはずでした。
自動アップデートを
運用システム として扱うことが重要です。. Signing is a release gate, manifests define the client contract, rollout channels limit exposure, and rollback remains a tested path rather than an emergency invention.
Electron アップデートの選択肢
2 時間の間、不正解のアップデート選択肢は運用上の問題となる。ネイティブバイナリアップデートは署名、メニュー、インストーラー、ロールバックを処理する必要がある。一方、レンダラー専用のJavaScriptまたはCSS変更は異なるパスを辿る。ホスティング制約も考慮すべきである: 小規模GitHubホストされたプロジェクトには、企業向け配布サービスと同じリリース制御が必要ではない。
electron-builderを使用するプロジェクトで署名済みアーティファクトの公開を行っている場合 electron-updater 通常、実用的デフォルトである。エコシステムは、公開対象、リリースマニフェスト、アーティファクトダウンロード、インストールの次の起動時にサポートしている。複数のホスティングモデルをサポートしているが、チームは署名、フィードの可用性、チャンネルポリシー、ロールアウト制御、監視を所有している。 Electron updater integration for Capgo は、Web層のバンドルとネイティブリリースのハイブリッド配信モデルを評価する際に、関連性がある。
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.
| オプション | ホスティング制御 | 署名サポート | チャンネル & ステージド ロールアウト | メンテナンスの負担 |
|---|---|---|---|---|
| electron-updater | S3、GitHub、汎用 HTTPS、その他の公開先 | パッケージ化されたリリース署名と統合 | 強固な基盤、カスタムポリシーは通常フィード周辺に存在 | 中 |
| update-electron-app | 主にシンプルなGitHubリリースワークフロー | 下位のElectron署名モデルを使用 | 制限が少ない、サーヴィスを追加することで拡張可能 | 低 |
| Squirrel.Windows or Squirrel.Mac | プラットフォームに基づく配布フロー | プラットフォームの署名要件に依存 | 可能ですが、通常は追加のリリースインフラが必要 | レガシーアプリケーション向けにモジュレート |
| カスタムサービス | マニフェスト、認証、コホート、フィードの制御 | 検証設計とキー管理を自社で行う | 最大限の柔軟性 | 高 |
| Capgo ライブアップデート | ウェブ層のバンドルに対するマネージド配布 | Electronアプリの自動更新 | 対象ユーザーとチャネルベースの配信 | ネイティブバイナリ更新とオペレーショナルモデルを分離 |
リリース承認、テナントターゲット、監査レコード、または規制されたデプロイ規則が実装コストを正当化する場合、カスタムサービスとしてHazel、Nuts、または内部フィードを使用します。代償は、継続的な所有権です。チームはマニフェストの意味を定義し、署名キーを保護し、クライアントの互換性を維持し、ダウンロードの失敗、リリースの拒否、ロールバックの動作をテストする必要があります。
ライブアップデートはレンダラーのみの変更を送信できますが、ネイティブシェルを再構築する必要はありません。Electron、ネイティブモジュール、パーミッション、またはインストーラーの動作が変更された場合、バイナリアップデートを置き換えることはできません。 Electron-アップデートを使用することから始めます。カスタムロールアウトロジックが必要な場合は別の方法を検討してください。 カスタムロジックが必要な場合は、ダウンロードと差分アップデートの動作を再現するのではなく、establishedマニフェストとアーティファクトの慣習を基に構築することをお勧めします。
メインプロセスで自動更新フローを実装する
パブリッシュターゲットを設定する必要があります。
最小限のelectron-builderの構成は次のようになります。
__CAPGO_KEEP_0__
{
"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回の失敗は明示的なテストに値する。最初に、既に起動中のクライアントはスケジュールに従って呼び出す必要がある。2番目に、イベントはログとテレメトリに到達する必要がある。アプリがイベントを報告せずに飲み込むと、 checkForUpdates() アプリのトラブルシューティングワークフローは証拠ではなく推測に始まる。 error CI/CDを署名されたリリースとマニフェストと組み合わせる リリースパイプラインはユーザーがインストールするものの元となるソースです。ローカルビルドが1人の開発者のマシン上で動作することは、公開されたバイナリ、 マニフェスト、署名、チャネルが同じリリースを表すことを証明するものではありません。
CI/CDの設定を自動更新用の署名されたリリースとマニフェストに接続する
Windows用の
macOS用の latest.yml アーティファクトが必要です。マニフェストが欠けていると、完全に有効なバイナリがクライアントに見えなくなります。 latest-mac.yml 署名をCIで明示的にする
シンプルな__CAPGO_KEEP_0__ 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
プラットフォーム固有のシークレットを使用し、署名材料をリポジトリ外に保管する。署名が失敗した場合、ジョブを停止するようにし、誰かが手動でアップロードするための署名なしのフォールバックを生成しないようにする。
| 変数 | 目的 |
|---|---|
CSC_LINK |
macOS証明書または証明書参照 |
CSC_KEY_PASSWORD |
macOS 証明書または証明書参照 |
WIN_CSC_LINK |
macOS 署名材料のパスワード |
AWS_ACCESS_KEY_ID |
Windows 証明書または証明書参照 |
AWS_SECRET_ACCESS_KEY |
限定されたアクセスを持つ公開資格情報 |
公開資格情報とペアされたシークレット
{
"build": {
"publish": {
"provider": "s3",
"bucket": "example-electron-releases",
"channel": "stable",
"publishAutoUpdate": true,
"updaterCacheDirName": "example-desktop-updater"
}
}
}
公開設定では、プロバイダーとチャネルを一貫して識別するようにする必要があります: 継続的インテグレーション設定ガイド 継続的インテグレーション設定ガイドは、チェックを正式化する際に役立ち、パイプライン オーケストレーションを比較するチームも、理解することで利益を得ることができる。 JenkinsとAnsibleを一緒に使用するタイミング.
意図的に面白みのないコマンドが、不完全なリリースを公開することが多い:
npx electron-builder --publish never
test -f dist/latest.yml
test -f dist/latest-mac.yml
find dist -name "*.blockmap" -print
チェックは署名されたインストールテストを置き換えるものではない。アップロードされたバイナリに必要なメタデータを取得するために、クライアントが必要とするものである。
ロールアウト、チャネル、ロールバック戦略
リリースフィードは、展開先として振る舞うべきであり、ダウンロードフォルダとして振る舞うべきではない。内部 内部, ベータ, 最新 チャネルを分離し、各チャネルは独自のマニフェストと署名されたアーティファクトセットによって裏付けられている。プロモーションは、テストされたリリースをポリシー間で移動するのではなく、クライアントがダウンロード中のファイルを上書きしないようにする。
チャネル分離は、誤ってテストビルドが生産環境に流れ込まないように保護する。アップデーターは、クライアントが内部コホート、ベータアウディエンス、または安定した人口に属しているかを判断する前に、フィードを評価する必要がある。
コホートを使用する前に広範な露出を避ける
カスタムマニフェストフィールドは、ステージング配信を表現できます:
version: 4.8.0
path: Example-Setup-4.8.0.exe
sha512: signed-artifact-hash
rolloutPercentage: 10
メインプロセスは、安定したユーザーごとのバケットを割り当て、次にそのバケットを rolloutPercentageと比較します。安定した割り当ては重要です。チェックごとに有効かつ無効の状態に移行するユーザーは、予期せぬ動作を受け、サポートレポートの解釈が困難になります。
リリースが観察期間を乗り越えた後、コホートを拡大してください。観察期間の精度は、使用パターンに基づいて決定する必要がありますが、シグナルに基づいて決定する必要があります。アップデートチェック結果、ダウンロード完了、起動健全性、クラッシュ、レンダラー例外、認証成功を追跡してください。
| シグナル | アクション | 理由 |
|---|---|---|
| フィードまたは署名エラーがチームが承認した制限を超えます | ロールアウトを保留 | クライアントがリリースを検証または検出できない場合 |
| ポストアップデート起動チェックが失敗 | フィードを元に戻す | バイナリはインストールされるかもしれませんが、起動中に失敗する可能性があります。 |
| レンダラー例外はプロモーション後にも増加します。 | 現在のコホートで停止します。 | ネイティブインストーラーは正常な状態であるかもしれませんが、新しいアプリケーションcodeは正常ではありません。 |
| シグナルはリリース予算内に残っています。 | コホートを拡大します。 | より広範な露出を支持する証拠があります。 |
ロールバックとアーティファクトを削除するのを混同しないでください。既存のクライアントはキャッシュされたメタデータを持っており、すでに悪いバージョンを実行している可能性があります。ロールバック計画には、前の署名されたリリース、フィードの変更、クライアントの動作が安全なバージョンに回復できる必要があります。
運用ルール: ロールバックは、インシデント中のアプリケーションを再構築せずに、オンコールエンジニアが実行できる必要があります。
実際には、ロールバック本番に必要なのは、影響を受けたチャネルに前のリリースマニフェストをプロモートし、ステージングマーカーを無効化し、新しいチェックが安全なバージョンに解決されることを確認することです。レンダラーcodeの問題がネイティブシェルの問題ではなく、ターゲットされたウェブ層ロールバックが速い場合があります。ロールアウトのフェーズ化を実行するプラットフォームは Capgo Electron アプリの自動更新の場合、別の配信レイヤーに関連する可能性がありますが、ネイティブバイナリのロールバックとウェブバンドルのロールバックの境界を曖昧にするべきではありません。
Auto-Update をセキュリティコントロールとして扱う
Electron のアップデートツールは、実行可能な code をダウンロードし、ユーザーが少ない操作でインストールできるため、更新パスは セキュリティの境界セキュリティの境界であり、単に便利な機能ではありません。Electron の公式ドキュメントでは、macOS ATS のプラットフォーム制約などを説明し、セキュリティカバレッジは 2022 年のシナリオを文書化しており、攻撃者が更新インフラストラクチャを制御し、まだ code-署名チェックを通過するのに害のあるパッケージを提供することができたことを説明しています。 Electron Builder の自動更新セキュリティドキュメント.
Code 署名は基礎となるものですが、全体の信頼モデルではありません。すべてのリリースに署名し、CI での証明書とアイデンティティの検証を行い、文書化されたキーローテーション手順を維持してください。macOS の場合、署名と認証に合わせてハード化されたランタイムを適切に組み合わせてください。Windows の場合、証明書の所有権、更新、ビルドへのアクセスの監査を行ってください。Linux の場合、Electron には Linux 向けのuniversal アップデートツールが提供されていないため、ディストリビューション固有の戦略が必要です。
メタデータをバイナリと同様に保護する必要があります
A signed binary can still be associated with the wrong release if the metadata channel is compromised or misconfigured. Consider adding a manifest signature verified against a public key embedded in the application, enforce a minimum permitted version, and reject unexpected downgrades unless an authorized recovery path explicitly permits them.
このフィードも、生産管理を実施する価値があります:
- パブリッシュアクセスを制限する: CIに必要な権限のみを与える:
- 署名シークレットを保護する: 証明書と秘密鍵は、管理されたシークレットストレージに保管し、リポジトリファイルにはしない:
- 依存関係を固定する: Electron、electron-builder、および依存関係のトランスитив依存をCIで固定する:
- アーティファクトをレビューする: 生成されたパッケージをスキャンし、意図したコミットとバージョンと比較する:
- 安全なトランスポートを要求する: ATSと厳密なHTTPS要件に従ってアップデート要求を実行する:
- 監視検証失敗: 繰り返し署名またはマニフェストの失敗をセキュリティイベントとして扱うのではなく、通常のネットワークノイズとして扱う。
Electronのメンテナンスツールキットは、パッケージングとアップデートのカバレッジを追加していますが、メンテナンスは脅威モデリングの必要性を排除しません。実際の目標は、攻撃者がバケット、CDN、またはビルドステップを乗っ取っても、クライアントが承認されていないリリースを受け入れることができないようにすることです。 署名検証ガイドライン 署名検証ガイドラインは、追加の検証層を設計するための有用なコンテキストを提供します。

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

Capgoは、各レンダラーの変更にnativeシェルを再構築することなく、署名されたウェブ層の変更を配信し、ターゲットチャネル、ロールアウト制御、更新観察性を提供するElectronのアップデータを提供します。nativeバイナリのリリースを制御されたJavaScriptおよびCSS配信から分離したい場合は、 Capgo エレクトロンリリースパイプラインと並行して評価してください。