---
title: "檢測 Agent 原生安裝包 — 需求討論稿 (FR-066)"
brand: "Guidant AI · **FR-066** 檢測 Agent 原生安裝包"
eyebrow: "FR-066 · Agent Native Installer — 需求討論稿 · 2026-08-18（v1 定案版）"
h1: "讓檢測 Agent 貼著宿主跑：非 docker、systemd 服務、一顆 tarball 裝完"
lede: "檢測 Agent（evidence-agent）目前唯一交付形式是 docker image＋三容器 compose。但 agent 的本職是**量測宿主機**——機器指紋要讀 `/sys/class/dmi/id/product_uuid`、`/etc/machine-id`、主網卡 MAC，這些在容器裡讀不到或會漂移，已經靠 `collect-host-id.sh` workaround 硬撐。FR-065 期間決策者裁定：**agent 安裝包另起新 FR、非 docker**。本案把 agent 做成 **Nuitka 編譯的 tarball 安裝包**，`install.sh` 一鍵裝成 systemd 服務，先做 Linux；Windows 只出評估文件。九項關鍵決策（D1–D9）已全數拍板，本稿記錄定案理由與被排除方案，供 design.md 深化。"
chips: [
  {text: "決策 D1–D9 全數定案", kind: ok},
  {text: "開放查證項 Q1–Q4", kind: warn},
  {text: "前作：FR-063（Nuitka）/ FR-064（簽章）/ FR-065（installer）", kind: accent},
  {text: "Windows 只出評估文件", kind: plain},
  {text: "tarball 全包 ~1GB+ 已接受", kind: plain}
]
footer: "FR-066 · 檢測 Agent 原生安裝包 — 需求討論稿 · 2026-08-18 v1 · 標的 repo：evidence-agent（v0.2.27）· 前作複用：FR-063 Nuitka build 管線／FR-064 簽章泛用層／FR-065 install.sh 七步結構 · 決策 D1–D9 已拍板 · 開放項 Q1–Q4 實作期查證"
---

## 分工概述（30 秒版） {#tldr sec="0" nav="30 秒版"}

**整案一句話**：把檢測 Agent 從「docker 三容器出貨」改成「Nuitka 編譯＋外部工具全包的一顆 tarball，`install.sh` 一鍵裝成 Linux systemd 服務」，宿主指紋直讀、SQLite 取代 PG、agent 自起 TLS 取代 nginx sidecar、build 期 manifest 簽章＋啟動驗章。

| 階段 | 一行說明 |
|------|---------|
| **FR-066.1** Nuitka build 管線 | agent 版 `build_release.sh`、dependency-injector 私房 wheel、version bake、`resource_path()` 改造、SQLite 化 |
| **FR-066.2** tarball 打包＋工具 bundle | 全包一顆（CINC / sonar-scanner / LibreOffice / xsltproc / git）＋ manifest 簽章 |
| **FR-066.3** install.sh＋systemd | 七步安裝、互動問答、upgrade/rollback（symlink 切換）、維運子命令、自起 TLS |
| **FR-066.4** 驗收與文件 | 乾淨機真機驗收、封閉網路驗證、客戶手冊、Windows 評估文件 |

**依賴一句**：.1 → .2 → .3 串行（build 產物是打包的輸入、打包產物是安裝的輸入），.4 收口。

## 需求背景：容器裡的 Agent 量不到宿主 {#why sec="1" nav="背景"}

### 1.1 現況交付形式

檢測 Agent（evidence-agent，獨立 repo `~/Projects/Billows/Audit-Manager/evidence-agent`，v0.2.27，Flask + dependency-injector）目前唯一的交付形式是：

- **docker image**（`python:3.11-slim` base）
- **docker compose 三容器**：`agent` 本體 + `agent-db`（postgres:16）+ `nginx` mTLS sidecar
- 出貨走 `docker save` / `docker load`

### 1.2 為什麼必須脫離 docker

