<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Update on Tarragon</title><link>https://tarrragon.github.io/blog/tags/update/</link><description>Recent content in Update on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Thu, 21 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/update/index.xml" rel="self" type="application/rss+xml"/><item><title>Desktop client 簽章、公證與自動更新流程</title><link>https://tarrragon.github.io/blog/ci/desktop-client-deploy/signing-notarization-update-flow/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/desktop-client-deploy/signing-notarization-update-flow/</guid><description>&lt;p>Desktop client 發布流程的核心責任是讓多平台安裝包可信、可更新、可回復。桌面應用和 web 不同，使用者會下載 installer 或 package 到本機；CI/CD 需要處理平台差異、code signing、notarization、auto-update feed、delta package 與多版本共存。&lt;/p>
&lt;h2 id="流程定位">流程定位&lt;/h2>
&lt;p>Desktop client 的風險集中在作業系統信任鏈與更新通道。macOS、Windows、Linux 對簽章、安裝包格式與安全提示的要求不同；同一份 source 通常會產生多個平台 artifact，因此 workflow 要把平台 matrix、簽章 secret 與 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/release-channel/" data-link-title="Release Channel" data-link-desc="說明 stable、beta、internal 等發行通道如何控制 artifact 接觸到的使用者範圍">Release Channel&lt;/a> 拆清楚。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>階段&lt;/th>
 &lt;th>責任&lt;/th>
 &lt;th>判讀訊號&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Build&lt;/td>
 &lt;td>產生 &lt;code>.dmg&lt;/code>、&lt;code>.pkg&lt;/code>、&lt;code>.msi&lt;/code>、AppImage 等&lt;/td>
 &lt;td>平台 matrix 是否完整&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Signing&lt;/td>
 &lt;td>建立 OS 信任&lt;/td>
 &lt;td>certificate、timestamp、keychain&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Notarize&lt;/td>
 &lt;td>通過 macOS 公證或平台審查&lt;/td>
 &lt;td>staple、gatekeeper 是否通過&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Release&lt;/td>
 &lt;td>發布到 channel 或 download page&lt;/td>
 &lt;td>stable / beta / internal 分流&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Update&lt;/td>
 &lt;td>推送 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/update-feed/" data-link-title="Update Feed" data-link-desc="說明桌面與客戶端應用如何透過更新來源取得已簽章版本與回復路徑">Update Feed&lt;/a> 或 delta package&lt;/td>
 &lt;td>feed 簽章、版本相容、回退策略&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Recovery&lt;/td>
 &lt;td>hotfix、rollback channel、停用更新&lt;/td>
 &lt;td>是否能阻止錯誤版本擴散&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Build 階段負責產生平台專屬 artifact。Flutter Desktop、Electron 與 Tauri 的輸出格式不同，但共同要求是每個 artifact 都能追到 commit、workflow run 與 dependency lock。&lt;/p>
