Skip to Content

grant line

grant 沒有 authored ref;它以 table + principal natural identity 管理一列 ACL。這讓 user、department、client 與 chatroom audience 的授權都能 plan、審查、套用與明確撤銷。

JSONL Line

{"kind":"grant","table":"orders","principal":{"type":"chatroom","id":"33333333-3333-4333-8333-333333333333","audience":"internal"},"spec":{"can_read":"filtered","can_insert":false,"can_edit":"none","visible_columns":["order_no","status"],"read_filter":{"and":[{"column":"status","op":"eq","value":"open"}]},"scope_values":["support"]}}

欄位契約

頂層對應 IacGrantLine:

欄位必填精確契約
kind是固定 "grant"
table是target table ref
principal是typed IacGrantPrincipal object
state否present/absent,預設 present
spec否object 或 null;absent 時禁止提供

principal 只接受 type、id、audience。type 必須是 user、department、client、chatroom;id 必填、1–160 字元並符合 ^([a-z0-9][a-z0-9_.-]{0,35}|\$(user|dept|smc|room):[^\r\n]{1,150})$——可以是最多 36 字元、不含冒號與空白的原始 ID,或是前綴與 type 相符的可攜身分 token(user → $user:、department → $dept:、client → $smc:、chatroom → $room:);audience 只有 chatroom 必填且只能是 internal/external,其餘 type 禁止。

Token 會在衍生的 {table}.grant:{type}:{id} ref 建立之前,以公司為錨點 fail-closed 地解析,因此指向同一 principal 的 token 文件與原始 ID 文件會收斂到同一列 state,而不是新增一筆重複 grant。

IaC Pydantic model 把 spec 定義為 Dict[str, Any],並在 parse 先守住三個危險值型別;server grant validators 再處理完整語意。引擎支援的精確欄位是 can_read、can_insert、can_edit、visible_columns、read_filter、edit_filter、scope_values。can_read/can_edit 是 none|own|all|filtered|null;can_insert 是 boolean/null;三者明確 null 分別正規化為 none/false/none。其他欄位可為 refs/policy/array 或 null。Spec 省略合法:新 grant 使用安全 write defaults,既有 grant 的未宣告 fields 保留 live 值。

Ref 與身分規則

Derived state ref 是 {table}.grant:{type}:{id};chatroom 再加 :{audience},例如 orders.grant:chatroom:33333333-3333-4333-8333-333333333333:internal。同一 principal 的 internal/external grants 是兩個不同 identities。

visible_columns entries 與 read_filter/edit_filter predicate column 都是 target table 的 column refs,不是 display names 或 internal keys。未知 token fail closed。link_target leaf 把這條規則拆到兩張表上:它的 link 是本行 table 的 ref,target 內每個 column 則是被連結那張表的 ref。相對地,predicate 的值可以帶 ACL row-policy token $me、$me.department、$today、$today±Nd(N 為 1 到 730,Asia/Taipei)與 $now——這套語法與上面的身分 token 及 command DSL 都互不相干。在 decimal 欄位上,predicate 的值是 decimal 字串,例如 "100.00",並以精確 decimal 比較,絕不當成浮點數。Grant derived refs 不占用 column/rule/trigger/view/public_read 的 authored child-ref slug,但同一 natural identity 不應在文件重複宣告。

若 principal.id 中的 token 無法解析,plan action 會帶一個 {table}.grant:{type}:unresolved-{8 個十六進位字元} 形式的佔位 ref,好讓錯誤仍可歸屬。它不是資源身分。

生命週期與規劃

Present grant 會對 natural identity create、update 或 noop,並以 last-applied fields 偵測 drift。只有 declared fields 由 IaC 管理;省略保留 live value。Filtered access 必須有對應的非空 policy——任一棵由 predicate 與 link_target leaf 組成的 and / or / not 樹——且非 filtered mode 不得保留 filter。

state: "absent" 不帶 spec,規劃 delete/revoke;若 live grant 已不存在則 noop warning。單純省略 line 不代表撤銷。Chatroom grant 另由 server plan 驗證 table department scope、company/chatroom 關係與 scope_values。

只要目標資料表是 live,server plan 就會執行與 REST grant route 相同的 grant validator,每一項失敗都是帶著 validator 訊息的 validate 錯誤:

Users not found: ['<id>'] Users not in the same company: ['<id>'] Cannot set explicit permissions for table managers — they have full implicit access Department not found Social media client not found Chatroom not found Chatroom grants are only valid on department-scoped tables

