<?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>Artifact on Tarragon</title><link>https://tarrragon.github.io/blog/tags/artifact/</link><description>Recent content in Artifact 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/artifact/index.xml" rel="self" type="application/rss+xml"/><item><title>前端 artifact 與 preview deployment 流程</title><link>https://tarrragon.github.io/blog/ci/frontend-deploy/static-artifact-preview-flow/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/frontend-deploy/static-artifact-preview-flow/</guid><description>&lt;p>前端 artifact 流程的核心責任是讓測試、預覽與正式發布使用同一份靜態產物。前端部署常見輸出是 HTML、CSS、JavaScript、圖片、sourcemap 與搜尋索引；這些產物一旦被重新 build，就可能受到環境變數、依賴版本、base URL 或 framework 設定影響，因此 CI/CD 需要把「產生一次、驗證一次、推進同一份」當成主線。&lt;/p>
&lt;h2 id="流程定位">流程定位&lt;/h2>
&lt;p>前端部署的風險集中在 build time。後端服務可以在 runtime 讀取設定、檢查資料庫與逐步接流量；前端靜態產物多半在 build 階段就把 route、asset path、環境變數與 feature flag 預先寫入 bundle。CI/CD 的判讀重點因此是「被部署的 artifact 是否就是已驗證的那一份」。&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>產生 production-like static artifact&lt;/td>
 &lt;td>lockfile、Node 版本、base URL 是否固定&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Browser test&lt;/td>
 &lt;td>驗證使用者可見行為&lt;/td>
 &lt;td>測試是否跑在 build 後 artifact&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/preview-environment/" data-link-title="Preview Environment" data-link-desc="說明 pull request 變更如何在隔離部署環境中被驗證">Preview environment&lt;/a>&lt;/td>
 &lt;td>讓 PR 變更可被 reviewer 實際操作&lt;/td>
 &lt;td>preview URL 是否對應 commit / PR&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Deploy&lt;/td>
 &lt;td>推進到 hosting、Pages 或 CDN&lt;/td>
 &lt;td>HTML cache、asset cache、SPA fallback&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy&lt;/a>&lt;/td>
 &lt;td>重新服務上一份已知可用 artifact&lt;/td>
 &lt;td>舊 artifact、cache purge 與 API 相容性&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Build 階段負責建立可驗證產物。真實服務裡，&lt;code>npm run dev&lt;/code> 成功不代表 production build 能成功；CI 應固定 Node 版本、package manager、lockfile、build command 與必要環境變數，讓 artifact 可以從乾淨環境重建。&lt;/p>
