Electron 빌드를 배포하고 릴리스 페이지를 오픈하자마자, 커피 머신이 커피를 다 내리기도 전에 첫 번째 지원 티켓이 도착합니다. 어떤 사용자는 앱에서 업데이트를 찾을 수 없다고 하고, 다른 사용자는 다운로드는 성공했지만 설치가 안 된다고 합니다. 또 다른 사용자는 인증 흐름이 깨진 구버전 바이너리를 여전히 사용 중인데, 정작 로그에는 유용한 정보가 거의 찍히지 않습니다.
이것이 바로 Electron 앱 자동 업데이트의불편한 현실입니다. 업데이터 API는 전체 구성 요소 중 하나일 뿐입니다. 실제 프로덕션 배포는 플랫폼 서명, 전송 정책, 매니페스트, 호스팅, 라이프사이클 이벤트, 관측성, 롤아웃 제어, 그리고 롤백 경로까지 모두 고려해야 합니다. 이 중 하나라도 간과한다면 단순한 패치 작업이 순식간에 대형 장애로 이어질 수 있습니다.
목차
- 이 가이드를 쓰게 만든 새벽 2시의 업데이트 장애 사고
- 올바른 Electron Updater 경로 선택하기
- 메인 프로세스에서 자동 업데이트 플로우 구현
- 서명된 릴리스 및 매니페스트를 위한 CI/CD 구성
- 롤아웃, 채널 및 롤백 전략
- 자동 업데이트를 보안 제어로 다루기
- 프로덕션 업데이트 런북 및 체크리스트
이 가이드를 쓰게 만든 새벽 2시의 업데이트 장애 사고
릴리스는 CI를 통과했고 평범해 보였습니다. 금요일 늦은 시간, 한 개발자가 서명되지 않은 Electron 빌드를 push했고, publish job이 릴리스가 완료된 것처럼 보이는 충분한 에셋을 업로드했습니다. 테스트에서는 애플리케이션이 실행되었지만, 설치된 프로덕션 빌드에서 업데이트 경로를 검증한 사람은 없었습니다.
새벽 2시 8분, PagerDuty가 온콜 엔지니어에게 경보를 보냈습니다. 일부 플릿에서 새로운 인증 플로우가 실패했고, 업데이트를 받은 사용자는 로그인 완료가 불가능했습니다. 다른 사용자는 업데이터가 아티팩트를 검증하거나 설치할 수 없어 이전 버전을 유지했습니다. 일부 고객은 깨진 릴리스를 겪었고, 나머지 플릿은 명확한 설명 없이 다른 버전을 실행 중이었습니다.
조사는 다음 5가지 체크를 따랐습니다:
- 릴리스 피드를 확인하세요. 바이너리는 존재했지만, 예상되는 메타데이터가 어떤 클라이언트가 이를 받아야 하는지 명확히 확립하지 못했습니다. 매니페스트는 릴리스 파이프라인과 설치된 클라이언트 간의 계약이지, 선택적인 업로드 세부 사항이 아닙니다.
- 서명 검사 릴리스가 올바르게 서명되지 않아 해당 플랫폼에서 검증이 실패했습니다. 서명이 누락되거나 유효하지 않을 경우 게시를 차단해야 합니다.
- 클라이언트 로그 비교 업데이트 오류가 중앙 텔레메트리에 전달되지 않았습니다. 애플리케이션이 이벤트를 무시하고 계속 실행되어 팀은 신뢰할 수 있는 증거를 확보하지 못했습니다.
- 롤아웃 제어 확인 내부 채널이나 단계별 코호트가 없었습니다. 모든 대상 클라이언트가 동일한 피드를 사용했기 때문에 실패가 격리 지점 없이 확산되었습니다.
- 롤백 검색 이전 버전을 다시 게시하거나 클라이언트를 손상된 릴리스에서 다른 곳으로 유도하기 위한 테스트된 절차가 없었습니다.
Electron 공식 문서에서 플랫폼 한계가 명확히 명시되어 있습니다. Linux에는 내장된 자동 업데이트 지원이 없으며, macOS 업데이트 요청은 다음을 충족해야 합니다 App Transport Security 요구사항. 문서에서는 또한 macOS 업데이트의 신뢰성과 릴리스 검증의 전제 조건으로 서명을 명시합니다. Electron autoUpdater 문서 는 API 제약 사항을 정의하며, 릴리스 시스템은 이를 둘러싼 운영 제어를 강제해야 합니다.
포스트모템 교훈: 무슨 일이 일어났는지 설명하지 못하는 업데이터는 텔레메트리가 빠진 원격 설치 시도에 불과합니다.
그 비용은 엔지니어링 시간에 그치지 않았습니다. 고객은 데스크톱 클라이언트에 대한 신뢰를 잃었고, 지원 팀은 일관성 없는 동작을 설명해야 했으며, 팀은 사고 전에 갖춰져 있었어야 할 릴리스 프로세스를 다시 구축하느라 다음 근무일을 통째로 보냈습니다.
자동 업데이트를 하나의 운영 시스템으로취급하세요. 서명은 릴리스 게이트이며, 매니페스트는 클라이언트 계약을 정의하고, 롤아웃 채널은 노출 범위를 제한하며, 롤백은 비상시 즉석에서 만드는 것이 아니라 검증된 경로로 남아 있어야 합니다.
올바른 Electron Updater 경로 선택하기
새벽 2시에 잘못된 업데이터 선택은 운영 문제가 됩니다. 네이티브 바이너리 업데이트는 서명, 매니페스트, 설치 프로그램, 롤백을 처리해야 합니다. 렌더러 전용 JavaScript 또는 CSS 변경은 다른 경로를 따릅니다. 호스팅 제약도 중요합니다. GitHub에 호스팅된 작은 프로젝트는 엔터프라이즈 배포 서비스와 같은 릴리스 제어가 필요하지 않습니다.
서명된 아티팩트를 게시하는 electron-builder 기반 프로젝트라면, electron-updater 가 보통 실용적인 기본값입니다. 이 생태계는 게시 대상, 릴리스 매니페스트, 아티팩트 다운로드, 다음 실행 시 설치를 아우릅니다. 여러 호스팅 모델을 지원하지만, 서명, 피드 가용성, 채널 정책, 롤아웃 제어, 모니터링은 여전히 팀이 책임져야 합니다. Capgo용 Electron updater 통합 네이티브 릴리스와 웹 레이어 번들을 함께 배포하는 하이브리드 모델을 평가할 때 관련이 있습니다.
update-electron-app GitHub Releases를 중심으로 작은 통합을 원하는 팀에 적합합니다. 시작 시와 주기적 간격으로 확인하므로 설정은 간단하지만, 고급 채널 선택, 단계적 트래픽, 커스텀 롤백 규칙에 대한 유연성은 낮습니다. GitHub Releases와 가용성이 운영 요구사항을 충족한다면 작은 릴리스 프로세스에 합리적인 선택입니다.
| 옵션 | 호스팅 제어 | 서명 지원 | 채널 및 단계적 롤아웃 | 유지보수 부담 |
|---|---|---|---|---|
| electron-updater | S3, GitHub, 일반 HTTPS 및 기타 게시 대상 | 패키지 릴리스 서명과 통합 | 견고한 기반, 커스텀 정책은 보통 피드 주위에 구현 | 보통 |
| update-electron-app | 주로 단순한 GitHub Releases 워크플로우 | 기반 Electron 서명 모델 사용 | 주변 서비스를 추가하지 않는 한 제한적 | 낮음 |
| Squirrel.Windows 또는 Squirrel.Mac | 플랫폼 중심 배포 플로우 | 플랫폼 서명 요구사항에 의존 | 가능하지만 보통 추가 릴리스 인프라 필요 | 레거시 애플리케이션에 적합 |
| 커스텀 서비스 | 매니페스트, 인증, 코호트, 피드에 대한 완전한 제어 | 검증 설계와 키 관리를 직접 담당합니다 | 최대 수준의 유연성 | 높음 |
| Capgo Live Update 사용하기 | 웹 레이어 번들을 위한 관리형 배포 | 자체 updater 및 배포 모델 사용 | 오디언스 타겟팅 및 채널 기반 배포 | 네이티브 바이너리 업데이트와 운영 모델 분리 |
릴리스 권한, 테넌트 타겟팅, 감사 기록 또는 규제 준수 배포 규칙 때문에 구현 비용을 감수할 가치가 있다면 Hazel, Nuts 또는 사내 피드와 같은 커스텀 서비스가 적합합니다. 다만 지속적인 관리 부담이 따릅니다. 팀에서 직접 manifest 의미 체계를 정의하고, 서명 키를 보호하며, 클라이언트 호환성을 유지하고, 다운로드 실패, 릴리스 거부 및 롤백 동작을 테스트해야 합니다.
Live updates를 사용하면 네이티브 쉘을 다시 빌드하지 않고도 renderer 전용 변경 사항을 배포할 수 있습니다. 단, Electron, 네이티브 모듈, 권한 또는 인스톨러 동작이 변경되는 경우에는 바이너리 업데이트를 대체할 수 없습니다. 커스텀 롤아웃 로직이 필요한 경우가 아니라면 electron-updater를 사용하세요. 커스텀 로직이 꼭 필요하다면 다운로드 및 differential update 동작을 새로 구현하기보다 기존 manifest 및 artifact 컨벤션을 기반으로 구축하세요. 가장 신뢰할 수 있는 경로는 팀이 긴박한 상황에서도 관찰하고, 단계적으로 배포하고, 되돌릴 수 있는 경로입니다.
메인 프로세스에서 자동 업데이트 플로우 구현
메인 프로세스가 업데이트 확인과 설치를 담당해야 합니다. 렌더러는 상태를 표시할 수 있지만, 실행 파일 업데이트가 신뢰할 수 있는지 또는 애플리케이션이 언제 종료될지 결정해서는 안 됩니다.
먼저 publish 대상 설정
최소한의 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()전에 설정하세요. 그렇지 않으면 일반적인 창 닫기 핸들러가 인스톨러가 인계받지 못하게 막을 수 있습니다.