Table manager 本來就有完整的隱含權限,所以 user grant 不能以 table manager 為對象。Validator 也會重新檢查 filter 與 visible_columns。若資料表由同一份文件建立,這些檢查會延到 apply,該行並警告 grant target table is itself being created in this apply; grant legality cannot be fully verified until then。省略 scope_values 的 present chatroom grant 會警告 scope_values omitted on a channel-governed table; silence preserves the current value, explicit null denies。

Apply 會重新解析 principal 並重跑 validator。Validator 失敗時回報第一則訊息,不加前綴;已解析不到的 token 回報 grant '{table}.grant:{type}': {token error};而在 apply 執行期間名稱易主的 token 回報 principal token '{token}' now resolves to a different principal than it did at plan time; run plan again。

驗證錯誤

Audience 與 grant value 的 byte-exact validator detail(伺服器的 value_error 文字,Workbench 會原樣重現):

principal.audience is required when principal.type=='chatroom' principal.audience is only valid when principal.type=='chatroom' grant spec 'can_insert' must be a boolean (true/false) or null, not str grant spec 'can_read' must be one of ['all', 'filtered', 'none', 'own'] or null, got 'read_only'

Ref/policy validate detail:

unknown table ref 'orders' unresolved visible_columns ref 'missing': unknown column ref 'orders.missing' unresolved read_filter ref 'missing': unknown column ref 'orders.missing' unresolved edit_filter ref 'missing': unknown column ref 'orders.missing' can_read "filtered" requires a read_filter read_filter is only valid when can_read is "filtered" can_edit "filtered" requires an edit_filter edit_filter is only valid when can_edit is "filtered" row policy must be one of {"and": [nodes]}, {"or": [nodes]}, {"not": node}, a {"column", "op", "value"} predicate or a {"link", "quantifier", "target"} link_target leaf row policy or[1] "and" must be a non-empty list of nodes row policy "not" takes exactly one node, not a list row policy and[0]: leaf node has unknown key(s): extra row policy: link_membership leaves are not supported in row policies — use link_target with a target {"column": "id", "op": "in", "value": [...]} row policy: quantifier must be "any" or "all" row policy: require_present must be stated explicitly (true/false) on quantifier "all" — all([]) is vacuously true row policy: require_present does not apply to quantifier "any" (already false when there are no linked records) row policy: "link" must name a link column (internal col_<hex> key) row policy target: a link leaf may not appear inside a link_target's target (row policies are 1-hop) row policy nests deeper than the max 5 levels row policy exceeds max 24 predicates (25) row policy exceeds max 6 link leaves (7)

Present grant 的目標已解析到既有表時,plan 先翻譯 filter ref,再檢查文法;結構錯誤使用 {read_filter|edit_filter} {path|root}: {message},例如 read_filter and[0]: predicate is missing a 'column' key。若 apply 必須建立目標表,server plan 會警告並將翻譯與 grant 合法性延至 apply。

row policy … 範例是 Workbench 本機結構預檢,不保證 IaC 診斷或接受結果相同。預檢涵蓋節點種類、允許 key、quantifier、require_present、深度(5)、leaf(24)及 link leaf(6)上限。伺服器 ref 翻譯可能在 ACL 驗證前以不同方式拒絕或重建節點。本表 scalar leaf 與 link 欄位 ref 依文件檢查;target ref、operator、token、型別配對及既有 grant 合法性仍由伺服器檢查。本機成功代表進入 server plan,不代表可以 apply。

身分 token 的語法與解析失敗屬於伺服器 plan 錯誤,目錄請見可攜身分 token。工作台會驗證 principal.id 的 pattern,但無法解析名稱。

前四類模板(audience 兩類、can_insert、access level)來自丟出一般 ValueError 的 validator。觸發其中任一類的文件在 plan 與 apply 都以 parse 階段的 400 回應,帶 typed value_error issue——兩類 audience 的 loc 是 ["grant", "principal"],can_insert 與 access level 是 ["grant"](見 Validator 訊息類別);工作台顯示相同的 detail。can_read 或 can_edit 為 list/object 時,現在產生 typed 400 grant_access_level_type,靜態訊息為 Grant access level must be a scalar or null,不含 input 或 context 值。見格式錯誤輸入。

動手試試

在 IaC 工作台建立範例 chatroom grant,依序移除 audience、把 can_read 改成 filtered 卻移除 policy,再修正。對測試 scope plan 後,核對 principal、audience、visible columns 與 scope values。

Last updated on