&lt;p>Browser test 階段負責驗證使用者實際會看到的頁面。Playwright、visual diff、a11y check 或 smoke test 應盡量對 build 後的靜態站執行，避免 dev server 的 fallback、熱更新或寬鬆路由遮蔽 production 問題。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/preview-environment/" data-link-title="Preview Environment" data-link-desc="說明 pull request 變更如何在隔離部署環境中被驗證">Preview environment&lt;/a> 階段負責把 PR 變成可操作畫面。Preview URL 要能追到 PR、commit 與 workflow run，reviewer 才能把畫面問題回報到正確版本；preview 也要隔離 production 資料與 credential，避免預覽環境變成未受控入口。&lt;/p>
&lt;p>Deploy 階段負責把 artifact 放到 hosting 或 CDN。前端部署失敗常出現在 cache policy、SPA fallback、base URL、static route 與 sourcemap 權限；deploy 成功只代表檔案上傳完成，仍需要檢查入口頁、核心路由與 asset 是否能從公開網址載入。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy&lt;/a> 階段負責恢復上一份可用靜態產物。前端 rollback 表面上只是切回舊檔案，但若 API schema、build time config 或 CDN cache 已經變動，舊頁面仍可能呼叫不相容的後端，因此 rollback 要搭配 smoke test 與 cache purge。&lt;/p>
&lt;h2 id="常見失敗路由">常見失敗路由&lt;/h2>
&lt;p>前端 CI 紅燈要先判斷失敗在 build、browser test、preview 還是 production deploy。不同層的修復入口不同；把所有紅燈都當成「重跑 workflow」會掩蓋 artifact 漂移與 cache 問題。&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>本機 dev 正常、CI build 失敗&lt;/td>
 &lt;td>production build 條件與本機不同&lt;/td>
 &lt;td>回本機跑 CI 同一條 build command&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>測試通過、上線後空白頁&lt;/td>
 &lt;td>測試沒有覆蓋 production artifact / URL&lt;/td>
 &lt;td>對已部署 artifact 跑 smoke test&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Preview URL 顯示舊畫面&lt;/td>
 &lt;td>preview cache 或 commit 對應錯位&lt;/td>
 &lt;td>檢查 preview artifact 與 workflow run&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>只有深層路由 404&lt;/td>
 &lt;td>SPA fallback 或 static route 設定錯誤&lt;/td>
 &lt;td>檢查 hosting rewrite / base URL&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>rollback 後仍看到新版&lt;/td>
 &lt;td>CDN / browser cache 尚未失效&lt;/td>
 &lt;td>檢查 cache invalidation 與 HTML cache policy&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>這張表的用途是縮短定位時間。前端部署問題常被誤判成「CDN 壞掉」或「瀏覽器快取」，但更常見的根因是 build artifact、route 與 cache policy 的契約沒有明確寫進 pipeline。&lt;/p></description><content:encoded><![CDATA[<p>前端 artifact 流程的核心責任是讓測試、預覽與正式發布使用同一份靜態產物。前端部署常見輸出是 HTML、CSS、JavaScript、圖片、sourcemap 與搜尋索引；這些產物一旦被重新 build，就可能受到環境變數、依賴版本、base URL 或 framework 設定影響，因此 CI/CD 需要把「產生一次、驗證一次、推進同一份」當成主線。</p>
<h2 id="流程定位">流程定位</h2>
<p>前端部署的風險集中在 build time。後端服務可以在 runtime 讀取設定、檢查資料庫與逐步接流量；前端靜態產物多半在 build 階段就把 route、asset path、環境變數與 feature flag 預先寫入 bundle。CI/CD 的判讀重點因此是「被部署的 artifact 是否就是已驗證的那一份」。</p>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>責任</th>
          <th>判讀訊號</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>產生 production-like static artifact</td>
          <td>lockfile、Node 版本、base URL 是否固定</td>
      </tr>
      <tr>
          <td>Browser test</td>
          <td>驗證使用者可見行為</td>
          <td>測試是否跑在 build 後 artifact</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/preview-environment/" data-link-title="Preview Environment" data-link-desc="說明 pull request 變更如何在隔離部署環境中被驗證">Preview environment</a></td>
          <td>讓 PR 變更可被 reviewer 實際操作</td>
          <td>preview URL 是否對應 commit / PR</td>
      </tr>
      <tr>
          <td>Deploy</td>
          <td>推進到 hosting、Pages 或 CDN</td>
          <td>HTML cache、asset cache、SPA fallback</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy</a></td>
          <td>重新服務上一份已知可用 artifact</td>
          <td>舊 artifact、cache purge 與 API 相容性</td>
      </tr>
  </tbody>
</table>
<p>Build 階段負責建立可驗證產物。真實服務裡，<code>npm run dev</code> 成功不代表 production build 能成功；CI 應固定 Node 版本、package manager、lockfile、build command 與必要環境變數，讓 artifact 可以從乾淨環境重建。</p>
<p>Browser test 階段負責驗證使用者實際會看到的頁面。Playwright、visual diff、a11y check 或 smoke test 應盡量對 build 後的靜態站執行，避免 dev server 的 fallback、熱更新或寬鬆路由遮蔽 production 問題。</p>
<p><a href="/blog/ci/knowledge-cards/preview-environment/" data-link-title="Preview Environment" data-link-desc="說明 pull request 變更如何在隔離部署環境中被驗證">Preview environment</a> 階段負責把 PR 變成可操作畫面。Preview URL 要能追到 PR、commit 與 workflow run，reviewer 才能把畫面問題回報到正確版本；preview 也要隔離 production 資料與 credential，避免預覽環境變成未受控入口。</p>
<p>Deploy 階段負責把 artifact 放到 hosting 或 CDN。前端部署失敗常出現在 cache policy、SPA fallback、base URL、static route 與 sourcemap 權限；deploy 成功只代表檔案上傳完成，仍需要檢查入口頁、核心路由與 asset 是否能從公開網址載入。</p>
<p><a href="/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy</a> 階段負責恢復上一份可用靜態產物。前端 rollback 表面上只是切回舊檔案，但若 API schema、build time config 或 CDN cache 已經變動，舊頁面仍可能呼叫不相容的後端，因此 rollback 要搭配 smoke test 與 cache purge。</p>
<h2 id="常見失敗路由">常見失敗路由</h2>
<p>前端 CI 紅燈要先判斷失敗在 build、browser test、preview 還是 production deploy。不同層的修復入口不同；把所有紅燈都當成「重跑 workflow」會掩蓋 artifact 漂移與 cache 問題。</p>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>判讀</th>
          <th>下一步</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>本機 dev 正常、CI build 失敗</td>
          <td>production build 條件與本機不同</td>
          <td>回本機跑 CI 同一條 build command</td>
      </tr>
      <tr>
          <td>測試通過、上線後空白頁</td>
          <td>測試沒有覆蓋 production artifact / URL</td>
          <td>對已部署 artifact 跑 smoke test</td>
      </tr>
      <tr>
          <td>Preview URL 顯示舊畫面</td>
          <td>preview cache 或 commit 對應錯位</td>
          <td>檢查 preview artifact 與 workflow run</td>
      </tr>
      <tr>
          <td>只有深層路由 404</td>
          <td>SPA fallback 或 static route 設定錯誤</td>
          <td>檢查 hosting rewrite / base URL</td>
      </tr>
      <tr>
          <td>rollback 後仍看到新版</td>
          <td>CDN / browser cache 尚未失效</td>
          <td>檢查 cache invalidation 與 HTML cache policy</td>
      </tr>
  </tbody>
</table>
<p>這張表的用途是縮短定位時間。前端部署問題常被誤判成「CDN 壞掉」或「瀏覽器快取」，但更常見的根因是 build artifact、route 與 cache policy 的契約沒有明確寫進 pipeline。</p>
<h2 id="最小-workflow-骨架">最小 workflow 骨架</h2>
<p>前端 workflow 應把 build、test、preview 與 deploy 的資料流顯性化。下面是概念骨架，重點在 artifact handoff 的方向，特定平台語法是次要的。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">npm ci</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">npm run build</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/upload-artifact</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">web-dist</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">  </span><span class="nt">test</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">build</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">web-dist</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">npm run test:e2e:static</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">  </span><span class="nt">preview</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">test</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">    </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">github.event_name == &#39;pull_request&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">web-dist</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">npm run deploy:preview</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">  </span><span class="nt">deploy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">test</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">    </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">github.ref == &#39;refs/heads/main&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">web-dist</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">npm run deploy:production</span></span></span></code></pre></div><p>這個骨架讓 deploy 依賴 test，也讓 test 與 deploy 使用 build job 產生的同一份產物。若專案需要在不同環境注入設定，要明確區分 build time config 與 runtime config，避免同一份 artifact 被重新 build 成另一份內容。</p>
<h2 id="tripwire">Tripwire</h2>
<p>Tripwire 的責任是提醒前端 workflow 需要重切。當同一類問題反覆出現，局部補命令通常只能暫時遮住資料流錯位。</p>
<ul>
<li>Preview 常和 production 不一致：把 preview 改成部署 build artifact，讓 preview job 沿用同一份產物。</li>
<li>E2E 測試通過但 production 壞：把 E2E 改到 static artifact 或 production-like server 上執行。</li>
<li>rollback 依賴人工找舊 commit：保留 release artifact 與版本索引，讓回退指向明確產物。</li>
<li>CDN cache 問題反覆出現：把 HTML cache、asset cache 與 purge 策略寫進 deploy checklist。</li>
</ul>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>前端部署總覽：回 <a href="../">前端部署 CI/CD</a>。</li>
<li>Gate 原理：讀 <a href="../../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a>。</li>
<li>本 blog 靜態站案例：讀 <a href="../../blog-project-deploy/">本 blog 專案部署</a>。</li>
</ul>
]]></content:encoded></item><item><title>CI gate 與 workflow 邊界</title><link>https://tarrragon.github.io/blog/ci/ci-gate-workflow-boundary/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/ci-gate-workflow-boundary/</guid><description>&lt;p>CI gate 的核心責任是把「是否進入下一階段」變成明確條件。測試、建置、發布與人工審核可以分成不同 workflow 或 job，但只要它們共同決定同一次發布，就需要有清楚的 gate 關係。&lt;/p>
&lt;h2 id="gate-形式">Gate 形式&lt;/h2>
&lt;p>Gate 形式要依控制範圍選擇。PR 合併、job 執行順序、production 發布與 artifact 傳遞是四種不同責任，混在一起會讓紅燈的意義變模糊。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Gate 形式&lt;/th>
 &lt;th>責任&lt;/th>
 &lt;th>判讀方式&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/required-checks/" data-link-title="Required Checks" data-link-desc="說明 pull request 的必要檢查如何作為合併 gate">Required checks&lt;/a>&lt;/td>
 &lt;td>阻止未通過測試的 commit 合併&lt;/td>
 &lt;td>PR 或 branch protection 顯示必須通過&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Job &lt;code>needs&lt;/code>&lt;/td>
 &lt;td>讓 deploy 等 test / build&lt;/td>
 &lt;td>同一 workflow 內 deploy 依賴前置 job&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/environment-protection/" data-link-title="Environment Protection" data-link-desc="說明目標環境的審核、權限與放行條件如何保護發布">Environment protection&lt;/a>&lt;/td>
 &lt;td>控制 production / target environment 發布&lt;/td>
 &lt;td>部署環境需要審核或 required reviewers&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff&lt;/a>&lt;/td>
 &lt;td>確保測試與發布使用同一份產物&lt;/td>
 &lt;td>test job 產生 artifact，deploy job 使用&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/required-checks/" data-link-title="Required Checks" data-link-desc="說明 pull request 的必要檢查如何作為合併 gate">Required checks&lt;/a> 適合保護主線。它讓測試結果成為合併條件，避免紅燈變更進入 &lt;code>main&lt;/code> 或 release branch（backend 延伸見 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/ci-pipeline/" data-link-title="CI Pipeline" data-link-desc="說明持續整合流程如何在合併前驗證品質與相容性">CI Pipeline&lt;/a>）。&lt;/p>