FR-065（產品落地 installer）期間，決策者裁定：**agent 安裝包另起新 FR、非 docker**。核心理由是 agent 的本職與容器化根本衝突：

::::::: grid2
::: {.card .crit}
#### 機器指紋讀不到／會漂移

指紋來源是 `/sys/class/dmi/id/product_uuid`、`/etc/machine-id`、主網卡 MAC——**容器內讀不到或會漂移**。已經發生過 machine-id 空檔導致指紋漂移的事故（Debian base image 的 `/etc/machine-id` 是空檔，退回隨機 MAC），現行靠 `deploy/collect-host-id.sh` workaround 從宿主抽值塞進容器硬撐。
:::

::: {.card .ok}
#### 業界同類產品皆為原生交付

Nessus Agent、Qualys Cloud Agent、Wazuh Agent、Elastic Agent、Datadog Agent——**全部以原生套件（deb/rpm/tarball）＋ systemd 服務交付**，沒有一家把主機檢測 agent 包成 docker 出貨。貼宿主量測的產品，原生安裝就是行規。
:::
:::::::

### 1.3 本案目標

- Agent 做成 **Nuitka standalone 編譯**的 tarball 安裝包
- `install.sh` 一鍵安裝為 **Linux systemd 服務**
- 外部檢測工具**全包在同一顆 tarball**，離線（封閉網路）完全自足
- **Windows 不實作**，只出評估文件與前提清單

### 1.4 前作可複用資產

本案不是從零開始——三個前作已把大部分地基打好：

| 前作 | 可直接複用 |
|------|-----------|
| **FR-063** Nuitka 落地版打包 | `scripts/build/build_release.sh` build 管線、dependency-injector 私房 wheel `rebuild_wheels.sh`、`resource_path()` 慣例、DI 靜態清單處理手法 |
| **FR-064** 防竄改偵測 | 簽章泛用層 `sign_payload` / `verify_payload`（帶 `type` 欄）、`gen_integrity_manifest.py`、`sign_manifest.sh`、License Center 簽發 |
| **FR-065** 產品落地 installer | `install.sh` 七步結構、`--check-only`、安裝落檔慣例、digest 驗證、維運子命令（status / logs / uninstall / fingerprint） |

## 決策定案（D1–D9） {#decisions sec="2" nav="決策 D1–D9"}

以下九項全部已由決策者拍板，每項記定案內容、理由與被排除方案。

### D1　打包形式＝Nuitka standalone → tarball → systemd 服務

::: {.callout .decided}
**✅ 定案：Nuitka standalone 編譯，打成 tarball，裝成 systemd 服務**

standalone 模式同樣是機器碼編譯——**自家 code 不可見**，保護強度與 FR-063 的 BE 打包相同。第三方套件以原始 `.py` 附帶（standalone 的 EXCLUDE 名單機制），但那些是公開開源套件、非自家 code，不構成洩漏。

[**排除：onefile 模式**——①啟動要先解壓到暫存目錄，有啟動延遲；②FR-064 逐檔 manifest 驗章在單一自解壓檔上難做；③外部工具（CINC / LibreOffice 等）反正要目錄形式存在，onefile 省不了目錄。]{.rec}
:::

### D2　本地 DB＝SQLite 化

::: {.callout .decided}
**✅ 定案：agent-db（postgres:16）退役，換 SQLite**

現況的 agent-db 只服務 **jedi-file-upload 的 `upload_files` 一張表**（`core/app_factory.py:37` 註解明寫；`create(checkfirst=True)` 自建表、無 migration 體系）。單表、單進程寫入、無並發、無 RLS——正是 SQLite 的甜蜜點。`init_db()` 吃 SQLAlchemy URL，換成 `sqlite:///` 即可。

**實作前置查證項（Q2）**：掃 jedi-file-upload 的 model 與查詢確認無 PG 方言依賴（jsonb / ON CONFLICT 等）。