&lt;p>Signing 階段負責讓 OS 信任安裝包。Windows code signing certificate、macOS Developer ID、timestamp server 與 Linux package signing key 都是發布能力；secret 應放在受控環境，並限制能觸發 signing job 的分支與 reviewer。&lt;/p>
&lt;p>Notarize 階段負責處理 macOS 信任 gate。macOS app 即使完成簽章，也常需要 notarization 與 stapling；CI 要把 notarization log 保存下來，否則使用者看到 Gatekeeper 警告時很難回溯。&lt;/p>
&lt;p>Release 階段負責把 artifact 放到正確 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/release-channel/" data-link-title="Release Channel" data-link-desc="說明 stable、beta、internal 等發行通道如何控制 artifact 接觸到的使用者範圍">Release Channel&lt;/a>。Internal、beta、stable 與 enterprise channel 的 gate 不同；CI/CD 要避免未審核的 beta artifact 被 stable feed 取用。&lt;/p>
&lt;p>Update 階段負責維持升級路徑。&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/update-feed/" data-link-title="Update Feed" data-link-desc="說明桌面與客戶端應用如何透過更新來源取得已簽章版本與回復路徑">Update Feed&lt;/a>、delta package、signature、minimum supported version 與 rollback channel 要一起設計；更新壞掉時，使用者可能卡在需要人工修復的版本。&lt;/p>
&lt;p>Recovery 階段負責止血。桌面客戶端常用方式是撤下 update feed、發布 hotfix、切換 rollback channel、停用 remote feature 或要求最低版本；每種方式都依賴 app 內建相容支援。&lt;/p>
&lt;h2 id="平台差異判讀">平台差異判讀&lt;/h2>
&lt;p>平台差異判讀的責任是讓 CI matrix 對應真實發布風險。桌面發布除了確認「三平台都 build 成功」，還要確認每個平台的安裝、啟動、更新與卸載行為。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>平台&lt;/th>
 &lt;th>高風險點&lt;/th>
 &lt;th>驗證方向&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>macOS&lt;/td>
 &lt;td>Developer ID、notarization、universal binary&lt;/td>
 &lt;td>Gatekeeper、arm64 / x64 啟動&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Windows&lt;/td>
 &lt;td>Authenticode、SmartScreen、installer 權限&lt;/td>
 &lt;td>安裝、更新、卸載、權限提示&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Linux&lt;/td>
 &lt;td>AppImage、deb、rpm、repository key&lt;/td>
 &lt;td>dependency、desktop entry、sandbox&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>這張表的用途是避免平台細節被單一「desktop build」欄位抹平。每個 OS 的失敗代價不同，CI 應保留平台專屬 gate。&lt;/p></description><content:encoded><![CDATA[<p>Desktop client 發布流程的核心責任是讓多平台安裝包可信、可更新、可回復。桌面應用和 web 不同，使用者會下載 installer 或 package 到本機；CI/CD 需要處理平台差異、code signing、notarization、auto-update feed、delta package 與多版本共存。</p>
<h2 id="流程定位">流程定位</h2>
<p>Desktop client 的風險集中在作業系統信任鏈與更新通道。macOS、Windows、Linux 對簽章、安裝包格式與安全提示的要求不同；同一份 source 通常會產生多個平台 artifact，因此 workflow 要把平台 matrix、簽章 secret 與 <a href="/blog/ci/knowledge-cards/release-channel/" data-link-title="Release Channel" data-link-desc="說明 stable、beta、internal 等發行通道如何控制 artifact 接觸到的使用者範圍">Release Channel</a> 拆清楚。</p>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>責任</th>
          <th>判讀訊號</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>產生 <code>.dmg</code>、<code>.pkg</code>、<code>.msi</code>、AppImage 等</td>
          <td>平台 matrix 是否完整</td>
      </tr>
      <tr>
          <td>Signing</td>
          <td>建立 OS 信任</td>
          <td>certificate、timestamp、keychain</td>
      </tr>
      <tr>
          <td>Notarize</td>
          <td>通過 macOS 公證或平台審查</td>
          <td>staple、gatekeeper 是否通過</td>
      </tr>
      <tr>
          <td>Release</td>
          <td>發布到 channel 或 download page</td>
          <td>stable / beta / internal 分流</td>
      </tr>
      <tr>
          <td>Update</td>
          <td>推送 <a href="/blog/ci/knowledge-cards/update-feed/" data-link-title="Update Feed" data-link-desc="說明桌面與客戶端應用如何透過更新來源取得已簽章版本與回復路徑">Update Feed</a> 或 delta package</td>
          <td>feed 簽章、版本相容、回退策略</td>
      </tr>
      <tr>
          <td>Recovery</td>
          <td>hotfix、rollback channel、停用更新</td>
          <td>是否能阻止錯誤版本擴散</td>
      </tr>
  </tbody>
</table>
<p>Build 階段負責產生平台專屬 artifact。Flutter Desktop、Electron 與 Tauri 的輸出格式不同，但共同要求是每個 artifact 都能追到 commit、workflow run 與 dependency lock。</p>
<p>Signing 階段負責讓 OS 信任安裝包。Windows code signing certificate、macOS Developer ID、timestamp server 與 Linux package signing key 都是發布能力；secret 應放在受控環境，並限制能觸發 signing job 的分支與 reviewer。</p>
<p>Notarize 階段負責處理 macOS 信任 gate。macOS app 即使完成簽章，也常需要 notarization 與 stapling；CI 要把 notarization log 保存下來，否則使用者看到 Gatekeeper 警告時很難回溯。</p>
<p>Release 階段負責把 artifact 放到正確 <a href="/blog/ci/knowledge-cards/release-channel/" data-link-title="Release Channel" data-link-desc="說明 stable、beta、internal 等發行通道如何控制 artifact 接觸到的使用者範圍">Release Channel</a>。Internal、beta、stable 與 enterprise channel 的 gate 不同；CI/CD 要避免未審核的 beta artifact 被 stable feed 取用。</p>
<p>Update 階段負責維持升級路徑。<a href="/blog/ci/knowledge-cards/update-feed/" data-link-title="Update Feed" data-link-desc="說明桌面與客戶端應用如何透過更新來源取得已簽章版本與回復路徑">Update Feed</a>、delta package、signature、minimum supported version 與 rollback channel 要一起設計；更新壞掉時，使用者可能卡在需要人工修復的版本。</p>
<p>Recovery 階段負責止血。桌面客戶端常用方式是撤下 update feed、發布 hotfix、切換 rollback channel、停用 remote feature 或要求最低版本；每種方式都依賴 app 內建相容支援。</p>
<h2 id="平台差異判讀">平台差異判讀</h2>
<p>平台差異判讀的責任是讓 CI matrix 對應真實發布風險。桌面發布除了確認「三平台都 build 成功」，還要確認每個平台的安裝、啟動、更新與卸載行為。</p>
<table>
  <thead>
      <tr>
          <th>平台</th>
          <th>高風險點</th>
          <th>驗證方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>macOS</td>
          <td>Developer ID、notarization、universal binary</td>
          <td>Gatekeeper、arm64 / x64 啟動</td>
      </tr>
      <tr>
          <td>Windows</td>
          <td>Authenticode、SmartScreen、installer 權限</td>
          <td>安裝、更新、卸載、權限提示</td>
      </tr>
      <tr>
          <td>Linux</td>
          <td>AppImage、deb、rpm、repository key</td>
          <td>dependency、desktop entry、sandbox</td>
      </tr>
  </tbody>
</table>
<p>這張表的用途是避免平台細節被單一「desktop build」欄位抹平。每個 OS 的失敗代價不同，CI 應保留平台專屬 gate。</p>
<h2 id="update-feed-契約">Update feed 契約</h2>
<p><a href="/blog/ci/knowledge-cards/update-feed/" data-link-title="Update Feed" data-link-desc="說明桌面與客戶端應用如何透過更新來源取得已簽章版本與回復路徑">Update Feed</a> 契約的責任是讓已安裝使用者安全升級。Auto-update 需要簽章、版本比較、channel、最低版本與回退策略共同成立，才能讓新版本 URL 進入 feed。</p>
<ol>
<li>Feed 只指向已簽章且已驗證的 artifact。</li>
<li>Stable feed 只接收 stable release，beta feed 只接收 beta release。</li>
<li>App 啟動時能處理 feed 暫時不可用。</li>
<li>Delta update 失敗時能 fallback 到 full installer。</li>
<li>錯誤版本要能從 feed 撤下，並讓未更新使用者停止取得。</li>
<li>已更新使用者要有 hotfix 或 rollback channel。</li>
</ol>
<p>這些條件讓更新通道具備操作性。若 app 只知道「看到新版就下載」，錯誤 feed 會把事故放大到所有啟動中的使用者。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>Desktop 部署總覽：回 <a href="../">Desktop Client 部署 CI/CD</a>。</li>
<li>App 發布通用觀念：讀 <a href="../../app-deploy/signing-store-rollout-flow/">App 簽章、商店審核與分批發布流程</a>。</li>
<li>簽章術語：讀 <a href="/blog/ci/knowledge-cards/app-signing/" data-link-title="App Signing" data-link-desc="說明行動與桌面應用的簽章憑證如何影響發布能力">App Signing</a>。</li>
</ul>
]]></content:encoded></item><item><title>Update Feed</title><link>https://tarrragon.github.io/blog/ci/knowledge-cards/update-feed/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/knowledge-cards/update-feed/</guid><description>&lt;p>Update Feed 的核心概念是「告訴已安裝客戶端該取得哪個版本」。它連接 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/release-channel/" data-link-title="Release Channel" data-link-desc="說明 stable、beta、internal 等發行通道如何控制 artifact 接觸到的使用者範圍">Release Channel&lt;/a> 與 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/app-signing/" data-link-title="App Signing" data-link-desc="說明行動與桌面應用的簽章憑證如何影響發布能力">App Signing&lt;/a>，讓自動更新具備信任與回復能力。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Update Feed 位在 signed artifact、release channel 與已安裝 app 之間，常包含版本號、下載 URL、signature、checksum、release notes 與最低支援版本。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;ul>
&lt;li>客戶端需要自動偵測新版本。&lt;/li>
&lt;li>beta 與 stable 使用者需要看到不同版本。&lt;/li>
&lt;li>錯誤版本需要從更新來源撤下。&lt;/li>
&lt;/ul>
&lt;h2 id="接近真實服務的例子">接近真實服務的例子&lt;/h2>
&lt;p>Electron app 啟動時讀取 stable feed，取得最新 signed installer 與 signature。若新版本 crash rate 升高，團隊先撤下 feed 指向，讓未更新使用者停止取得錯誤版本。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>Update Feed 要定義簽章驗證、channel 分流、版本比較、fallback installer、撤版策略與 telemetry，讓已安裝客戶端安全升級。&lt;/p></description><content:encoded><![CDATA[<p>Update Feed 的核心概念是「告訴已安裝客戶端該取得哪個版本」。它連接 <a href="/blog/ci/knowledge-cards/release-channel/" data-link-title="Release Channel" data-link-desc="說明 stable、beta、internal 等發行通道如何控制 artifact 接觸到的使用者範圍">Release Channel</a> 與 <a href="/blog/ci/knowledge-cards/app-signing/" data-link-title="App Signing" data-link-desc="說明行動與桌面應用的簽章憑證如何影響發布能力">App Signing</a>，讓自動更新具備信任與回復能力。</p>
<h2 id="概念位置">概念位置</h2>
<p>Update Feed 位在 signed artifact、release channel 與已安裝 app 之間，常包含版本號、下載 URL、signature、checksum、release notes 與最低支援版本。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<ul>
<li>客戶端需要自動偵測新版本。</li>
<li>beta 與 stable 使用者需要看到不同版本。</li>
<li>錯誤版本需要從更新來源撤下。</li>
</ul>
<h2 id="接近真實服務的例子">接近真實服務的例子</h2>
<p>Electron app 啟動時讀取 stable feed，取得最新 signed installer 與 signature。若新版本 crash rate 升高，團隊先撤下 feed 指向，讓未更新使用者停止取得錯誤版本。</p>
<h2 id="設計責任">設計責任</h2>
<p>Update Feed 要定義簽章驗證、channel 分流、版本比較、fallback installer、撤版策略與 telemetry，讓已安裝客戶端安全升級。</p>
]]></content:encoded></item></channel></rss>