&lt;p>Job &lt;code>needs&lt;/code> 適合同一條 workflow 內的發布管線。它讓 &lt;code>deploy&lt;/code> 必須等 &lt;code>test&lt;/code>、&lt;code>build&lt;/code> 或 &lt;code>package&lt;/code> 成功後才執行，避免 deploy job 先於驗證結果流動（platform 延伸見 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/deployment-contract/" data-link-title="Deployment Contract" data-link-desc="說明服務與部署平台之間的生命週期約定">Deployment Contract&lt;/a>）。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/environment-protection/" data-link-title="Environment Protection" data-link-desc="說明目標環境的審核、權限與放行條件如何保護發布">Environment protection&lt;/a> 適合正式環境。即使 build 與測試通過，production 或其他目標環境仍可要求人工審核、特定分支或特定 reviewer 才能部署（治理延伸見 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/release-gate/" data-link-title="Release Gate" data-link-desc="說明變更在正式釋出前如何通過或阻擋">Release Gate&lt;/a>）。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff&lt;/a> 適合避免「測試一份、發布另一份」的漂移。較嚴謹的流程會讓 build job 產生 artifact，test job 驗證這份 artifact，deploy job 發布同一份 artifact（供應鏈延伸見 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/artifact-provenance/" data-link-title="Artifact Provenance" data-link-desc="說明交付物的來源、完整性與簽章關聯如何建立信任">Artifact Provenance&lt;/a>）。&lt;/p>
&lt;h2 id="workflow-邊界">Workflow 邊界&lt;/h2>
&lt;p>Workflow 邊界的責任是決定哪些步驟共享同一條執行圖。放在同一條 workflow 裡的 job 可以用 &lt;code>needs&lt;/code> 建立顯式依賴；分散在不同 workflow 裡的流程，通常要靠 branch protection 或 environment protection 建立跨 workflow gate。&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>單一 workflow 多 job&lt;/td>
 &lt;td>test / build / deploy 緊密相依&lt;/td>
 &lt;td>YAML 變長，但依賴關係清楚&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>多 workflow&lt;/td>
 &lt;td>不同觸發條件或責任完全不同&lt;/td>
 &lt;td>跨 workflow gate 要靠 repo 設定&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>PR workflow + deploy&lt;/td>
 &lt;td>PR 驗證、main 發布分離&lt;/td>
 &lt;td>main push 若缺 required checks 會漏&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Artifact pipeline&lt;/td>
 &lt;td>同一份產物要被測試再發布&lt;/td>
 &lt;td>artifact 版本與權限要治理&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>多 workflow 的關鍵風險是順序假設。GitHub Actions 的 workflow 彼此獨立；跨 workflow 順序需要靠 repository 設定或 API 顯式串接。&lt;/p></description><content:encoded><![CDATA[<p>CI gate 的核心責任是把「是否進入下一階段」變成明確條件。測試、建置、發布與人工審核可以分成不同 workflow 或 job，但只要它們共同決定同一次發布，就需要有清楚的 gate 關係。</p>
<h2 id="gate-形式">Gate 形式</h2>
<p>Gate 形式要依控制範圍選擇。PR 合併、job 執行順序、production 發布與 artifact 傳遞是四種不同責任，混在一起會讓紅燈的意義變模糊。</p>
<table>
  <thead>
      <tr>
          <th>Gate 形式</th>
          <th>責任</th>
          <th>判讀方式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/required-checks/" data-link-title="Required Checks" data-link-desc="說明 pull request 的必要檢查如何作為合併 gate">Required checks</a></td>
          <td>阻止未通過測試的 commit 合併</td>
          <td>PR 或 branch protection 顯示必須通過</td>
      </tr>
      <tr>
          <td>Job <code>needs</code></td>
          <td>讓 deploy 等 test / build</td>
          <td>同一 workflow 內 deploy 依賴前置 job</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/environment-protection/" data-link-title="Environment Protection" data-link-desc="說明目標環境的審核、權限與放行條件如何保護發布">Environment protection</a></td>
          <td>控制 production / target environment 發布</td>
          <td>部署環境需要審核或 required reviewers</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff</a></td>
          <td>確保測試與發布使用同一份產物</td>
          <td>test job 產生 artifact，deploy job 使用</td>
      </tr>
  </tbody>
</table>
<p><a href="/blog/ci/knowledge-cards/required-checks/" data-link-title="Required Checks" data-link-desc="說明 pull request 的必要檢查如何作為合併 gate">Required checks</a> 適合保護主線。它讓測試結果成為合併條件，避免紅燈變更進入 <code>main</code> 或 release branch（backend 延伸見 <a href="/blog/backend/knowledge-cards/ci-pipeline/" data-link-title="CI Pipeline" data-link-desc="說明持續整合流程如何在合併前驗證品質與相容性">CI Pipeline</a>）。</p>
<p>Job <code>needs</code> 適合同一條 workflow 內的發布管線。它讓 <code>deploy</code> 必須等 <code>test</code>、<code>build</code> 或 <code>package</code> 成功後才執行，避免 deploy job 先於驗證結果流動（platform 延伸見 <a href="/blog/backend/knowledge-cards/deployment-contract/" data-link-title="Deployment Contract" data-link-desc="說明服務與部署平台之間的生命週期約定">Deployment Contract</a>）。</p>
<p><a href="/blog/ci/knowledge-cards/environment-protection/" data-link-title="Environment Protection" data-link-desc="說明目標環境的審核、權限與放行條件如何保護發布">Environment protection</a> 適合正式環境。即使 build 與測試通過，production 或其他目標環境仍可要求人工審核、特定分支或特定 reviewer 才能部署（治理延伸見 <a href="/blog/backend/knowledge-cards/release-gate/" data-link-title="Release Gate" data-link-desc="說明變更在正式釋出前如何通過或阻擋">Release Gate</a>）。</p>
<p><a href="/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff</a> 適合避免「測試一份、發布另一份」的漂移。較嚴謹的流程會讓 build job 產生 artifact，test job 驗證這份 artifact，deploy job 發布同一份 artifact（供應鏈延伸見 <a href="/blog/backend/knowledge-cards/artifact-provenance/" data-link-title="Artifact Provenance" data-link-desc="說明交付物的來源、完整性與簽章關聯如何建立信任">Artifact Provenance</a>）。</p>
<h2 id="workflow-邊界">Workflow 邊界</h2>
<p>Workflow 邊界的責任是決定哪些步驟共享同一條執行圖。放在同一條 workflow 裡的 job 可以用 <code>needs</code> 建立顯式依賴；分散在不同 workflow 裡的流程，通常要靠 branch protection 或 environment protection 建立跨 workflow gate。</p>
<table>
  <thead>
      <tr>
          <th>結構</th>
          <th>適合情境</th>
          <th>常見風險</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>單一 workflow 多 job</td>
          <td>test / build / deploy 緊密相依</td>
          <td>YAML 變長，但依賴關係清楚</td>
      </tr>
      <tr>
          <td>多 workflow</td>
          <td>不同觸發條件或責任完全不同</td>
          <td>跨 workflow gate 要靠 repo 設定</td>
      </tr>
      <tr>
          <td>PR workflow + deploy</td>
          <td>PR 驗證、main 發布分離</td>
          <td>main push 若缺 required checks 會漏</td>
      </tr>
      <tr>
          <td>Artifact pipeline</td>
          <td>同一份產物要被測試再發布</td>
          <td>artifact 版本與權限要治理</td>
      </tr>
  </tbody>
</table>
<p>多 workflow 的關鍵風險是順序假設。GitHub Actions 的 workflow 彼此獨立；跨 workflow 順序需要靠 repository 設定或 API 顯式串接。</p>
<h2 id="發布阻擋判讀">發布阻擋判讀</h2>
<p>發布阻擋要同時看 YAML 與 GitHub repository 設定。YAML 說明 workflow 或 job 如何執行；跨 workflow 的「測試通過才發布」通常要靠 <a href="/blog/ci/knowledge-cards/branch-protection/" data-link-title="Branch Protection" data-link-desc="說明主線分支如何以規則保護合併與發布前置條件">Branch Protection</a>、required status checks 或 environment protection。</p>
<table>
  <thead>
      <tr>
          <th>問題</th>
          <th>只看 YAML 能判斷嗎</th>
          <th>應檢查的位置</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>deploy 是否等 build</td>
          <td>可以</td>
          <td>同 workflow 的 <code>needs</code></td>
      </tr>
      <tr>
          <td>deploy 是否等另一條 test workflow</td>
          <td>通常要查設定</td>
          <td><a href="/blog/ci/knowledge-cards/branch-protection/" data-link-title="Branch Protection" data-link-desc="說明主線分支如何以規則保護合併與發布前置條件">Branch Protection</a> / <a href="/blog/ci/knowledge-cards/required-checks/" data-link-title="Required Checks" data-link-desc="說明 pull request 的必要檢查如何作為合併 gate">Required Checks</a></td>
      </tr>
      <tr>
          <td>PR 是否必須通過測試才能合併</td>
          <td>需要查 repo 設定</td>
          <td><a href="/blog/ci/knowledge-cards/branch-protection/" data-link-title="Branch Protection" data-link-desc="說明主線分支如何以規則保護合併與發布前置條件">Branch Protection</a></td>
      </tr>
      <tr>
          <td>目標環境是否需要人工審核</td>
          <td>需要查環境設定</td>
          <td>Environment protection</td>
      </tr>
      <tr>
          <td>測試與發布是否同一份 artifact</td>
          <td>可以部分判斷</td>
          <td>workflow artifact upload / download</td>
      </tr>
  </tbody>
</table>
<p>這個判讀順序能避免錯修。若測試紅燈但目標環境仍發布，問題通常在 deploy gate 尚未把測試狀態納入發布條件。</p>
<h2 id="常見反模式">常見反模式</h2>
<p>反模式的共同問題是讓 CI 綠燈與發布安全之間失去因果關係。CI 的目標是讓綠燈代表「這次變更在定義好的條件下可進下一階段」。</p>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>風險</th>
          <th>替代做法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>deploy workflow 不等 test</td>
          <td>測試紅燈仍可能發布</td>
          <td>用 required checks 或 <code>needs</code></td>
      </tr>
      <tr>
          <td>CI 與本機命令不同</td>
          <td>本機通過但 CI 失敗</td>
          <td>把命令收斂到 Makefile / npm script</td>
      </tr>
      <tr>
          <td>測試與發布各自 build</td>
          <td>測試產物與發布產物漂移</td>
          <td>用 artifact handoff</td>
      </tr>
      <tr>
          <td>看到紅燈直接重跑</td>
          <td>掩蓋 flaky 或環境問題</td>
          <td>先看失敗 log，再決定是否重跑</td>
      </tr>
      <tr>
          <td>用 <code>--no-verify</code> 或跳過 CI</td>
          <td>把局部問題帶進主線</td>
          <td>修掉 gate 或明確記錄例外</td>
      </tr>
  </tbody>
</table>
<h2 id="tripwire">Tripwire</h2>
<p>Tripwire 的責任是提示什麼時候 workflow 結構需要重切，讓團隊從局部 patch 回到 gate 設計。</p>
<ul>
<li>測試紅燈仍發布：把 deploy gate 顯式化，使用 required checks 或同 workflow <code>needs</code>。</li>
<li>本機常常重現不出 CI：把命令收斂到 <code>Makefile</code> 或 <code>npm scripts</code>，減少 workflow 專屬命令。</li>
<li>測試常因 artifact 缺失失敗：建立 artifact handoff，讓測試與發布使用同一份產物。</li>
<li>workflow 說明與實作分叉：同步更新 workflow 文件與 YAML，讓維護入口保持可信。</li>
</ul>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>CI 紅燈處理流程：讀 <a href="../github-actions-failure-flow/">CI 失敗到修復發布流程</a>。</li>
<li>靜態站部署案例：讀 <a href="../blog-project-deploy/">本 blog 專案部署</a>。</li>
<li>可靠性層的 release gate：讀 <a href="/blog/backend/06-reliability/release-gate/" data-link-title="6.8 Release Gate 與變更節奏" data-link-desc="把驗證、migration、相容性納入放行判準">6.8 Release Gate 與變更節奏</a>。</li>
</ul>
]]></content:encoded></item><item><title>Artifact</title><link>https://tarrragon.github.io/blog/ci/knowledge-cards/artifact/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/knowledge-cards/artifact/</guid><description>&lt;p>Artifact 的核心概念是「可被追溯的交付產物」。它是 build 的輸出單位，也是 test 與 deploy 的共同依據。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Artifact 位在 build、test、package、deploy 之間，常見形式包含靜態網站檔案、container image、app bundle、安裝包與報告檔案。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;ul>
&lt;li>測試與部署的輸入來源需要一致。&lt;/li>
&lt;li>發布事故需要從線上版本反查 build run。&lt;/li>
&lt;li>團隊需要管理產物保留時間與完整性驗證。&lt;/li>
&lt;/ul>
&lt;h2 id="接近真實服務的例子">接近真實服務的例子&lt;/h2>
&lt;p>前端靜態站會把 &lt;code>public/&lt;/code> 作為 artifact，上傳後再部署。後端則用 image digest 作為 artifact 識別，推進到不同環境。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>Artifact 要定義命名、版本追溯、保留策略與完整性檢查，讓發布結果可重播、可比對、可審計。&lt;/p></description><content:encoded><![CDATA[<p>Artifact 的核心概念是「可被追溯的交付產物」。它是 build 的輸出單位，也是 test 與 deploy 的共同依據。</p>
<h2 id="概念位置">概念位置</h2>
<p>Artifact 位在 build、test、package、deploy 之間，常見形式包含靜態網站檔案、container image、app bundle、安裝包與報告檔案。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<ul>
<li>測試與部署的輸入來源需要一致。</li>
<li>發布事故需要從線上版本反查 build run。</li>
<li>團隊需要管理產物保留時間與完整性驗證。</li>
</ul>
<h2 id="接近真實服務的例子">接近真實服務的例子</h2>
<p>前端靜態站會把 <code>public/</code> 作為 artifact，上傳後再部署。後端則用 image digest 作為 artifact 識別，推進到不同環境。</p>
<h2 id="設計責任">設計責任</h2>
<p>Artifact 要定義命名、版本追溯、保留策略與完整性檢查，讓發布結果可重播、可比對、可審計。</p>
]]></content:encoded></item><item><title>Artifact Handoff</title><link>https://tarrragon.github.io/blog/ci/knowledge-cards/artifact-handoff/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/knowledge-cards/artifact-handoff/</guid><description>&lt;p>Artifact Handoff 的核心概念是「測試與發布共用同一份產物」。它把可重現性從口頭約定變成流程保證。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Artifact Handoff 位在 build、test、deploy 之間，透過 upload / download artifact 串接驗證與發布。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;ul>
&lt;li>測試通過但部署後行為與測試結果不一致。&lt;/li>
&lt;li>多環境重新 build 造成版本漂移。&lt;/li>
&lt;li>事故追查時缺少從部署版本反查 build run 的路徑。&lt;/li>
&lt;/ul>
&lt;h2 id="接近真實服務的例子">接近真實服務的例子&lt;/h2>
&lt;p>CI build 產生靜態網站 artifact，browser test 驗證該 artifact，deploy job 再發布同一份產物。容器場域則可把 image digest 當成 handoff 物件。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>Artifact Handoff 要定義產物格式、保留策略、完整性驗證與追溯欄位，讓測試結果可直接映射到發布結果。&lt;/p></description><content:encoded><![CDATA[<p>Artifact Handoff 的核心概念是「測試與發布共用同一份產物」。它把可重現性從口頭約定變成流程保證。</p>
<h2 id="概念位置">概念位置</h2>
<p>Artifact Handoff 位在 build、test、deploy 之間，透過 upload / download artifact 串接驗證與發布。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<ul>
<li>測試通過但部署後行為與測試結果不一致。</li>
<li>多環境重新 build 造成版本漂移。</li>
<li>事故追查時缺少從部署版本反查 build run 的路徑。</li>
</ul>
<h2 id="接近真實服務的例子">接近真實服務的例子</h2>
<p>CI build 產生靜態網站 artifact，browser test 驗證該 artifact，deploy job 再發布同一份產物。容器場域則可把 image digest 當成 handoff 物件。</p>
<h2 id="設計責任">設計責任</h2>
<p>Artifact Handoff 要定義產物格式、保留策略、完整性驗證與追溯欄位，讓測試結果可直接映射到發布結果。</p>
]]></content:encoded></item><item><title>Artifact 與可重播性</title><link>https://tarrragon.github.io/blog/ci/artifact-reproducibility/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/artifact-reproducibility/</guid><description>&lt;p>Artifact 可重播性的核心責任是讓每次發布都能追到同一份被驗證的產物。CI/CD 不只是在 runner 上跑命令；它要回答「測試通過的是哪份內容」「發布出去的是哪份內容」「事故時如何找回同一份內容」。&lt;/p>
&lt;h2 id="概念定位">概念定位&lt;/h2>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/artifact/" data-link-title="Artifact" data-link-desc="說明 CI/CD 中可被驗證、保存與發布的交付產物">Artifact&lt;/a> 是 CI/CD 流程中的交付單位。前端可能是 &lt;code>dist/&lt;/code>，後端可能是 binary 或 image，App 可能是 IPA / AAB，資料任務可能是 DAG 或 query package；不同形式的 artifact 都承擔同一個責任：把 source change 轉成可驗證、可保存、可推進的產物。&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 once&lt;/td>
 &lt;td>同一次變更只產生一次正式 artifact&lt;/td>
 &lt;td>build job 是否保存產物&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Verify once&lt;/td>
 &lt;td>測試同一份 artifact&lt;/td>
 &lt;td>test job 是否 download artifact&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff&lt;/a>&lt;/td>
 &lt;td>在 job / workflow 間交接產物&lt;/td>
 &lt;td>checksum、digest、version 是否一致&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Promote same artifact&lt;/td>
 &lt;td>staging / production 推進同一份&lt;/td>
 &lt;td>production 是否重新 build&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Recover artifact&lt;/td>
 &lt;td>事故時找回上一份可用產物&lt;/td>
 &lt;td>retention、release、registry 是否保留&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Build once 的責任是降低環境漂移。若 test job 與 deploy job 各自 build，一個 lockfile、環境變數或 base image 差異就能讓兩份產物不同；此時 CI 綠燈不再能證明 production 內容可信。&lt;/p>
