feat: 實作管理端指令群 jwks/accounts/audit-logs(issue #12)
- docs/commands.md 新增 §3.8 jwks、§3.9 accounts、§3.10 audit-logs 規格 - Api 新增 jwks/accounts/audit-logs 端點(共用 api_request) - 新增 Jwks/Accounts/AuditLogs/Admin 模組;CLI 接線三個指令群 - 403 → 退出碼 8 提示需 admin;一次性密碼只在成功當下輸出 - 測試 100 例全綠(fake API 注入,比照 cli_test.exs)
This commit is contained in:
+170
-1
@@ -513,6 +513,162 @@ TOTP 兩因子管理(WebAuthn/passkey 不在範圍)。
|
||||
|
||||
---
|
||||
|
||||
### 3.8 `bear jwks`:簽章金鑰管理指令群(admin,已實作)
|
||||
|
||||
> 依賴:bear 伺服器端 **JWK 管理 JSON API**(alterminal/bear#36/PR #46,資源前綴 `/api/v1/jwks`,PAT Bearer 認證、admin 限定)。API 已上線,本節指令群已實作(issue #12)。
|
||||
|
||||
|
||||
比照 `apps` 的「資源群組」結構。金鑰材質(`key_data`)**永不經 CLI 顯示**(API 端即不序列化;公開 JWK 走 `/.well-known/jwks.json`),本群組僅管理公開中繼資料。
|
||||
|
||||
|
||||
```
|
||||
bear jwks list [--json]
|
||||
bear jwks show <kid> [--json]
|
||||
bear jwks create --kid KID [--alg ALG] [--json]
|
||||
bear jwks toggle <kid> [--json]
|
||||
```
|
||||
|
||||
**認證與授權(群組共通)**:一律使用既有 PAT 憑證(`bear login --token` 或 `BEAR_TOKEN` 環境變數)作為 Bearer,僅限 admin 角色。
|
||||
`401`(token 無效)→ 退出碼 `3`,提示重新 `bear login`;`403`(非 admin)→ 退出碼 `8`,提示此操作需 admin 權限,不重試。
|
||||
|
||||
|
||||
**識別與退出碼**:金鑰一律以 `kid`(人類可讀)識別;API 路徑參數為 UUID,由 CLI 先以 list 比對解析。退出碼同 §3.6 群組共通表(0/1/2/3/6/8)。
|
||||
|
||||
|
||||
#### 3.8.1 `bear jwks list`
|
||||
|
||||
**行為**:`GET /api/v1/jwks`(Bearer PAT),列出所有金鑰(active 與 inactive),最新在前;人類可讀輸出為表格(ID 前 8 碼、KID、KTY、ALG、ACTIVE、CREATED AT)。
|
||||
|
||||
```
|
||||
ID KID KTY ALG ACTIVE CREATED AT
|
||||
0192cccc sig-2026-01 RSA RS256 active 2026-09-09T00:00:00Z
|
||||
0192cccc sig-2025-12 EC ES256 inactive 2025-12-01T00:00:00Z
|
||||
```
|
||||
|
||||
|
||||
**`--json` 輸出範例**:`{"ok": true, "jwks": [{…}]}`(僅公開欄位,無 `key_data`)。
|
||||
|
||||
|
||||
#### 3.8.2 `bear jwks show <kid>`
|
||||
|
||||
**行為**:`GET /api/v1/jwks/{id}`(以 kid 解析),印出公開欄位(id、kid、kty、alg、use、active、created_at);找不到 kid → 退出碼 `1`。
|
||||
|
||||
#### 3.8.3 `bear jwks create --kid KID [--alg ALG]`
|
||||
|
||||
| 選項 | 預設 | 說明 |
|
||||
|------|------|------|
|
||||
| `--kid` | (必填) | 金鑰識別碼 |
|
||||
| `--alg` | `RS256` | `RS256`/`RS384`/`RS512`/`ES256`/`ES384`/`ES512` |
|
||||
|
||||
**行為**:`POST /api/v1/jwks`(body 為 kid 與 alg;金鑰由伺服器產生)。成功印出 `JWK 已建立:<kid>(<alg>/active)`。`alg` 非法 → 退出碼 `2`(本地檢查);kid 重複等 422 → 退出碼 `1` 逐欄位列錯。
|
||||
|
||||
**`--json` 輸出範例**:`{"ok": true, "jwk": {…}}`
|
||||
|
||||
#### 3.8.4 `bear jwks toggle <kid>`
|
||||
|
||||
**行為**:`POST /api/v1/jwks/{id}/toggle`(以 kid 解析),切換 `active ⇄ inactive`;成功印出如 `sig-2026-01:active → inactive`。
|
||||
**`--json` 輸出範例**:`{"ok": true, "jwk": {"id": "…", "kid": "…", "active": false}}`
|
||||
|
||||
---
|
||||
|
||||
### 3.9 `bear accounts`:帳號管理指令群(admin,已實作)
|
||||
|
||||
> 依賵:bear 伺服器端 **帳號管理 JSON API**(alterminal/bear#36/PR #46,資源前綴 `/api/v1/accounts`,PAT Bearer 認證、admin 限定)。API 已上線,本節指令群已實作(issue #12)。
|
||||
|
||||
帳號 JSON 不含機密欄位(hash_password、totp_secret、recovery codes;API 端保證),CLI 亦不顯示。敏感規則與伺服器端一致:不可移除自己的 admin 角色(403)、不可刪除自己(403)。
|
||||
|
||||
```
|
||||
bear accounts list [--page N] [--per-page N] [--json]
|
||||
bear accounts show <email> [--json]
|
||||
bear accounts create --email EMAIL [--role user|admin] [--generate-password] [--json]
|
||||
bear accounts update <email> --role user|admin [--json]
|
||||
bear accounts set-password <email> [--generate-password] [--json]
|
||||
bear accounts delete <email> [--json]
|
||||
```
|
||||
|
||||
**認證與授權(群組共通)**:同 §3.8(PAT Bearer、僅限 admin;401 → 3;403 → 8)。退出碼同 §3.6 群組共通表。
|
||||
|
||||
**識別與密碼**:帳號一律以 `email` 識別;API 路徑參數為 UUID,由 CLI 先以 list 分頁比對解析。密碼不進命令列(避免 shell history 與 ps):交互提示輸入(不回顧)或 `--generate-password` 由 CLI 產生。初始/新密碼只在成功當下一次性輸出。
|
||||
|
||||
#### 3.9.1 `bear accounts list`
|
||||
|
||||
**行為**:`GET /api/v1/accounts`(Bearer PAT,分頁,最新在前);人類可讀輸出為表格。
|
||||
|
||||
```
|
||||
EMAIL ROLE TOTP CREATED AT
|
||||
admin@example.com admin on 2026-01-01T00:00:00Z
|
||||
alice@example.com user off 2026-02-01T00:00:00Z
|
||||
```
|
||||
|
||||
**`--json` 輸出範例**:`{"ok": true, "page": 1, "per_page": 20, "total": 2, "accounts": […]}`
|
||||
|
||||
#### 3.9.2 `bear accounts show <email>`
|
||||
|
||||
**行為**:`GET /api/v1/accounts/{id}`(以 email 解析),印出公開欄位(id、email、role、totp_enabled、created_at、updated_at);找不到 → 退出碼 `1`。
|
||||
|
||||
#### 3.9.3 `bear accounts create`
|
||||
|
||||
| 選項 | 預設 | 說明 |
|
||||
|------|------|------|
|
||||
| `--email` | (必填) | 帳號 email(唯一) |
|
||||
| `--role` | `user` | `user` 或 `admin` |
|
||||
| `--generate-password` | 互動輸入 | 由 CLI 產生 16 字元隨機密碼(含字母與數字) |
|
||||
|
||||
**行為**:`POST /api/v1/accounts`(免信箱驗證;密碼以明文放入 `hash_password`,伺服器端驗強度後雜湏)。成功印出帳號摘要與一次性密碼區塊:
|
||||
|
||||
```
|
||||
帳號已建立:new@example.com(user)
|
||||
初始密碼(只顯示這一次,請立即保存並轉交當事人):
|
||||
xK7mP9qR2sL4wY6z
|
||||
```
|
||||
|
||||
**`--json` 輸出範例**:`{"ok": true, "account": {…}, "initial_password": "…"}`(密碼只出現這一次)。
|
||||
|
||||
#### 3.9.4 `bear accounts update <email> --role user|admin`
|
||||
|
||||
**行為**:`PUT /api/v1/accounts/{id}`(body 為 role)。成功印出 `alice@example.com:角色 → admin`。伺服器拒絕自降 admin(403)→ 退出碼 `8`。`--role` 罪給或非法 → 退出碼 `2`。
|
||||
|
||||
#### 3.9.5 `bear accounts set-password <email>`
|
||||
|
||||
**行為**:`PUT /api/v1/accounts/{id}/password`(管理員設新密碼,免舊密碼)。密碼來源同 create;非 TTY 且未給 `--generate-password` → 退出碼 `2`,提示加 `--generate-password`。成功後一次性顯示新密碼(同 create 提示)。
|
||||
|
||||
#### 3.9.6 `bear accounts delete <email>`
|
||||
|
||||
**行為**:`DELETE /api/v1/accounts/{id}`(管理端硬刪除,免驗證碼)。成功印出 `已刪除帳號:<email>`;伺服器拒絕自刪(403)→ 退出碼 `8`。
|
||||
|
||||
**`--json` 輸出範例**:`{"ok": true, "email": "alice@example.com", "deleted": true}`
|
||||
|
||||
---
|
||||
|
||||
### 3.10 `bear audit-logs`:稽核日誌指令群(admin,已實作)
|
||||
|
||||
> 依賵:bear 伺服器端 **稽核日誌 JSON API**(alterminal/bear#36/PR #46,`/api/v1/audit-logs`,PAT Bearer 認證、admin 限定)。API 已上線,本節指令群已實作(issue #12)。
|
||||
|
||||
```
|
||||
bear audit-logs list [--page N] [--per-page N] [--category CATEGORY] [--json]
|
||||
```
|
||||
|
||||
**認證與授權**:同 §3.8(PAT Bearer、僅限 admin;401 → 3;403 → 8)。
|
||||
|
||||
#### 3.10.1 `bear audit-logs list`
|
||||
|
||||
| 選項 | 預設 | 說明 |
|
||||
|------|------|------|
|
||||
| `--page` | `1` | 分頁頁碼 |
|
||||
| `--per-page` | `50` | 每頁筆數(伺服器上限 200) |
|
||||
| `--category` | 全部 | 過濾類別(伺服器端支援;如 `account`、`jwk`) |
|
||||
|
||||
**行為**:`GET /api/v1/audit-logs`(Bearer PAT,最新在前);回應附 `emails` 對照(account/actor id → email),人類可讀輸出以 email 呈現、無對照時顯示 id 前 8 碼:
|
||||
|
||||
```
|
||||
TIME CATEGORY EVENT ACTOR ACCOUNT
|
||||
2026-09-09T01:00:00Z account account_created_by_admin admin@example.com alice@example.com
|
||||
```
|
||||
|
||||
**`--json` 輸出範例**:`{"ok": true, "page": 1, "per_page": 50, "total": 1, "total_pages": 1, "emails": {…}, "entries": […]}`
|
||||
|
||||
---
|
||||
|
||||
## 4. 退出碼總表
|
||||
|
||||
| 碼 | 語意 |
|
||||
@@ -525,7 +681,7 @@ TOTP 兩因子管理(WebAuthn/passkey 不在範圍)。
|
||||
| `5` | 授權被拒絕(access_denied) |
|
||||
| `6` | 網路/伺服器錯誤 |
|
||||
| `7` | 設定檔/憑證檔格式損毀 |
|
||||
| `8` | 權限不足(HTTP 403;App 管理操作僅限 admin) |
|
||||
| `8` | 權限不足(HTTP 403;管理端操作僅限 admin:apps/jwks/accounts/audit-logs) |
|
||||
|
||||
---
|
||||
|
||||
@@ -549,6 +705,7 @@ TOTP 兩因子管理(WebAuthn/passkey 不在範圍)。
|
||||
- 所有診斷訊息走 stderr;`--json` 模式將錯誤以 `{"ok": false, "error": "...", "code": N}` 輸出。
|
||||
- token、user_code、device_code 一律不入 log、不入 stdout(除 `bear token` 之目的外)、不入版本庫。
|
||||
- `client_secret`(App 管理)僅於 `apps create`/`apps rotate-secret` 成功當下一次性輸出;`403` 顯示「此操作需 admin 權限」並以退出碼 `8` 結束,不重試。
|
||||
- 管理端指令群(jwks/accounts/audit-logs)同樣 admin 限定;帳號的初始/新密碼僅於 `accounts create`/`accounts set-password` 成功當下一次性輸出;密碼不進命令列(互動輸入不回顧,或 `--generate-password`);JWK 的 `key_data` 永不經顯示。
|
||||
- 個人自助的敏感輸入(密碼、email/MFA 驗證碼)一律互動提示、不回顧、不接受命令列參數;一次性明文(`tokens create` 的 PAT、`mfa` 的 recovery codes)僅於成功當下輸出(見 §3.7)。
|
||||
- 網路層一律使用 `Req`,遵循 bear 倉庫 HTTP 客戶端慣例。
|
||||
|
||||
@@ -596,6 +753,17 @@ TOTP 兩因子管理(WebAuthn/passkey 不在範圍)。
|
||||
| `mfa setup` | `POST /api/v1/profile/mfa/setup`(先無 code 取 secret,再帶 code 確認) |
|
||||
| `mfa disable` | `POST /api/v1/profile/mfa/disable` |
|
||||
| `mfa recovery-codes` | `POST /api/v1/profile/mfa/recovery-codes` |
|
||||
| `jwks list` | `GET /api/v1/jwks` |
|
||||
| `jwks show` | `GET /api/v1/jwks/{id}` |
|
||||
| `jwks create` | `POST /api/v1/jwks` |
|
||||
| `jwks toggle` | `POST /api/v1/jwks/{id}/toggle` |
|
||||
| `accounts list` | `GET /api/v1/accounts` |
|
||||
| `accounts show` | `GET /api/v1/accounts/{id}` |
|
||||
| `accounts create` | `POST /api/v1/accounts` |
|
||||
| `accounts update` | `PUT /api/v1/accounts/{id}` |
|
||||
| `accounts set-password` | `PUT /api/v1/accounts/{id}/password` |
|
||||
| `accounts delete` | `DELETE /api/v1/accounts/{id}` |
|
||||
| `audit-logs list` | `GET /api/v1/audit-logs` |
|
||||
|
||||
> `apps` 群組依賴 alterminal/bear#28 的 App 管理 JSON API(PAT Bearer、admin 限定);`profile` 系列依賴 alterminal/bear#35 的個人自助 JSON API(PAT Bearer、任何有效帳號)。
|
||||
|
||||
@@ -613,6 +781,7 @@ TOTP 兩因子管理(WebAuthn/passkey 不在範圍)。
|
||||
| `logout` | `POST /revoke`(撤銷 refresh token) | 僅清除本機憑證;PAT 需至網頁 `/profile/tokens` 撤銷 |
|
||||
| `status` | 顯示 access token 剩餘秒數 | 純本機判定:顯示模式(PAT/BEAR_TOKEN 環境變數)與 issuer |
|
||||
| `apps` | P3 暫緩 | ✅ 已實作(issue #10):`list`/`show`/`create`/`update`/`rotate-secret`/`toggle`,對接 alterminal/bear#28 的 `/api/v1/apps` JSON API(PAT Bearer、admin 限定)。`client_id` → UUID 由 CLI 以 list 解析;一次性 `client_secret` 僅於 create/rotate-secret 成功當下輸出 |
|
||||
| `jwks`/`accounts`/`audit-logs` | P3 暫緩 | ✔ 已實作(issue #12):對接 alterminal/bear#46 的管理端 JSON API(PAT Bearer、admin 限定);規格見 §3.8–§3.10 |
|
||||
| `profile`/`password`/`email`/`sessions`/`tokens`/`mfa` | P3 暫緩 | 未實作;個人自助指令規格見 #11(§3.7),伺服器端 API 見 alterminal/bear#35 |
|
||||
|
||||
退出碼差異:`login`/`whoami` 的 token 無效(401)依 §3.1 為 `3`(本節實作一致)。
|
||||
|
||||
Reference in New Issue
Block a user