[**排除**：①要求宿主裝 PG——加重客戶前置需求，違背一鍵安裝目標；②bundle PG 進 tarball——包更肥、多一個服務要維運（起停／備份／密碼），為一張表不值得。]{.rec}
:::

### D3　外部工具交付＝全包一顆 tarball，離線完全自足

::: {.callout .decided}
**✅ 定案：所有外部檢測工具 bundle 進同一顆 tarball，install.sh 自動安裝，離線完全自足**

決策者裁定理由：封閉網路情境（FR-059.3 已驗證為既定支援情境）下，全包才**不存在漏帶／版本錯配的現場事故**。體積 ~1GB+ 已明示接受。

**bundle 清單**：

| 工具 | 體積 | 備註 |
|------|------|------|
| CINC Auditor（Ruby omnibus） | ~275MB | ⚖️ **授權紅線：絕不可換成官方 InSpec 商業 binary** |
| sonar-scanner（含 JRE） | ~147MB | amd64 專屬 |
| LibreOffice ＋ fonts-noto-cjk | ~400MB+ | 檔案預覽轉 PDF；⚠️ 字型家族名是 `Noto Sans CJK TC` 不是 `Noto Sans TC` |
| xsltproc ＋ `assets/nmap.xsl` | 小 | nmap 報告轉換 |
| git | 小 | |

**不 bundle**：ZAP / OpenVAS（客戶自備 daemon）、OpenSCAP / Nmap 引擎（裝在目標主機、agent SSH 過去跑，不在 agent 機上）。

[**排除**：方案 B「核心包＋工具附加包分層」——升級只傳 core 較省流量，但多檔交付有漏帶風險，封閉網路現場出事沒有網路可補救；方案 C「宿主前置需求清單」——把安裝品質丟給客戶，且客戶自裝 InSpec 會踩 CINC 授權紅線。]{.rec}
:::

### D4　mTLS 承接＝agent 自起 TLS，砍掉 nginx sidecar

::: {.callout .decided}
**✅ 定案：agent 以 gunicorn/ssl 自行承接 8443 資料面 TLS，nginx sidecar 退役**

mTLS 的**驗證邏輯本來就在 agent code 內**（`core/data_plane_auth.py`），nginx 只是轉發層——砍掉它不損失任何安全能力。8443 的 server 憑證由 enrollment 時 CA 簽出（CSR SAN＝base_url host），**客戶不需自備憑證**。
:::

### D5　設定模型＝systemd EnvironmentFile，客戶側 mTLS 全自動

::: {.callout .decided}
**✅ 定案：`/etc/guidant-agent/agent.env` 作為 systemd EnvironmentFile**

沿用現有**全環境變數**設計（`config/config.py`，agent 沒有 agent.json 這種設定檔）——**零 code 改動**。`install.sh` 互動問答三題（雲端位址／註冊 token／本機對外位址）生成該檔。

客戶側 mTLS **全自動**：agent 自我註冊流程已存在（`core/enroll.py`：產 keypair＋CSR → 拿 token 註冊 → 憑證簽回存 cert_dir → 心跳走 mTLS → 404 自動重註冊），**客戶零 openssl 操作**。雲端側 PKI 由 FR-065 產品 install.sh 已涵蓋（install.sh:1936 `AGENT_CERT_DIR`）。
:::

### D6　簽章／防竄改＝本 FR 一起做，瘦身版

::: {.callout .decided}
**✅ 定案：build 期 manifest 簽章＋啟動時驗章；不做 FR-064 runtime 全家桶**

複用 FR-064 泛用層：簽章加一個 `agent_manifest` type、`gen_integrity_manifest.py` 改常數、`sign_manifest.sh` 近零改——**複用成本僅 1–2 張小卡**。

為什麼值得做：agent 以 **root 服務跑在客戶機、握 mTLS 憑證**，是整條信任鏈最容易被摸的一端。

**不做**：FR-064 的 runtime 抽查／lockdown／unlock token 全家桶——對 agent 過重。
:::