명시적인 테스트가 필요한 두 가지 실패 사례가 있습니다. 첫째, 이미 실행 중인 클라이언트는 checkForUpdates() 시작할 때만이 아니라 일정 간격으로 호출해야 합니다. 둘째, error 이벤트는 로그와 텔레메트리에 남아야 합니다. 앱이 보고 없이 이벤트를 삼키면, 앱 트러블슈팅 워크플로우 추측이 아닌 증거로 시작합니다.
서명된 릴리스와 매니페스트를 위한 CI/CD 설정
릴리스 파이프라인은 사용자가 설치할 콘텐츠의 단일 진실 공급원입니다. 한 개발자의 로컬 머신에서 동작하는 빌드만으로는 공개된 바이너리, 매니페스트, 서명, 채널이 모두 동일한 릴리스를 가리킨다는 것을 증명할 수 없습니다.
Electron-builder의 publish 모델은 릴리스 메타데이터와 업데이트 대상이 함께 전송되도록 기대합니다. 많은 설정에서 이는 다음과 같은 아티팩트가 필요함을 의미합니다. latest.yml Windows용 latest-mac.yml macOS용, 플랫폼별 패키지 및 blockmap 파일과 함께. 매니페스트가 누락되면 완벽하게 유효한 바이너리도 클라이언트에 표시되지 않을 수 있습니다.
CI에서 서명을 명시적으로 처리하세요
간소화된 GitHub Actions 패턴은 다음과 같습니다:
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 |
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, 스모크 테스트 결과를 기준으로 작업을 게이트해야 합니다. 게시 후에는 피드에 예상된 매니페스트가 포함되어 있는지, 그리고 해당 매니페스트가 그 작업이 생성한 정확한 아티팩트를 가리키는지 확인해야 합니다. 지속적 통합 설정 가이드 이러한 체크를 공식화할 때 유용하며, 파이프라인 오케스트레이션을 비교하는 팀은 Jenkins와 Ansible을 함께 사용할 때를 이해하는 것도 도움이 될 수 있습니다.
불완전한 릴리스를 흔히 드러내는 명령어들은 의도적으로 지루합니다:
npx electron-builder --publish never
test -f dist/latest.yml
test -f dist/latest-mac.yml
find dist -name "*.blockmap" -print
이러한 체크는 서명된 설치 테스트를 대체하지 않습니다. 하지만 클라이언트가 발견하는 데 필요한 메타데이터 없이 바이너리를 업로드하는 운영 실수는 잡아낼 수 있습니다.
롤아웃, 채널 및 롤백 전략
릴리스 피드는 다운로드 폴더보다 배포 대상처럼 동작해야 합니다. 유지 내부, 베타, 그리고 최신 각 채널은 자체 manifest와 서명된 artifact 세트를 기반으로 분리 운영됩니다. 프로모션은 테스트를 마친 릴리스를 정책 간에 이동시키는 것이지, 클라이언트가 다운로드 중인 파일을 덮어쓰는 게 아닙니다.
채널 분리는 실수로 테스트 빌드가 프로덕션에 섞이는 것도 막아줍니다. 업데이터는 피드를 평가하기 전에 클라이언트가 내부 코호트, 베타 사용자, 안정 버전 사용자 중 어디에 속하는지 알아야 합니다.
광범위한 노출 전 코호트 활용하기
커스텀 manifest 필드로 단계적 배포를 표현할 수 있습니다:
version: 4.8.0
path: Example-Setup-4.8.0.exe
sha512: signed-artifact-hash
rolloutPercentage: 10
메인 프로세스가 사용자별 고정 버킷을 할당한 뒤, 그 버킷을 다음 값과 비교할 수 있습니다 rolloutPercentage. 안정적인 할당이 중요합니다. 매 체크마다 대상과 비대상 상태를 오가는 사용자는 예측 불가능한 동작을 겪게 되고, 지원 리포트를 해석하기도 어려워집니다.
릴리스가 관찰 기간을 무사히 통과한 후에만 코호트를 확장하세요. 관찰 기간은 사용 패턴에 맞게 정하되, 날짜만 보고 결정하지 말고 지표를 근거로 삼아야 합니다. 업데이트 체크 결과, 다운로드 완료, 실행 상태, 크래시, 렌더러 예외, 인증 성공 여부를 추적하세요.
| 시그널 | 작업 | 사유 |
|---|---|---|
| 피드 또는 서명 오류가 팀의 허용 임계치를 초과함 | 롤아웃 보류 | 클라이언트가 릴리스를 검증하거나 발견하지 못할 수 있습니다 |
| 업데이트 후 시작 체크 실패 | 피드 되돌리기 | 바이너리는 설치되지만 시작 시 실패할 수 있습니다 |
| 프로모션 후 렌더러 예외 증가 | 현재 코호트에서 보류 | 네이티브 인스톨러는 정상일 수 있지만 새로운 애플리케이션 code은 그렇지 않을 수 있습니다 |
| 신호는 릴리스 예산 내에서 유지됩니다 | 코호트 확장 | 증거가 더 넓은 노출을 뒷받침합니다 |
롤백을 아티팩트 삭제와 혼동하지 마세요. 기존 클라이언트는 메타데이터를 캐시했을 수 있고, 일부는 이미 잘못된 버전을 실행 중일 수 있습니다. 롤백 계획에는 이전 서명된 릴리스, 피드 변경, 그리고 복구할 수 있는 클라이언트 동작이 필요합니다.
운영 규칙: 롤백은 장애 중 온콜 엔지니어가 애플리케이션을 다시 빌드하지 않고도 실행할 수 있어야 합니다.
실무적으로 런북은 이전 릴리스 매니페스트를 영향을 받은 채널로 다시 프로모션하고, 스테이징 마커를 무효화한 뒤, 새 체크가 안전한 버전으로 해석되는지 확인해야 합니다. 문제가 네이티브 셸이 아니라 렌더러 code에 있다면 웹 레이어만 대상으로 한 롤백이 더 빠를 수 있습니다. 예를 들어 Capgo 단계적 롤아웃은 해당 별도 배포 레이어에 유효할 수 있지만, 네이티브 바이너리 롤백과 웹 번들 롤백 사이의 경계를 모호하게 해서는 안 됩니다.
자동 업데이트를 보안 제어로 다루기
Electron updater는 실행 가능한 code를 다운로드하고 사용자 상호작용이 거의 없이 설치할 수 있습니다. 이는 업데이트 경로를 단순한 편의 기능이 아니라 보안 경계로 만듭니다. Electron 공식 문서에는 macOS ATS 같은 플랫폼 제약이 설명되어 있고, 보안 관련 보도에서는 업데이트 인프라를 장악한 공격자가 code 서명 검사를 통과한 악성 패키지를 배포할 수 있었던 2022년 사례를 기록했습니다. 자세한 내용은 Electron Builder 자동 업데이트 보안 문서에서 확인하세요..
Code 서명은 여전히 기본이지만, 신뢰 모델의 전부는 아닙니다. 모든 릴리스에 서명하고, CI에서 인증서와 신원을 검증하며, 문서화된 키 로테이션 절차를 유지하세요. macOS에서는 서명에 노타리제이션과 애플리케이션에 적합한 강화된 런타임을 결합하세요. Windows에서는 인증서 소유권, 갱신, 빌드 접근 권한이 감사 가능하도록 하세요. Linux는 Electron이 내장된 범용 업데이트 제공기를 제공하지 않으므로 배포판별 전략이 필요합니다.
바이너리와 마찬가지로 메타데이터도 철저히 보호하세요
메타데이터 채널이 침해되거나 잘못 구성되면 서명된 바이너리도 잘못된 릴리스와 연결될 수 있습니다. 애플리케이션에 내장된 공개 키로 검증되는 매니페스트 서명을 추가하고, 허용되는 최소 버전을 강제하며, 승인된 복구 경로가 명시적으로 허용하는 경우를 제외하고는 예상치 못한 다운그레이드를 거부하세요.
피드에도 프로덕션 제어가 필요합니다:
- 게시 권한 제한: CI에는 릴리스 자산 게시에 필요한 권한만 부여하세요.
- 서명 시크릿 보호: 인증서와 개인 키는 저장소 파일이 아닌 관리형 시크릿 저장소에 보관하세요.
- 의존성 고정: CI에서 Electron, electron-builder 및 전이적 의존성을 고정하세요.
- 아티팩트 검토: 생성된 패키지를 스캔하고 의도한 커밋 및 버전과 비교하세요.
- 보안 전송 필수: 업데이트 요청 시 ATS 및 엄격한 HTTPS 요구사항을 준수하세요.
- 검증 실패 모니터링: 반복되는 서명 또는 매니페스트 실패는 일반 네트워크 노이즈가 아니라 보안 이벤트로 취급하세요.
Electron의 유지 관리되는 툴링 생태계는 패키징 및 업데이터 지원 범위를 계속 확장하고 있지만, 유지보수만으로 위협 모델링의 필요성이 사라지지는 않습니다. 실질적인 목표는 공격자가 버킷, CDN 또는 빌드 단계를 탈취해도 클라이언트가 승인되지 않은 릴리스를 수락하지 못하게 하는 것입니다. 다음의 서명 검증 가이드라인은 해당 추가 검증 레이어를 설계하는 데 유용한 컨텍스트를 제공합니다.

