管理逐操作存取
誰: 部門管理者(服務帳號的角色是 0,所以會先被角色門檻以 403 Insufficient permissions. 拒絕;見驗證與角色)。這裡所有操作的前提: Worker 已部署且為 active,且上線 release 以 builder 政策 department-worker-project-v2.8 或更新版本建置 — 否則回 409 Department Worker must be deployed and active 或 409 {"code":"operation_settings_require_supported_release","message":"Re-upload and deploy this Worker with the operation-settings runtime policy before changing per-operation access"}。路徑相對於 /private/module/edge-workers;每個成功回應都是 Cache-Control: no-store。概念:逐操作存取。
讀取
GET /worker/operation-settings
GET /worker/operation-settings?version_id=<version-uuid>
→ 200 {
"state": "reconciled",
"version_id": "<version-uuid>",
"revision": 3,
"default_service_account_id": null,
"default_service_account": null,
"operations": [
{ "operation_id": "createOrder", "method": "POST", "path": "/orders",
"access": { "mode": "api_key_and_ip", "ip_allowlist": ["203.0.113.0/24"] },
"service_account_id": null,
"effective_access": { "mode": "api_key_and_ip", "ip_allowlist_configured": true,
"api_key_configured": true, "source": "operation" },
"effective_service_account": null },
{ "operation_id": "getStatus", "method": "GET", "path": "/status",
"access": { "mode": "public", "ip_allowlist": [] },
"service_account_id": null,
"effective_access": { "mode": "public", "ip_allowlist_configured": false,
"api_key_configured": false, "source": "operation" },
"effective_service_account": null },
{ "operation_id": "listOrders", "method": "GET", "path": "/orders",
"access": null,
"service_account_id": null,
"effective_access": { "mode": "teamsync_internal", "ip_allowlist_configured": false,
"api_key_configured": false, "source": "worker" },
"effective_service_account": null }
]
}revision是PUT的 CAS 權杖。從未儲存過設定的 Worker 會讀到state: "legacy"、revision: 0,且每個操作都是access: null。effective_access依目前的 Worker 層級政策計算,所以/worker/access-policy改變時它也會跟著變。?version_id=讓你在部署前預覽另一個 release:它必須是這個 Worker 的ready或deployed版本(否則 404Department Worker not found),且以 v2.8 或更新版本建置(否則 409{"code":"operation_settings_require_supported_release","message":"The selected release does not support operation settings"})。該 release 尚無設定表時,回應呈現不帶operation_settings部署時會帶過去的內容 — 目標中也存在之操作的上線列,加上上線中的預設服務帳號 — 且仍回報state: "pending"、revision: 0。
替換設定
PUT /worker/operation-settings
{
"base_revision": 3,
"operations": [
{ "operation_id": "createOrder",
"access": { "mode": "api_key_and_ip", "ip_allowlist": ["203.0.113.0/24"] } },
{ "operation_id": "getStatus", "access": { "mode": "public" } },
{ "operation_id": "listOrders", "access": null }
]
}
→ 200 { "state": "reconciled", "revision": 4, "operations": [ … ], … }- 整份清單替換:上線 manifest 的每個操作都要恰好列出一次。少列或多列 → 422
[{"loc":["body","operations"],"msg":"operation settings must list every manifest operation","type":"operation_settings_incomplete"}]。要繼承 Worker 層級政策就用"access": null。 base_revision必須等於目前的revision(legacy或pending的表為 0);否則 409Operation-settings revision is stale— 重新 GET 後再套用。成功時回傳的revision=base_revision + 1。- 既有的操作金鑰與金鑰擁有權一律留在各自的操作 id 上,不受請求內容影響。
- 請求也帶出站身分欄位
operations[].service_account_id與default_service_account_id(省略 = 保留目前綁定,null= 清除);見服務帳號。從不送這兩個欄位的用戶端永遠不會改動綁定。 - 狀態為
pending的表在公開通道上失敗即關閉;以base_revision: 0送出PUT即可讓它 reconciled。只存在其他 release generation 的金鑰不會被帶進來,所以曾擁有金鑰的操作需要新金鑰。 - Schema 驗證(422)拒絕重複的 id(
operation settings must contain unique operation ids)、總數超過 256 條的 CIDR(operation settings contain too many IP allowlist entries)、沒有 CIDR 的ip_allowlist/api_key_and_ip覆寫(the selected access mode requires at least one CIDR)、其他模式帶 CIDR(IP allowlist is supported only by IP-restricted modes),以及重複的 CIDR(IP allowlist entries must be unique)。未知欄位也會被拒絕。
輪替操作金鑰
POST /worker/operation-settings/createOrder/api-key
→ 200 {
"api_key": "tsw_…",
"header_name": "X-TeamSync-Worker-Key",
"operation_id": "createOrder",
"access": { "mode": "api_key_and_ip", "ip_allowlist_configured": true,
"api_key_configured": true, "source": "operation" }
}- 沒有請求本體:伺服器自行讀取目前的 revision。明文(
tsw_+ 43 個字元)只出現一次 — 請立即保存;任何回應都不會顯示操作金鑰的後四碼提示。 - 操作必須在上線 manifest 中(否則 404
Department Worker not found),且上線中的表為reconciled(否則 409{"code":"operation_settings_pending","message":"Write operation settings before assigning an operation API key"}—legacy的 Worker 要先PUT一次設定)。 - 輪替會立即取代先前的金鑰、把 revision 推進 1(下一次
PUT前請重新 GET),且不改變模式。呼叫者在公開 URL 上以X-TeamSync-Worker-Key送出金鑰;只有在操作的有效模式為api_key或api_key_and_ip時才會檢查。
撤銷操作金鑰
DELETE /worker/operation-settings/createOrder/api-key
→ 200 {
"operation_id": "createOrder",
"revoked": true,
"access": { "mode": "api_key_and_ip", "ip_allowlist_configured": true,
"api_key_configured": false, "source": "operation" }
}- 沒有請求本體。Worker 為
paused時、以及部署進行中也可以撤銷:操作可以在上線 manifest 或暫存的目標 manifest 中(否則 404);若上線 release 在呼叫期間改變,改為撤銷暫存的 release。 - 不是
reconciled→ 409Operation settings are pending。 - 金鑰會在每個已儲存的 release generation 中清除。重複呼叫回
revoked: false,且不推進 revision(稽核為operation_settings.api_key.revoke_noop)。 - 擁有權是永久的:只要該操作的有效模式是金鑰模式,在你輪替出新金鑰之前,它不接受任何金鑰(絕不退回 Worker 層級金鑰)。
帶操作設定部署
POST /worker/deployments 接受選用的 operation_settings 區塊,形狀與 PUT 本體相同。票證機制、輪詢與其他部署錯誤見部署與輪詢。
POST /worker/deployments
{
"version_id": "<version-uuid>",
"base_revision": 7,
"operation_settings": {
"base_revision": 4,
"operations": [
{ "operation_id": "cancelOrder", "access": { "mode": "api_key" } }
]
}
}
→ 202 { …EdgeWorkerDeploymentStatus ticket… }- 兩個不同的 revision:外層
base_revision是 Worker 的latest_revision(同部署與輪詢);operation_settings.base_revision是上線中操作設定表的revision(否則 409Operation-settings revision is stale)。設定會在目標 release 開始服務之前先暫存。 - 清單可以只列一部分:列出的操作覆寫;兩個 release 都有且未列出的操作保留完整的上線列(存取、金鑰、金鑰擁有權、綁定);目標 manifest 沒有的操作會被丟棄。列出目標 manifest 沒有的 id → 422
[{"loc":["body","operations"],"msg":"operation_id is not present in the target release manifest","type":"operation_not_found"}]。 - 不帶
operation_settings時,上線中的表會依同樣規則自動帶過去。 - 暫存的表從自己的 revision 起算,所以部署完成後、下一次
PUT之前要重新 GET。範例中的cancelOrder還沒有金鑰:部署後請為它輪替一把,否則它的公開呼叫會得到 401。 - 完全相同的重試(同樣的
version_id、base_revision與設定)回傳既有票證;同一組值但設定不同 → 409{"code":"operation_settings_dedupe_mismatch","message":"Deployment settings differ from the existing ticket"}。
| 狀態碼 | detail | 何時 |
|---|---|---|
| 409 | {"code":"operation_settings_require_supported_release","message":"Deploy the Worker once before adding operation settings"} | 送了設定,但沒有上線中的 active release |
| 409 | {"code":"operation_settings_require_supported_release","message":"The live release does not support operation settings"} | 送了設定,上線 release 早於 v2.8 |
| 409 | {"code":"operation_settings_require_supported_release","message":"The target release does not support operation settings"} | 上線 release 為 v2.8 或更新、目標早於 v2.8 — 即使不帶設定也會拒絕 |
| 409 | {"code":"operation_settings_pending","message":"Reconcile the live release before deploying settings"} | 上線中的表為 pending |
| 503 | {"code":"operation_settings_live_read_unavailable","message":"Retry the deployment after the live settings read recovers"} | 連續兩次讀不到上線設定 |
設定鎖
PUT、輪替、撤銷與每個新的部署請求(既有票證的完全相同重試除外)都會取得同一把部門層級的鎖(600 秒後過期);部署在暫存設定並寫入票證期間持有它。
- 鎖被占用 → 409
{"code":"deployment_in_progress","message":"Another Worker settings mutation or deployment is in progress"}。稍後重試。 - 鎖的儲存無法連線 → 503
Operation-settings mutation lock is unavailable。 - 另外,只要有其他部署票證處於
pending、leased或uncertain,PUT、輪替與新的部署都會被拒絕:409{"code":"deployment_in_progress","message":"Operation settings cannot change during a deployment"}。請等票證結束(撤銷不受此限)。
錯誤
detail 可能是字串或 {code, message} 物件;後端生成的 OpenAPI 把其中多數標為單純字串,所以兩種都要解析。「全部」指四個 /worker/operation-settings 路由。自後端 5.22.0 起,變更也可能被拒絕並回 409 worker_serving_target_unavailable(後端無法驗證是哪個位置在服務該 Worker)。平台維運者搬移該 Worker 期間,會回 503 Department Worker control change is unavailable;但在搬移的短暫暫停期間,會先讀取該 Worker 狀態的呼叫改回該路由慣用的修訂版過期 409(錯誤、搬移 Worker)。
| 狀態碼 | detail | 路由 |
|---|---|---|
| 404 | Department Worker not found | 全部 — 沒有 Worker、version_id 不是 ready/deployed 版本、operation_id 不在 manifest 中 |
| 409 | Department Worker must be deployed and active | 全部(撤銷也接受 paused) |
| 409 | operation_settings_require_supported_release(訊息見上) | 全部 |
| 409 | deployment_in_progress(兩種訊息見上) | PUT、輪替、撤銷(僅鎖)、部署 |
| 409 | Operation-settings revision is stale | PUT、輪替、撤銷、部署 |
| 409 | {"code":"operation_settings_pending","message":"Write operation settings before assigning an operation API key"} | 輪替 |
| 409 | Operation settings are pending | 撤銷 |
| 413 | Worker operation settings request exceeds limit(本體超過 65 536 B) | PUT、輪替、撤銷 |
| 422 | operation_settings_incomplete(僅 PUT)、operation_not_found(僅部署)、上述 schema 訊息、service_account_not_found | PUT、部署 |
| 503 | {"code":"worker_release_unavailable","message":"Worker release changed; retry this request"} | 全部 — 呼叫期間已部署的 release 改變了 |
| 503 | Department Worker operation settings are unavailable | 全部 — 讀寫失敗,或儲存的 revision 不是 base_revision + 1 |
| 503 | Department Worker operation key is unavailable | 輪替 — 儲存的金鑰回讀不符 |
| 503 | Department Worker control change is unavailable | PUT、輪替、撤銷 — 無法寫入控制面稽核意圖 |
| 503 | Operation-settings mutation lock is unavailable | PUT、輪替、撤銷、部署 |
| 503 | Deployed department Worker contract is unavailable | 全部 — 無法讀取已部署的 manifest |
PUT 與部署上的服務帳號綁定錯誤(service_account_not_found、service_account_credentials_require_supported_release、api_base_unconfigured、憑證遞送)說明見服務帳號。
稽核
每次變更都走耐久的控制面稽核 outbox,最終成為回執背書的稽核事實:operation_settings.replaced、operation_settings.staged(部署)、operation_settings.api_key.rotated、operation_settings.api_key.revoked / operation_settings.api_key.revoke_noop — 只記摘要,絕不記金鑰內容。見稽核。