### D7　升級／回滾＝版本目錄＋symlink 切換

::: {.callout .decided}
**✅ 定案：`/opt/guidant-agent/versions/<ver>/` ＋ `current` symlink**

升級＝解新版本目錄、切 symlink、重啟服務；**回滾＝切回舊 symlink**。SQLite 檔與 mTLS 憑證放資料目錄、**不隨版本目錄走**。agent 無 DB migration 負擔（D2 單表自建），所以不需要 FR-065 那套 pg_dump 備份模型——這條升級模型比產品端輕得多。
:::

### D8　Windows＝只出評估文件＋前提清單，不實作不承諾

::: {.callout .decided}
**✅ 定案：本 FR 對 Windows 只產出評估文件，比照 FR-065 D9**

（FR-065 的對應工作 T-4.3 於 2026-08-18 裁定跳過、評估文件未產出——agent 版評估文件從零寫，不假設有前稿可抄。）

評估三題：①指紋來源（WMI / registry）；②服務形式（Windows Service / NSSM）；③工具鏈可用性（CINC / sonar-scanner 等在 Windows 的形態）。

註：脫離 docker 後，**Docker Desktop 商業授權疑慮消失**；但 machine-id 等指紋問題在 Windows 依然存在，是評估文件的重點。
:::

### D9　指紋＝只做 Linux 原生直讀，不預抽 OS 抽象層

::: {.callout .decided}
**✅ 定案：原生化後直讀系統路徑，廢除 collect-host-id.sh；不為 Windows 預留抽象層**

直讀 `/sys/class/dmi/id/product_uuid`、`/etc/machine-id`、主網卡 MAC——`core/fingerprint.py` 已有伏筆註記（「原生封裝後直接讀系統路徑，模型不變」）。`deploy/collect-host-id.sh` workaround 隨之廢除。

[**排除：先抽 OS 抽象層**——Windows 需求未定案（D8 只出評估文件），為未定需求預先抽象是過度設計；等 Windows 真要做再抽，重構成本可控。]{.rec}
:::

## 現況接入點盤點 {#inventory sec="3" nav="接入點盤點"}

evidence-agent repo 內每個會被本案觸動的元件，逐項列現況與本案動作：

| 元件 | 現況 | 本案動作 |
|------|------|---------|
| `Dockerfile` / `rebuild.sh` | docker image build 入口 | **退役**，換成 agent 版 Nuitka build 腳本（.1） |
| `deploy/docker-compose.yml` | agent + agent-db + nginx 三服務編排 | **退役**，換 systemd unit（.3） |
| agent-db（postgres:16） | 只服務 jedi-file-upload `upload_files` 一張表 | **→ SQLite**（D2，.1） |
| nginx mTLS sidecar | 8443 TLS 終結＋轉發 | **退役**，agent 自起 TLS（D4，.3） |
| `deploy/collect-host-id.sh` | 容器讀不到宿主指紋的 workaround | **廢除**（D9） |
| `config/config.py` 版本上報 | 讀 `pyproject.toml` 取版號 | Nuitka 後檔案不存在 → **改 version bake**（同 FR-063 D6 手法，.1） |
| connector 硬編工具路徑 | `/usr/bin/*` 寫死（image 內裝好） | **配置化或 install.sh 建 symlink** 指向 bundle 工具（.2/.3） |
| `__file__` 定位三處 | `inspec.py:145` / `nmap.py:101` / `config.py:85` | **改 `resource_path()` 慣例**（FR-063 同款，.1） |
| `assets/` 資料檔 | nmap.xsl 等隨 repo | Nuitka `--include-data-dir` 帶入（.1） |
| dependency-injector | C extension，Nuitka 需特製 wheel | **複用 FR-063 私房 wheel**（`rebuild_wheels.sh`，.1） |
| jedi-common / jedi-file-upload | 私服（Nexus）套件 | **編進 binary**；build 機需可達 Nexus（.1） |
| DI wiring | **本來就是硬編靜態清單**（無動態掃描） | 免改——FR-063 的 DI 掃描雷不會踩 |
| eventlet / WeasyPrint | agent **沒有**這兩個依賴 | 免處理——FR-063 另兩大雷也不會踩 |
| 心跳排程 | `threading.Thread`（非 APScheduler） | 免改，Nuitka 相容 |

