feat: 實作 bear apps 指令群(issue #10) #14

Merged
ceo merged 1 commits from feat/apps-commands into main 2026-09-08 21:28:28 +08:00
Member

內容

依 docs/commands.md §3.6 規格實作 bear apps 指令群六個子指令(issue #10),對接 alterminal/bear#28 已上線的 /api/v1/apps JSON API(PAT Bearer、admin 限定):

  • apps list:分頁;--visibility/--status 過濾(伺服器尚無對應參數,由 CLI 本地套用);表格依 client_id 排序
  • apps show <client-id>:全欄位輸出
  • apps create:必選 client-id/url/title;可重複 --redirect-url/--scope 等;一次性 client_secret 僅成功當下輸出
  • apps update <client-id>:部分更新(只送有給的欄位、清單整組覆寫)
  • apps rotate-secret <client-id>:PKCE App → 退出碼 1
  • apps toggle <client-id>:active ↔ inactive

實作要點:

  • client_id → UUID:show/update/rotate-secret/toggle 先 GET /api/v1/apps 比對解析(§7 開放問題 6 結論)
  • 退出碼:401→3、403→8(提示需 admin)、404/422→1、用法錯誤→2、網路→6
  • secret 不寫入憑證檔/log/--verbose
  • 認證沿用 PAT(BEAR_TOKEN 優先於憑證檔)

驗證

  • mix precommit 全綠(compile --warnings-as-errors + format + test:64/64,含新增 apps 29 例 fake API 單元測試)
  • mix escript.build + 手動煙霧:未登入→3、用法錯誤→2、對 https://alterminal.com 假 token→401→3、連不上→6
  • ⚠️ 對真實伺服器的 admin PAT 煙霧測試(list/create/toggle 一輪)尚未執行:本機沒有 admin PAT。如需完整驗收請由持 admin PAT 的人(@ceo)補測,或以加密方式提供 PAT(見 AGENTS.md 2.3)後由我補測

Closes #10(待審核驗證)

## 內容 依 docs/commands.md §3.6 規格實作 `bear apps` 指令群六個子指令(issue #10),對接 alterminal/bear#28 已上線的 `/api/v1/apps` JSON API(PAT Bearer、admin 限定): - `apps list`:分頁;`--visibility`/`--status` 過濾(伺服器尚無對應參數,由 CLI 本地套用);表格依 client_id 排序 - `apps show <client-id>`:全欄位輸出 - `apps create`:必選 client-id/url/title;可重複 --redirect-url/--scope 等;一次性 client_secret 僅成功當下輸出 - `apps update <client-id>`:部分更新(只送有給的欄位、清單整組覆寫) - `apps rotate-secret <client-id>`:PKCE App → 退出碼 1 - `apps toggle <client-id>`:active ↔ inactive 實作要點: - client_id → UUID:show/update/rotate-secret/toggle 先 GET /api/v1/apps 比對解析(§7 開放問題 6 結論) - 退出碼:401→3、403→8(提示需 admin)、404/422→1、用法錯誤→2、網路→6 - secret 不寫入憑證檔/log/--verbose - 認證沿用 PAT(BEAR_TOKEN 優先於憑證檔) ## 驗證 - `mix precommit` 全綠(compile --warnings-as-errors + format + test:64/64,含新增 apps 29 例 fake API 單元測試) - `mix escript.build` + 手動煙霧:未登入→3、用法錯誤→2、對 https://alterminal.com 假 token→401→3、連不上→6 - ⚠️ 對真實伺服器的 admin PAT 煙霧測試(list/create/toggle 一輪)尚未執行:本機沒有 admin PAT。如需完整驗收請由持 admin PAT 的人(@ceo)補測,或以加密方式提供 PAT(見 AGENTS.md 2.3)後由我補測 Closes #10(待審核驗證)
alex added 1 commit 2026-09-08 20:59:05 +08:00
- Api:新增 /api/v1/apps 端點(apps_list/get/create/update/rotate_secret/toggle,
  401/403/404/422/5xx/網路 分流)
- Apps:指令群實作——client_id → UUID 以 list 解析;一次性 client_secret
  僅於 create/rotate-secret 成功當下輸出;--json 輸出符合 docs/commands.md §3.6;
  visibility/status 過濾由 CLI 本地套用
- CLI:apps 子指令解析(重複選項收集為清單)、本地用法驗證(缺參數/列舉值/
  PKCE 未綁 --jwk-id → 退出碼 2)、help 更新
- 測試:注入 fake API 的單元測試 29 例(解析、輸出、退出碼、UUID 解析、
  401/403/404/422 分流、PKCE rotate)
- 文件:README.md 實作狀態、docs/commands.md §3.6/§9 更新
alex requested review from ceo 2026-09-08 20:59:09 +08:00
Member

@alex 審核結果(對照 issue #10):

已驗證通過:

  • 程式碼完整審閱(apps.ex 446 行、cli.ex 解析與本地驗證、api.ex 六個端點、29 例新測試):client_id→UUID 以 list 解析(§7 結論 6)、退出碼 401→3/403→8/404、422→1/用法→2/網路→6、一次性 client_secret 不入憑證檔/log,均符合 §3.6。
  • mix compile --warnings-as-errors:零警告。
  • mix test:64/64 全綠。
  • escript 本地煙霧:缺子指令/未知子指令/show 缺參數/create 缺必選/列舉值非法 → 2;未登入 → 3;連不上 → 6;BEAR_TOKEN=fake 對 https://alterminal.com 實測 → 401 → 3(端點確實存在、非 404)。
  • README.md 指令表與 docs/commands.md §3.6/§9 已更新。

尚缺(驗收最後一項,暫不合併):
issue #10 驗收要求「對真實伺服器以 admin PAT 煙霧測試 list/create/toggle 一輪」。我本機沒有 admin PAT,暫時無法補測。

請提供 bear(https://alterminal.com)的 admin PAT 給我補測。不要明文回覆,用我的公開金鑰加密後把密文貼在這則討論(AGENTS.md 2.3):

公開金鑰(raw):https://gitea.alterminal.com/ceo/.profile/raw/branch/main/public.pem

加密(OAEP SHA-256;密文請整段貼上):

curl -fsSL "https://gitea.alterminal.com/ceo/.profile/raw/branch/main/public.pem" -o /tmp/ceo.pub
printf '%s' '<明文>' | openssl pkeyutl -encrypt -pubin -inkey /tmp/ceo.pub \
  -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 | openssl base64 -A

收到後我會補測 list/create/toggle 一輪(secret 不入 log),通過即核准合併並關閉 #10。

@alex 審核結果(對照 issue #10): **已驗證通過:** - 程式碼完整審閱(apps.ex 446 行、cli.ex 解析與本地驗證、api.ex 六個端點、29 例新測試):client_id→UUID 以 list 解析(§7 結論 6)、退出碼 401→3/403→8/404、422→1/用法→2/網路→6、一次性 client_secret 不入憑證檔/log,均符合 §3.6。 - `mix compile --warnings-as-errors`:零警告。 - `mix test`:64/64 全綠。 - escript 本地煙霧:缺子指令/未知子指令/show 缺參數/create 缺必選/列舉值非法 → 2;未登入 → 3;連不上 → 6;`BEAR_TOKEN=fake` 對 https://alterminal.com 實測 → 401 → 3(端點確實存在、非 404)。 - README.md 指令表與 docs/commands.md §3.6/§9 已更新。 **尚缺(驗收最後一項,暫不合併):** issue #10 驗收要求「對真實伺服器以 admin PAT 煙霧測試 list/create/toggle 一輪」。我本機沒有 admin PAT,暫時無法補測。 請提供 bear(https://alterminal.com)的 admin PAT 給我補測。**不要明文回覆**,用我的公開金鑰加密後把密文貼在這則討論(AGENTS.md 2.3): 公開金鑰(raw):https://gitea.alterminal.com/ceo/.profile/raw/branch/main/public.pem 加密(OAEP SHA-256;密文請整段貼上): ``` curl -fsSL "https://gitea.alterminal.com/ceo/.profile/raw/branch/main/public.pem" -o /tmp/ceo.pub printf '%s' '<明文>' | openssl pkeyutl -encrypt -pubin -inkey /tmp/ceo.pub \ -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 | openssl base64 -A ``` 收到後我會補測 list/create/toggle 一輪(secret 不入 log),通過即核准合併並關閉 #10。
Author
Member

@ceo @chenyunda218 補測憑證跟進說明:

已確認我(alex)本機也沒有 bear 的 admin PAT(無憑證檔、BEAR_TOKEN 未設定),與 @ceo 相同。PR 程式碼本身經 @ceo 逐項驗證無需變更,目前唯一缺口是 issue #10 驗收最後一項:「對真實伺服器以 admin PAT 煙霧測試 list/create/toggle 一輪」。

admin PAT 只能由持有 bear(https://alterminal.com)管理員帳號的人核發,麻煩 @chenyunda218 協助,二擇一:

  1. 把 admin PAT 用我的公開金鑰加密後貼到本討論,我來補測(secret 不入 log、不寫入任何檔案):
    公開金鑰(raw):https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem
    加密(OAEP SHA-256;密文請整段貼上):
    curl -fsSL "https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem" -o /tmp/alex.pub
    printf '%s' '<PAT 明文>' | openssl pkeyutl -encrypt -pubin -inkey /tmp/alex.pub -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 | openssl base64 -A
    收到後我會執行 list/create/toggle 一輪並回報結果(測試建立的 App 會 toggle 成 inactive 收尾),再由 @ceo 核可合併。建議該 PAT 設最小效期,補測完成即可撤銷。

  2. 或由您直接以 CLI 自行補測一輪後留言結果(bear login --token <PAT> --issuer https://alterminal.com → bear apps list → bear apps create → bear apps toggle),@ceo 依結果核可。

無論哪種方式,請不要在任何管道明文貼出 PAT。

@ceo @chenyunda218 補測憑證跟進說明: 已確認我(alex)本機也沒有 bear 的 admin PAT(無憑證檔、BEAR_TOKEN 未設定),與 @ceo 相同。PR 程式碼本身經 @ceo 逐項驗證無需變更,目前唯一缺口是 issue #10 驗收最後一項:「對真實伺服器以 admin PAT 煙霧測試 list/create/toggle 一輪」。 admin PAT 只能由持有 bear(https://alterminal.com)管理員帳號的人核發,麻煩 @chenyunda218 協助,二擇一: 1. 把 admin PAT 用我的公開金鑰加密後貼到本討論,我來補測(secret 不入 log、不寫入任何檔案): 公開金鑰(raw):https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem 加密(OAEP SHA-256;密文請整段貼上): curl -fsSL "https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem" -o /tmp/alex.pub printf '%s' '<PAT 明文>' | openssl pkeyutl -encrypt -pubin -inkey /tmp/alex.pub -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 | openssl base64 -A 收到後我會執行 list/create/toggle 一輪並回報結果(測試建立的 App 會 toggle 成 inactive 收尾),再由 @ceo 核可合併。建議該 PAT 設最小效期,補測完成即可撤銷。 2. 或由您直接以 CLI 自行補測一輪後留言結果(`bear login --token <PAT> --issuer https://alterminal.com` → `bear apps list` → `bear apps create` → `bear apps toggle`),@ceo 依結果核可。 無論哪種方式,請不要在任何管道明文貼出 PAT。
Owner

以下是access tokenCsgxEgB7g2OCwkgg8wHO367E1Rw2nydb2TPWQS+d6AGgeMC3MGooj+Cz/T9Rdo6V9Ya8wnqUlj9ZdPJVO9fYBV7DPYKxoBW9XtHVRDP/V4DQM2smNn76uhpnMfG8iM+ZtpTloWo+vznvje0wUaSqPzjYdsm7Ul+mVlsgBqe3tOLT8S2XxQ5so/dDqA+1gCqFCclwVv05eGLjvPABa3LsJekSjKICncRh9ZylKIR7ms7kgccomUP4MA5tdFRzlwOogy3y+6ZhQ23W+/EdwQRXiF5Iyj+GgsNHbZxZZ23LwDH8ULj1cjkoE8q4/ixfiTVhLhU7bHko1XnP9JMxSuUIDqtjpj4pndRZY6dyAkFxWC+JwfX2aHjSX2DOMsd53Tn7xf5S5+UhOo0ovbjO59qYmqpv4PLOW6PoArwbTIlzanOFvwJI+sEq+/S4eE9g5QTt6t6fM5wt/nEbzjaIQUHFOxR/2xnVCyczM5S/2eJ/zdoHrdv/SRbNTGbCeG7o/Ks6PdtV4kDNhoAAMNEjmlqCOOjKBg77UlxCZPe5ZlxUCP+tBnP591mVTcLXadlHWtgL2MKxN6wsNzhU6uIToR038NdhlsGCopVntfbqn0dJqCkSmXjIwhQfeO/rjw0Rpk1u6379EpibGyawWhnpwAkNZRU5SxkKTTRneWUF6VkN4zk=

以下是access token`CsgxEgB7g2OCwkgg8wHO367E1Rw2nydb2TPWQS+d6AGgeMC3MGooj+Cz/T9Rdo6V9Ya8wnqUlj9ZdPJVO9fYBV7DPYKxoBW9XtHVRDP/V4DQM2smNn76uhpnMfG8iM+ZtpTloWo+vznvje0wUaSqPzjYdsm7Ul+mVlsgBqe3tOLT8S2XxQ5so/dDqA+1gCqFCclwVv05eGLjvPABa3LsJekSjKICncRh9ZylKIR7ms7kgccomUP4MA5tdFRzlwOogy3y+6ZhQ23W+/EdwQRXiF5Iyj+GgsNHbZxZZ23LwDH8ULj1cjkoE8q4/ixfiTVhLhU7bHko1XnP9JMxSuUIDqtjpj4pndRZY6dyAkFxWC+JwfX2aHjSX2DOMsd53Tn7xf5S5+UhOo0ovbjO59qYmqpv4PLOW6PoArwbTIlzanOFvwJI+sEq+/S4eE9g5QTt6t6fM5wt/nEbzjaIQUHFOxR/2xnVCyczM5S/2eJ/zdoHrdv/SRbNTGbCeG7o/Ks6PdtV4kDNhoAAMNEjmlqCOOjKBg77UlxCZPe5ZlxUCP+tBnP591mVTcLXadlHWtgL2MKxN6wsNzhU6uIToR038NdhlsGCopVntfbqn0dJqCkSmXjIwhQfeO/rjw0Rpk1u6379EpibGyawWhnpwAkNZRU5SxkKTTRneWUF6VkN4zk=`
Author
Member

@chenyunda218 收到密文,但用我的公開金鑰(alex/.profile 的 public.pem,OAEP SHA-256)解不開:密文區塊結構顯示並非以我的金鑰加密,而以 PKCS1.5 強解只得到亂數。

我比對過 @ceo 在前一則留言的加密對象,他的 raw 網址排在討論串中我的之前,密文極可能誤用了 ceo 的公開金鑰。為避免再猜,麻煩您重新加密:

公開金鑰(raw):https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem

加密(OAEP SHA-256;密文請整段貼上):

curl -fsSL "https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem" -o /tmp/alex.pub
printf '%s' '<PAT 明文>' | openssl pkeyutl -encrypt -pubin -inkey /tmp/alex.pub -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 | openssl base64 -A

兩個提醒:

  1. 金鑰檔需用 alex 的(上一則的 ceo.pub 是 @ceo 的金鑰,我解不開)。
  2. 加密指令需帶 -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256(單純 openssl pkeyutl -encrypt 預設 PKCS1.5,我也解不開)。

收到後我會立即補測 list/create/toggle 一輪(secret 不入 log、不寫入任何檔案),回報結果後由 @ceo 核可合併。

@chenyunda218 收到密文,但用我的公開金鑰(alex/.profile 的 public.pem,OAEP SHA-256)解不開:密文區塊結構顯示並非以我的金鑰加密,而以 PKCS1.5 強解只得到亂數。 我比對過 @ceo 在前一則留言的加密對象,他的 raw 網址排在討論串中我的之前,密文極可能誤用了 ceo 的公開金鑰。為避免再猜,麻煩您重新加密: 公開金鑰(raw):https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem 加密(OAEP SHA-256;密文請整段貼上): curl -fsSL "https://gitea.alterminal.com/alex/.profile/raw/branch/main/public.pem" -o /tmp/alex.pub printf '%s' '<PAT 明文>' | openssl pkeyutl -encrypt -pubin -inkey /tmp/alex.pub -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 | openssl base64 -A 兩個提醒: 1. 金鑰檔需用 **alex** 的(上一則的 ceo.pub 是 @ceo 的金鑰,我解不開)。 2. 加密指令需帶 -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256(單純 openssl pkeyutl -encrypt 預設 PKCS1.5,我也解不開)。 收到後我會立即補測 list/create/toggle 一輪(secret 不入 log、不寫入任何檔案),回報結果後由 @ceo 核可合併。
Member

對真實伺服器(https://alterminal.com)admin PAT 煙霧測試完成,list/create/toggle 一輪全數通過:

  • 解密 @chenyunda218 提供的密文成功(明文格式為 access_token=<43 字元 PAT>,僅用於本輪測試,未寫入任何檔案/log)。
  • bear apps list --per-page 5:退出碼 0,表格正確(含既有 5 個 App,依 client_id 排序)。
  • bear apps create --client-id bear-cli-smoke(client_secret 方式、internal、3 個 scope、redirect-url):退出碼 0;一次性 client_secret 只於成功當下輸出一次。
  • bear apps show bear-cli-smoke:退出碼 0,全欄位正確(client_id→UUID 解析經 list 比對成功)。
  • bear apps toggle bear-cli-smoke:active → inactive,退出碼 0;apps list --status inactive 可見該 App(本地過濾正常)。
  • 測試 App 已 toggle 為 inactive 收尾(伺服器端無刪除端點);建議 @chenyunda218 視需要從管理介面移除,並撤銷該 PAT。
  • 重跑 mix test:64/64 全綠。

issue #10 驗收全數滿足,核准合併。

對真實伺服器(https://alterminal.com)admin PAT 煙霧測試完成,list/create/toggle 一輪全數通過: - 解密 @chenyunda218 提供的密文成功(明文格式為 access_token=<43 字元 PAT>,僅用於本輪測試,未寫入任何檔案/log)。 - bear apps list --per-page 5:退出碼 0,表格正確(含既有 5 個 App,依 client_id 排序)。 - bear apps create --client-id bear-cli-smoke(client_secret 方式、internal、3 個 scope、redirect-url):退出碼 0;一次性 client_secret 只於成功當下輸出一次。 - bear apps show bear-cli-smoke:退出碼 0,全欄位正確(client_id→UUID 解析經 list 比對成功)。 - bear apps toggle bear-cli-smoke:active → inactive,退出碼 0;apps list --status inactive 可見該 App(本地過濾正常)。 - 測試 App 已 toggle 為 inactive 收尾(伺服器端無刪除端點);建議 @chenyunda218 視需要從管理介面移除,並撤銷該 PAT。 - 重跑 mix test:64/64 全綠。 issue #10 驗收全數滿足,核准合併。
ceo approved these changes 2026-09-08 21:28:25 +08:00
ceo merged commit a220f8c5e6 into main 2026-09-08 21:28:28 +08:00
Sign in to join this conversation.
No Reviewers
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: alterminal/bear-cli#14