&lt;p>Verify once 的責任是把測試結果綁到具體產物。測試應輸出 artifact identity，例如 checksum、&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/image-digest/" data-link-title="Image Digest" data-link-desc="說明 container image digest 如何作為不可變產物身分，支撐掃描、推進與 runtime 追溯">Image Digest&lt;/a>、release asset name 或 bundle version，讓 reviewer 能確認紅綠燈對應哪份內容。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff&lt;/a> 的責任是在 job 邊界保留身分。Upload / download artifact、registry digest、release asset、package registry 與 object storage 都可以做 handoff；重點是交接時沿用既有產物。&lt;/p>
&lt;p>Promote same artifact 的責任是讓環境差異集中在設定與流量。Staging 驗證過的 image、package 或 static artifact 應被推進到 production；若 production 重新 build，就需要重新驗證 production 那份產物。&lt;/p>
&lt;p>Recover artifact 的責任是讓 rollback 有實體目標。沒有保留 artifact 的 rollback 會變成「從舊 commit 重新 build」，這會受到依賴、base image、registry、toolchain 與時間漂移影響。&lt;/p>
&lt;h2 id="可重播性檢查">可重播性檢查&lt;/h2>
&lt;p>可重播性檢查的責任是確認產物身分與建置條件足夠明確。嚴格 reproducible build 很難在所有專案做到，但 CI/CD 至少要達到「同一次 workflow 的產物可以被查詢、保存、驗證與重新部署」。&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>Source&lt;/td>
 &lt;td>artifact 對應哪個 commit&lt;/td>
 &lt;td>embed git SHA / release version&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Dependency&lt;/td>
 &lt;td>dependency 是否固定&lt;/td>
 &lt;td>lockfile、base image digest&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Environment&lt;/td>
 &lt;td>build 環境是否固定&lt;/td>
 &lt;td>runner image、toolchain version&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Identity&lt;/td>
 &lt;td>artifact 是否有不可變身分&lt;/td>
 &lt;td>checksum、digest、signature&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Retention&lt;/td>
 &lt;td>artifact 保留多久&lt;/td>
 &lt;td>release asset、registry retention&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Provenance&lt;/td>
 &lt;td>artifact 如何被產生&lt;/td>
 &lt;td>workflow run、&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/sbom/" data-link-title="SBOM" data-link-desc="說明 Software Bill of Materials 如何揭露 artifact 內含元件，支撐供應鏈掃描與例外治理">SBOM&lt;/a>、attestation&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>這張表讓團隊知道自己目前在哪個成熟度。初期可以先做到 source、dependency、identity；高治理場景再補 SBOM、signature 與 provenance。&lt;/p></description><content:encoded><![CDATA[<p>Artifact 可重播性的核心責任是讓每次發布都能追到同一份被驗證的產物。CI/CD 不只是在 runner 上跑命令；它要回答「測試通過的是哪份內容」「發布出去的是哪份內容」「事故時如何找回同一份內容」。</p>