::: {.callout .ok}
**好消息：FR-063 的三大 Nuitka 雷（eventlet monkey patch / WeasyPrint 動態載入 / DI 動態掃描）agent 一個都不會踩**

agent 沒有 eventlet、沒有 WeasyPrint，DI wiring 本來就是硬編靜態清單。`.1` 的風險面遠小於當初 BE 打包。
:::

## 開放項（實作期查證，Q1–Q4） {#pending sec="4" nav="開放項"}

::: {.callout .pending}
**Q1　LibreOffice 離線化形式**

自帶 deb 組 `dpkg -i` vs portable / AppImage——兩條路都存在，實作期（.2）實測選定。判準：離線可裝、字型（fonts-noto-cjk）能一起落、體積可接受。
:::

::: {.callout .pending}
**Q2　jedi-file-upload PG 方言依賴掃描（D2 前置）**

掃 model 定義與所有查詢，確認無 jsonb / ON CONFLICT 等 PG 方言。有的話評估改寫成本再定 SQLite 落地細節。`.1` 開工先做。
:::

::: {.callout .pending}
**Q3　Nuitka 編 agent 的 EXCLUDE_COMPILE_PKGS 名單重評**

agent 依賴集合與 BE 不同（paramiko / python-gvm / zaproxy / cryptography 等），FR-063 的名單不能照抄。agent 沒有 pandas 級的編譯大戶，**冷 build 預期遠低於 BE 的 56 分鐘**。
:::

::: {.callout .pending}
**Q4　image 內 openscap-utils / sshpass 是否實際已無用**

OpenSCAP connector 已改 paramiko 直連、不用官方 `oscap-ssh` 腳本——這兩個套件可能是殘留。查證結果決定要不要跟著搬進 tarball（不搬＝包更瘦）。
:::

## 階段拆分草案 {#phases sec="5" nav="階段拆分"}

供後續 design.md 深化。建議拆 4 個子需求：

| 子需求 | 內容 | 依賴 |
|--------|------|------|
| **FR-066.1** Nuitka build 管線 | agent 版 `build_release.sh`、dependency-injector 私房 wheel 複用、version bake、`resource_path()` 改造三處 `__file__`、`assets/` include、**SQLite 化**（含 Q2 查證） | 起點 |
| **FR-066.2** tarball 打包＋工具 bundle | 全包一顆（D3 清單）、Q1/Q4 查證落地、manifest 簽章（D6：`agent_manifest` type、gen/sign 腳本改造） | 依賴 .1（build 產物是輸入） |
| **FR-066.3** install.sh＋systemd | 七步安裝結構、互動問答三題生成 agent.env（D5）、自起 TLS（D4）、upgrade/rollback symlink 模型（D7）、維運子命令（status / logs / uninstall / fingerprint） | 依賴 .2（tarball 是輸入） |
| **FR-066.4** 驗收與文件 | 乾淨機真機驗收、封閉網路（離線）驗證、客戶安裝手冊、**Windows 評估文件**（D8） | 收口，依賴 .1–.3 |

**依賴鏈**：.1 → .2 → .3 **串行**，.4 收口。與 FR-063/064/065 不同，本案各階段產物互為輸入，無平行空間。

## 交付物結構 {#deliverable sec="6" nav="交付物"}