프로덕션 업데이트 런북 및 체크리스트
릴리스는 다른 엔지니어가 압박 속에서도 운영할 수 있을 때 비로소 준비된 것입니다. 체크리스트는 배포 작업과 인시던트 채널 가까이에 두세요.
릴리스 전 게이트
- 버전 식별: 패키지 버전, 릴리스 태그, 커밋 SHA, 변경 사항이 일치하는지 확인하세요.
- 서명: 모든 플랫폼 아티팩트가 서명되고, 노타리제이션 또는 동등한 검증이 완료되었는지 확인하세요.
- 매니페스트 계약: 확인
latest.yml,latest-mac.yml, 해시, 경로, 블록맵이 업로드된 아티팩트와 일치하는지 확인하세요. - 채널 안전성: 릴리스 채널로 승격하기 전에 내부 또는 베타 피드에 게시하세요.
- 텔레메트리: 업데이트 확인, 다운로드 진행률, 설치 완료, 실행 상태, 오류가 제대로 들어오는지 확인하세요.
Canary 및 전체 배포
- 코호트 제어: 의도적으로 소규모 내부 또는 베타 사용자부터 시작하세요.
- 헬스 버짓: 실행 실패, 업데이트 다운로드 실패, 렌더러 예외, 인증 실패가 팀이 승인한 한도를 넘으면 프로모션을 보류하세요.
- 프로모션 승인: 릴리스를 stable 피드로 옮기기 전에 명시적인 go/no-go 결정을 요구하세요.
- 고객 영향: 첫 인시던트 이후가 아니라 광범위한 배포 전에 지원 메시지를 준비하세요.
인시던트 대응
새 바이너리가 실행에 실패하거나 프로세스 스폰이 실패하거나 업데이트 다운로드가 완료되지 않으면 즉시 프로모션을 중단하세요. 이전에 서명된 매니페스트를 복원하고 스테이징 마커를 무효화한 뒤, 새 클라이언트가 이전 버전을 가리키는지 확인하세요. 그런 다음 텔레메트리로 플릿이 복구되는지 확인한 후 상황 종료를 공지하세요.
구체적인 롤백 명령은 제공업체에 따라 다르지만, 순서는 항상 문서화해야 합니다: 채널 매니페스트를 이전 버전으로 전환하고, 스테이징 태그를 무효화하며, 복구 시 강제 업데이트 마커를 푸시하고, 라이브 텔레메트리로 다운그레이드 경로를 검증합니다. 테스트되지 않은 롤백은 희망일 뿐입니다.

Capgo는 서명된 웹 레이어 변경 사항 배포, 대상 채널, 롤아웃 제어, 업데이트 관측성을 제공하여 모든 렌더러 변경 시 네이티브 셸을 다시 빌드할 필요가 없는 Electron 업데이트기를 제공합니다. 네이티브 바이너리 릴리스와 제어된 JavaScript 및 CSS 배포를 분리하고 싶다면 방문하세요 Capgo 기존 Electron 릴리스 파이프라인과 함께 평가해 보세요.