<h2 id="概念定位">概念定位</h2>
<p><a href="/blog/ci/knowledge-cards/artifact/" data-link-title="Artifact" data-link-desc="說明 CI/CD 中可被驗證、保存與發布的交付產物">Artifact</a> 是 CI/CD 流程中的交付單位。前端可能是 <code>dist/</code>，後端可能是 binary 或 image，App 可能是 IPA / AAB，資料任務可能是 DAG 或 query package；不同形式的 artifact 都承擔同一個責任：把 source change 轉成可驗證、可保存、可推進的產物。</p>
<table>
  <thead>
      <tr>
          <th>能力</th>
          <th>責任</th>
          <th>判讀訊號</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build once</td>
          <td>同一次變更只產生一次正式 artifact</td>
          <td>build job 是否保存產物</td>
      </tr>
      <tr>
          <td>Verify once</td>
          <td>測試同一份 artifact</td>
          <td>test job 是否 download artifact</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff</a></td>
          <td>在 job / workflow 間交接產物</td>
          <td>checksum、digest、version 是否一致</td>
      </tr>
      <tr>
          <td>Promote same artifact</td>
          <td>staging / production 推進同一份</td>
          <td>production 是否重新 build</td>
      </tr>
      <tr>
          <td>Recover artifact</td>
          <td>事故時找回上一份可用產物</td>
          <td>retention、release、registry 是否保留</td>
      </tr>
  </tbody>
