Skip to Content

client_access line

client_access 是 chatroom、department 與 company 三種 scope 上每張 table 的 singleton resource。它不使用 authored ref,而是固定成 {table}.client_access;passphrase 是 write-only secret,其他設定仍可 plan 與 state 管理。對應的 REST clientAccess 介面使用同一個三-scope matrix。

JSONL Line

{"kind":"client_access","table":"orders","spec":{"passphrase_enabled":true,"passphrase":"correct-horse-battery-staple","passphrase_permissions":{"can_read":"all","can_insert":false,"can_edit":"none"}}}

欄位契約

頂層 IacClientAccessLine 只接受三個欄位,且全部必填:kind: "client_access"、table ref、typed spec。沒有 ref、renamed_from 或 state。

IacClientAccessSpec:

欄位必填精確契約
passphrase_enabled是Pydantic boolean;JSON boolean 最清楚,"false" 等可辨識 token 會被 coercion
passphrase否string 或 null。新的明文 passphrase 為 1–72 個 UTF-8 位元組(因此最多 72 個字元);它是唯寫的,並依送出的原樣做 bcrypt 雜湊,不會修剪空白或做 Unicode 正規化。"<REDACTED>" 表示保留 live hash;省略或送 null 則不輪替
passphrase_permissions否DefaultPermissionsPayload object/null

passphrase_permissions 支援 can_read(預設 all)、can_insert(預設 false)、can_edit(預設 none)、read_filter、edit_filter;access level 集合是 none|own|all|filtered。省略整個 permissions 物件、且該表尚無 client-access 權限時,apply 會寫入 {"can_read": "all", "can_insert": false, "can_edit": "none"};已存在的權限則保留。Client-access spec 的未知欄位會以 extra_forbidden 拒絕。

Ref 與身分規則

table: "orders" 產生固定 identity orders.client_access。它加入同一 per-table child-ref namespace,因此若 column、rule、trigger、view 或 public_read 的 authored ref 也叫 client_access,會碰撞:

duplicate ref 'orders.client_access' (already declared in this document)

passphrase_permissions 直接重用 REST DefaultPermissionsPayload。其中 row-policy predicate 的 column 是 live col_<hex> internal key,不是 IaC column ref;client_access path 不做 grant line 的 ref translation。Filtered client access 因此必須以目的 scope 的 internal keys 重新核對,不能把來源 scope 的 policy 當成可攜 ref。Passphrase 本身不是 ref,也不應被拿來形成 identity。

生命週期與規劃

Client access 沒有 state 欄位,因此也沒有 absent/delete lifecycle——這一點它只和 header 與 record 相同,其他 kind 都不是這樣。要停用 passphrase access,宣告 passphrase_enabled: false。初次設定提供真實 passphrase。Export 只有在該表存有 passphrase hash 時才輸出 "<REDACTED>",否則不輸出 passphrase。Apply "<REDACTED>" 會保留既有 hash;沒有 hash 時則會失敗:若該行在 live 資料表上啟用 passphrase access,plan 會回報 validate 錯誤;其他情況——passphrase_enabled: false,或資料表由本文件建立——則由 apply 讓該行在 200 內失敗:

passphrase_enabled with '<REDACTED>' requires an existing live passphrase hash

Passphrase 的變更在 plan 中顯示為 {"field": "passphrase", "from": "<REDACTED>", "to": "<REDACTED>"},plan 從不回傳 plaintext 或 hash。新的 plaintext 會與保存的 hash 比對,所以重送目前的 passphrase 會規劃為 noop。Spec omitted fields 不接管 live value;state 也會移除 secret。

72 位元組的上限就是 bcrypt 的輸入上限,現在與 REST client-access payload 完全一致。以前最多 256 個字元的 passphrase 也能通過 parse,但 bcrypt 無法使用超過 72 個位元組。空字串、超過 72 個字元,或超過 72 個 UTF-8 位元組——30 個中日韓文字的 passphrase 就已經是 90 個位元組——都是 parse 錯誤;精確訊息見錯誤目錄。

驗證錯誤

缺少 spec:

[{"type": "missing", "loc": ["client_access", "spec"], "msg": "Field required", "url": "https://errors.pydantic.dev/<pydantic-version>/v/missing"}]

passphrase_enabled: "maybe":

[{"type": "bool_parsing", "loc": ["client_access", "spec", "passphrase_enabled"], "msg": "Input should be a valid boolean, unable to interpret input", "url": "https://errors.pydantic.dev/<pydantic-version>/v/bool_parsing"}]

Parent 與 singleton collision:

unknown table ref 'orders' duplicate ref 'orders.client_access' (already declared in this document)

精確本機 detail 來源:components/iac/parse.ts;live-hash 檢查在伺服器端執行,依上文所述發生在 plan 或 apply。passphrase_permissions 的 validator 只在 apply 執行,失敗時回報第一則訊息,不加前綴。REST 欄位契約見 client access 參考。

動手試試

在 IaC 工作台用 passphrase_enabled: "maybe" 觀察 parse error,再改成 JSON boolean。Export 一份測試設定並確認 secret 已遮罩;跨 scope apply 前替換 redacted passphrase。

Last updated on