```{.mermaid cap="圖 1 — tarball 交付物結構（D1/D3/D6 落地形狀）"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
  T["guidant-agent-&lt;ver&gt;.tar.gz<br/>~1GB+（D3 已接受）"]
  T --> A["agent/<br/>Nuitka standalone 產物<br/>自家 code 已編機器碼"]
  T --> B["tools/<br/>外部工具 bundle"]
  T --> C["install.sh<br/>七步安裝＋互動問答<br/>upgrade / rollback / 維運子命令"]
  T --> D["manifest.json ＋ manifest.sig<br/>FR-064 泛用層簽章<br/>type=agent_manifest"]
  T --> E["systemd/<br/>guidant-agent.service<br/>EnvironmentFile=/etc/guidant-agent/agent.env"]
  B --> B1["cinc-auditor（~275MB）<br/>⚖️ 不可換官方 InSpec"]
  B --> B2["sonar-scanner＋JRE（~147MB）"]
  B --> B3["LibreOffice＋fonts-noto-cjk（~400MB+）<br/>形式待 Q1 實測"]
  B --> B4["xsltproc＋nmap.xsl / git"]
```

## 端到端安裝時序 {#install-flow sec="7" nav="安裝時序"}

```{.mermaid cap="圖 2 — 客戶側一鍵安裝到心跳上線（D4/D5 全自動 mTLS）"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
    participant OP as 客戶操作者
    participant IS as install.sh
    participant SD as systemd
    participant AG as guidant-agent 服務
    participant CL as 雲端產品（FR-065 已含 PKI）
    OP->>IS: 解 tarball、執行 install.sh
    IS->>IS: 七步：前置檢查→驗 manifest 簽章→落檔 versions/&lt;ver&gt;→裝 bundle 工具→建 symlink→裝 systemd unit→啟動
    IS->>OP: 互動問答三題（雲端位址／註冊 token／本機對外位址）
    IS->>IS: 生成 /etc/guidant-agent/agent.env
    IS->>SD: systemctl enable --now guidant-agent
    SD->>AG: 啟動（啟動時驗 manifest 簽章）
    AG->>AG: 直讀宿主指紋（product_uuid / machine-id / MAC）
    AG->>CL: enroll：產 keypair＋CSR（SAN=本機位址）＋token 註冊
    CL-->>AG: CA 簽回 client 憑證＋8443 server 憑證
    AG->>AG: 憑證存 cert_dir，gunicorn/ssl 自起 8443 資料面
    loop 心跳
        AG->>CL: mTLS 心跳（404 → 自動重註冊）
    end
```

## Build 管線 {#build-flow sec="8" nav="build 管線"}

```{.mermaid cap="圖 3 — 出貨側 build 管線（FR-063/064 資產複用點標示）"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
  S["evidence-agent 源碼<br/>+ jedi-common / jedi-file-upload<br/>（build 機需可達 Nexus）"] --> W["dependency-injector<br/>私房 wheel<br/>（複用 FR-063 rebuild_wheels.sh）"]
  W --> N["Nuitka standalone 編譯<br/>version bake ＋ resource_path()<br/>--include-data-dir assets/<br/>EXCLUDE 名單重評（Q3）"]
  N --> P["組 tarball 骨架<br/>agent/ + install.sh + systemd/"]
  TB["工具 bundle 下載/整備<br/>CINC / sonar-scanner /<br/>LibreOffice（Q1）/ xsltproc / git"] --> P
  P --> M["gen_integrity_manifest.py<br/>（FR-064 改常數）逐檔 hash"]
  M --> SG["sign_manifest.sh → License Center 簽章<br/>type=agent_manifest（D6）"]
  SG --> OUT["guidant-agent-&lt;ver&gt;.tar.gz<br/>出貨"]
```

## 附註 {#notes sec="9" nav="附註"}

- 本稿為討論稿定案版，D1–D9 已拍板；下一步是 design.md 深化（含各子需求的卡片拆分）與 Notion 開卡。
- Q1–Q4 為實作期查證項，不阻擋 design.md 撰寫，但 Q2（PG 方言）是 D2 落地的前置守門。
- 本案標的 repo 是 evidence-agent，主專案（compliance-manager-be）只承載文件與簽章工具鏈的複用來源。