</table>
<p>Build once 的責任是降低環境漂移。若 test job 與 deploy job 各自 build，一個 lockfile、環境變數或 base image 差異就能讓兩份產物不同；此時 CI 綠燈不再能證明 production 內容可信。</p>
<p>Verify once 的責任是把測試結果綁到具體產物。測試應輸出 artifact identity，例如 checksum、<a href="/blog/ci/knowledge-cards/image-digest/" data-link-title="Image Digest" data-link-desc="說明 container image digest 如何作為不可變產物身分，支撐掃描、推進與 runtime 追溯">Image Digest</a>、release asset name 或 bundle version，讓 reviewer 能確認紅綠燈對應哪份內容。</p>
<p><a href="/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact handoff</a> 的責任是在 job 邊界保留身分。Upload / download artifact、registry digest、release asset、package registry 與 object storage 都可以做 handoff；重點是交接時沿用既有產物。</p>
<p>Promote same artifact 的責任是讓環境差異集中在設定與流量。Staging 驗證過的 image、package 或 static artifact 應被推進到 production；若 production 重新 build，就需要重新驗證 production 那份產物。</p>
<p>Recover artifact 的責任是讓 rollback 有實體目標。沒有保留 artifact 的 rollback 會變成「從舊 commit 重新 build」，這會受到依賴、base image、registry、toolchain 與時間漂移影響。</p>
<h2 id="可重播性檢查">可重播性檢查</h2>
<p>可重播性檢查的責任是確認產物身分與建置條件足夠明確。嚴格 reproducible build 很難在所有專案做到，但 CI/CD 至少要達到「同一次 workflow 的產物可以被查詢、保存、驗證與重新部署」。</p>
<table>
  <thead>
      <tr>
          <th>檢查項</th>
          <th>判讀問題</th>
          <th>常見做法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Source</td>
          <td>artifact 對應哪個 commit</td>
          <td>embed git SHA / release version</td>
      </tr>
      <tr>
          <td>Dependency</td>
          <td>dependency 是否固定</td>
          <td>lockfile、base image digest</td>
      </tr>
      <tr>
          <td>Environment</td>
          <td>build 環境是否固定</td>
          <td>runner image、toolchain version</td>
      </tr>
      <tr>
          <td>Identity</td>
          <td>artifact 是否有不可變身分</td>
          <td>checksum、digest、signature</td>
      </tr>
      <tr>
          <td>Retention</td>
          <td>artifact 保留多久</td>
          <td>release asset、registry retention</td>
      </tr>
      <tr>
          <td>Provenance</td>
          <td>artifact 如何被產生</td>
          <td>workflow run、<a href="/blog/ci/knowledge-cards/sbom/" data-link-title="SBOM" data-link-desc="說明 Software Bill of Materials 如何揭露 artifact 內含元件，支撐供應鏈掃描與例外治理">SBOM</a>、attestation</td>
      </tr>
  </tbody>
</table>
<p>這張表讓團隊知道自己目前在哪個成熟度。初期可以先做到 source、dependency、identity；高治理場景再補 SBOM、signature 與 provenance。</p>
<h2 id="常見反模式">常見反模式</h2>
<p>反模式的共同問題是讓「綠燈」失去指向性。當綠燈不知道對應哪份產物，CI/CD 只剩下命令執行紀錄。</p>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>風險</th>
          <th>替代做法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>test 與 deploy 各自 build</td>
          <td>測試與發布內容漂移</td>
          <td>build once，artifact handoff</td>
      </tr>
      <tr>
          <td>rollback 重新 build 舊 commit</td>
          <td>舊 commit 可能產出不同內容</td>
          <td>保留上一份 release artifact</td>
      </tr>
      <tr>
          <td>只用人類可讀 tag</td>
          <td>tag 可被覆寫或語意不精準</td>
          <td>搭配 checksum / digest</td>
      </tr>
      <tr>
          <td>artifact retention 太短</td>
          <td>事故時找不到可回復版本</td>
          <td>對 release artifact 設長期保留</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>Artifact 術語：讀 <a href="/blog/ci/knowledge-cards/artifact/" data-link-title="Artifact" data-link-desc="說明 CI/CD 中可被驗證、保存與發布的交付產物">Artifact</a>。</li>
<li>Artifact handoff：讀 <a href="/blog/ci/knowledge-cards/artifact-handoff/" data-link-title="Artifact Handoff" data-link-desc="說明測試與部署如何共用同一份可追溯產物">Artifact Handoff</a>。</li>
<li>Gate 邊界：讀 <a href="../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a>。</li>
</ul>
]]></content:encoded></item><item><title>3CX 2023：供應鏈 Artifact 壓力</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/field-cases/3cx-2023-supply-chain-artifact-pressure/</link><pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/field-cases/3cx-2023-supply-chain-artifact-pressure/</guid><description>&lt;p>本案例的責任是提供供應鏈 artifact 壓力素材。3CX 2023 事件顯示，第三方軟體、員工端點、build 系統與客戶下載 artifact 可以形成連鎖供應鏈壓力。&lt;/p>
&lt;h2 id="來源">來源&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>來源&lt;/th>
 &lt;th>可引用範圍&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="https://cloud.google.com/blog/topics/threat-intelligence/3cx-software-supply-chain-compromise">Mandiant：3CX software supply chain compromise&lt;/a>&lt;/td>
 &lt;td>供應鏈連鎖、initial compromise、trojanized desktop app、UNC4736&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://www.3cx.com/blog/news/mandiant-security-update2/">3CX：Initial intrusion vector found&lt;/a>&lt;/td>
 &lt;td>X_TRADER 初始入侵、VEILEDSIGNAL、IOC 與 vendor update&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://www.cisa.gov/news-events/alerts/2023/03/30/supply-chain-attack-against-3cxdesktopapp">CISA：Supply Chain Attack Against 3CXDesktopApp&lt;/a>&lt;/td>
 &lt;td>user guidance、IOC hunting、vendor communications&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="defender-pressure">Defender Pressure&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>壓力&lt;/th>
 &lt;th>服務判讀&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Artifact trust pressure&lt;/td>
 &lt;td>客戶下載的 legitimate app 需要可驗證 provenance&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Build environment pressure&lt;/td>
 &lt;td>build 系統需要和 endpoint compromise 風險分離&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Customer response pressure&lt;/td>
 &lt;td>供應鏈事件需要快速提供 uninstall、hunt 與 update 路由&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Release gate pressure&lt;/td>
 &lt;td>release process 需要能驗證來源、簽章與 build evidence&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="control-gap">Control Gap&lt;/h2>
&lt;p>控制缺口的核心是 artifact trust 需要跨越端點、CI、簽章與發佈流程。當 initial compromise 來自上游軟體時，單一 release gate 需要補足來源信任、build isolation 與 customer communication。&lt;/p>
&lt;h2 id="detection-route">Detection Route&lt;/h2>
&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>artifact hash 與預期不一致&lt;/td>
 &lt;td>判斷 release integrity&lt;/td>
 &lt;td>啟動 release freeze 與 rollback&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>build 來源或簽章證據缺口&lt;/td>
 &lt;td>判斷 provenance gap&lt;/td>
 &lt;td>啟動 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/artifact-provenance/" data-link-title="Artifact Provenance" data-link-desc="說明交付物的來源、完整性與簽章關聯如何建立信任">artifact provenance&lt;/a> review&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>客戶端 IOC 命中&lt;/td>
 &lt;td>判斷 downstream impact&lt;/td>
 &lt;td>啟動 customer advisory route&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="exercise-hook">Exercise Hook&lt;/h2>
&lt;p>本案例可支撐 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/scenarios/supply-chain-artifact-drill/" data-link-title="Supply Chain Artifact Drill" data-link-desc="以 artifact provenance 偏移設計供應鏈 release gate 與 rollback 演練">Supply chain artifact drill&lt;/a>。演練重點是確認 artifact provenance、release freeze、rollback 與 customer communication 是否能在同一事件中協作。&lt;/p>
&lt;h2 id="write-back-target">Write-back Target&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/supply-chain-integrity-and-artifact-trust/" data-link-title="7.12 供應鏈完整性與 Artifact 信任" data-link-desc="定義 build provenance、artifact 信任與交付鏈風險問題">7.12 供應鏈完整性與 Artifact 信任&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/security-risk-in-release-gate/" data-link-title="7.22 資安風險如何進入 Release Gate" data-link-desc="把資安風險、例外與驗證證據納入 release gate，建立可稽核的放行判準">7.22 資安風險如何進入 Release Gate&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/detection-lifecycle-pattern/" data-link-title="Detection Lifecycle Pattern" data-link-desc="定義偵測規則如何管理來源、邏輯、測試事件、誤報與退場">Detection lifecycle pattern&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/exercise-write-back-pattern/" data-link-title="Exercise Write-back Pattern" data-link-desc="定義 tabletop 與 game day 如何把 finding 回寫成控制更新、runbook 更新與 [tripwire](/backend/knowledge-cards/tripwire/)">Exercise write-back pattern&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>本案例的責任是提供供應鏈 artifact 壓力素材。3CX 2023 事件顯示，第三方軟體、員工端點、build 系統與客戶下載 artifact 可以形成連鎖供應鏈壓力。</p>
<h2 id="來源">來源</h2>
<table>
  <thead>
      <tr>
          <th>來源</th>
          <th>可引用範圍</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://cloud.google.com/blog/topics/threat-intelligence/3cx-software-supply-chain-compromise">Mandiant：3CX software supply chain compromise</a></td>
          <td>供應鏈連鎖、initial compromise、trojanized desktop app、UNC4736</td>
      </tr>
      <tr>
          <td><a href="https://www.3cx.com/blog/news/mandiant-security-update2/">3CX：Initial intrusion vector found</a></td>
          <td>X_TRADER 初始入侵、VEILEDSIGNAL、IOC 與 vendor update</td>
      </tr>
      <tr>
          <td><a href="https://www.cisa.gov/news-events/alerts/2023/03/30/supply-chain-attack-against-3cxdesktopapp">CISA：Supply Chain Attack Against 3CXDesktopApp</a></td>
          <td>user guidance、IOC hunting、vendor communications</td>
      </tr>
  </tbody>
</table>
<h2 id="defender-pressure">Defender Pressure</h2>
<table>
  <thead>
      <tr>
          <th>壓力</th>
          <th>服務判讀</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Artifact trust pressure</td>
          <td>客戶下載的 legitimate app 需要可驗證 provenance</td>
      </tr>
      <tr>
          <td>Build environment pressure</td>
          <td>build 系統需要和 endpoint compromise 風險分離</td>
      </tr>
      <tr>
          <td>Customer response pressure</td>
          <td>供應鏈事件需要快速提供 uninstall、hunt 與 update 路由</td>
      </tr>
      <tr>
          <td>Release gate pressure</td>
          <td>release process 需要能驗證來源、簽章與 build evidence</td>
      </tr>
  </tbody>
</table>
<h2 id="control-gap">Control Gap</h2>
<p>控制缺口的核心是 artifact trust 需要跨越端點、CI、簽章與發佈流程。當 initial compromise 來自上游軟體時，單一 release gate 需要補足來源信任、build isolation 與 customer communication。</p>
<h2 id="detection-route">Detection Route</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>判讀用途</th>
          <th>下一步</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>artifact hash 與預期不一致</td>
          <td>判斷 release integrity</td>
          <td>啟動 release freeze 與 rollback</td>
      </tr>
      <tr>
          <td>build 來源或簽章證據缺口</td>
          <td>判斷 provenance gap</td>
          <td>啟動 <a href="/blog/backend/knowledge-cards/artifact-provenance/" data-link-title="Artifact Provenance" data-link-desc="說明交付物的來源、完整性與簽章關聯如何建立信任">artifact provenance</a> review</td>
      </tr>
      <tr>
          <td>客戶端 IOC 命中</td>
          <td>判斷 downstream impact</td>
          <td>啟動 customer advisory route</td>
      </tr>
  </tbody>
</table>
<h2 id="exercise-hook">Exercise Hook</h2>
<p>本案例可支撐 <a href="/blog/backend/07-security-data-protection/blue-team/materials/scenarios/supply-chain-artifact-drill/" data-link-title="Supply Chain Artifact Drill" data-link-desc="以 artifact provenance 偏移設計供應鏈 release gate 與 rollback 演練">Supply chain artifact drill</a>。演練重點是確認 artifact provenance、release freeze、rollback 與 customer communication 是否能在同一事件中協作。</p>
<h2 id="write-back-target">Write-back Target</h2>
<ul>
<li><a href="/blog/backend/07-security-data-protection/supply-chain-integrity-and-artifact-trust/" data-link-title="7.12 供應鏈完整性與 Artifact 信任" data-link-desc="定義 build provenance、artifact 信任與交付鏈風險問題">7.12 供應鏈完整性與 Artifact 信任</a></li>
<li><a href="/blog/backend/07-security-data-protection/security-risk-in-release-gate/" data-link-title="7.22 資安風險如何進入 Release Gate" data-link-desc="把資安風險、例外與驗證證據納入 release gate，建立可稽核的放行判準">7.22 資安風險如何進入 Release Gate</a></li>
<li><a href="/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/detection-lifecycle-pattern/" data-link-title="Detection Lifecycle Pattern" data-link-desc="定義偵測規則如何管理來源、邏輯、測試事件、誤報與退場">Detection lifecycle pattern</a></li>
<li><a href="/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/exercise-write-back-pattern/" data-link-title="Exercise Write-back Pattern" data-link-desc="定義 tabletop 與 game day 如何把 finding 回寫成控制更新、runbook 更新與 [tripwire](/backend/knowledge-cards/tripwire/)">Exercise write-back pattern</a></li>
</ul>
]]></content:encoded></item><item><title>Supply Chain Artifact Drill</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/scenarios/supply-chain-artifact-drill/</link><pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/scenarios/supply-chain-artifact-drill/</guid><description>&lt;p>本情境的責任是演練 artifact provenance 與 release gate。它以 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/field-cases/3cx-2023-supply-chain-artifact-pressure/" data-link-title="3CX 2023：供應鏈 Artifact 壓力" data-link-desc="把 3CX supply chain compromise 轉成 build、artifact、來源信任與 release gate 的藍隊案例素材">3CX 2023 supply chain case&lt;/a> 為來源，轉成通用軟體供應鏈 artifact drill。&lt;/p>
&lt;h2 id="scenario-trigger">Scenario Trigger&lt;/h2>
&lt;p>客戶回報桌面客戶端或 agent 版本觸發 EDR alert。內部比對發現公開下載 artifact、build record 與簽章證據之間存在偏移。&lt;/p>
&lt;h2 id="initial-hypothesis">Initial Hypothesis&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>假設&lt;/th>
 &lt;th>驗證資料&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>artifact 在 build 後被替換&lt;/td>
 &lt;td>checksum、registry log、publish log&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>build environment 受影響&lt;/td>
 &lt;td>CI log、runner image、credential use&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>upstream dependency 或工具引入污染&lt;/td>
 &lt;td>dependency provenance、developer endpoint evidence&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="control-surface">Control Surface&lt;/h2>
&lt;p>控制面包含 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/artifact-provenance/" data-link-title="Artifact Provenance" data-link-desc="說明交付物的來源、完整性與簽章關聯如何建立信任">artifact provenance&lt;/a>、CI pipeline、release gate、release freeze、rollback 與 customer advisory。&lt;/p>
&lt;h2 id="response-route">Response Route&lt;/h2>
&lt;ol>
&lt;li>Freeze：暫停 affected artifact 發佈與自動更新。&lt;/li>
&lt;li>Scope：比對 artifact hash、download log、customer version distribution。&lt;/li>
&lt;li>Validate：重建 clean build、驗證簽章與 provenance。&lt;/li>
&lt;li>Rollback：提供 clean artifact、uninstall 或 rollback route。&lt;/li>
&lt;li>Write-back：更新 release gate、build isolation 與 artifact evidence policy。&lt;/li>
&lt;/ol>
&lt;h2 id="evidence-target">Evidence Target&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>證據&lt;/th>
 &lt;th>用途&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>build provenance record&lt;/td>
 &lt;td>判斷 artifact 是否可追溯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>signing log&lt;/td>
 &lt;td>判斷簽章流程是否被濫用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>customer download log&lt;/td>
 &lt;td>判斷 downstream impact&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>release freeze record&lt;/td>
 &lt;td>證明風險放行被暫停&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="write-back-target">Write-back Target&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/supply-chain-integrity-and-artifact-trust/" data-link-title="7.12 供應鏈完整性與 Artifact 信任" data-link-desc="定義 build provenance、artifact 信任與交付鏈風險問題">7.12 供應鏈完整性與 Artifact 信任&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/security-risk-in-release-gate/" data-link-title="7.22 資安風險如何進入 Release Gate" data-link-desc="把資安風險、例外與驗證證據納入 release gate，建立可稽核的放行判準">7.22 資安風險如何進入 Release Gate&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/detection-lifecycle-pattern/" data-link-title="Detection Lifecycle Pattern" data-link-desc="定義偵測規則如何管理來源、邏輯、測試事件、誤報與退場">Detection lifecycle pattern&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/exercise-write-back-pattern/" data-link-title="Exercise Write-back Pattern" data-link-desc="定義 tabletop 與 game day 如何把 finding 回寫成控制更新、runbook 更新與 [tripwire](/backend/knowledge-cards/tripwire/)">Exercise write-back pattern&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>本情境的責任是演練 artifact provenance 與 release gate。它以 <a href="/blog/backend/07-security-data-protection/blue-team/materials/field-cases/3cx-2023-supply-chain-artifact-pressure/" data-link-title="3CX 2023：供應鏈 Artifact 壓力" data-link-desc="把 3CX supply chain compromise 轉成 build、artifact、來源信任與 release gate 的藍隊案例素材">3CX 2023 supply chain case</a> 為來源，轉成通用軟體供應鏈 artifact drill。</p>
<h2 id="scenario-trigger">Scenario Trigger</h2>
<p>客戶回報桌面客戶端或 agent 版本觸發 EDR alert。內部比對發現公開下載 artifact、build record 與簽章證據之間存在偏移。</p>
<h2 id="initial-hypothesis">Initial Hypothesis</h2>
<table>
  <thead>
      <tr>
          <th>假設</th>
          <th>驗證資料</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>artifact 在 build 後被替換</td>
          <td>checksum、registry log、publish log</td>
      </tr>
      <tr>
          <td>build environment 受影響</td>
          <td>CI log、runner image、credential use</td>
      </tr>
      <tr>
          <td>upstream dependency 或工具引入污染</td>
          <td>dependency provenance、developer endpoint evidence</td>
      </tr>
  </tbody>
</table>
<h2 id="control-surface">Control Surface</h2>
<p>控制面包含 <a href="/blog/backend/knowledge-cards/artifact-provenance/" data-link-title="Artifact Provenance" data-link-desc="說明交付物的來源、完整性與簽章關聯如何建立信任">artifact provenance</a>、CI pipeline、release gate、release freeze、rollback 與 customer advisory。</p>
<h2 id="response-route">Response Route</h2>
<ol>
<li>Freeze：暫停 affected artifact 發佈與自動更新。</li>
<li>Scope：比對 artifact hash、download log、customer version distribution。</li>
<li>Validate：重建 clean build、驗證簽章與 provenance。</li>
<li>Rollback：提供 clean artifact、uninstall 或 rollback route。</li>
<li>Write-back：更新 release gate、build isolation 與 artifact evidence policy。</li>
</ol>
<h2 id="evidence-target">Evidence Target</h2>
<table>
  <thead>
      <tr>
          <th>證據</th>
          <th>用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>build provenance record</td>
          <td>判斷 artifact 是否可追溯</td>
      </tr>
      <tr>
          <td>signing log</td>
          <td>判斷簽章流程是否被濫用</td>
      </tr>
      <tr>
          <td>customer download log</td>
          <td>判斷 downstream impact</td>
      </tr>
      <tr>
          <td>release freeze record</td>
          <td>證明風險放行被暫停</td>
      </tr>
  </tbody>
</table>
<h2 id="write-back-target">Write-back Target</h2>
<ul>
<li><a href="/blog/backend/07-security-data-protection/supply-chain-integrity-and-artifact-trust/" data-link-title="7.12 供應鏈完整性與 Artifact 信任" data-link-desc="定義 build provenance、artifact 信任與交付鏈風險問題">7.12 供應鏈完整性與 Artifact 信任</a></li>
<li><a href="/blog/backend/07-security-data-protection/security-risk-in-release-gate/" data-link-title="7.22 資安風險如何進入 Release Gate" data-link-desc="把資安風險、例外與驗證證據納入 release gate，建立可稽核的放行判準">7.22 資安風險如何進入 Release Gate</a></li>
<li><a href="/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/detection-lifecycle-pattern/" data-link-title="Detection Lifecycle Pattern" data-link-desc="定義偵測規則如何管理來源、邏輯、測試事件、誤報與退場">Detection lifecycle pattern</a></li>
<li><a href="/blog/backend/07-security-data-protection/blue-team/materials/control-patterns/exercise-write-back-pattern/" data-link-title="Exercise Write-back Pattern" data-link-desc="定義 tabletop 與 game day 如何把 finding 回寫成控制更新、runbook 更新與 [tripwire](/backend/knowledge-cards/tripwire/)">Exercise write-back pattern</a></li>
</ul>
]]></content:encoded></item></channel></rss>