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"
tabletarget table ref
principaltyped IacGrantPrincipal object
statepresent/absent,預設 present
specobject 或 null;absent 時禁止提供

principal 只接受 typeidaudiencetype 必須是 userdepartmentclientchatroomid 必填、1–160 字元並符合 ^([a-z0-9][a-z0-9_.-]{0,35}|\$(user|dept|smc|room):[^\r\n]{1,150})$——可以是最多 36 字元、不含冒號與空白的原始 ID,或是前綴與 type 相符的可攜身分 tokenuser$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_readcan_insertcan_editvisible_columnsread_filteredit_filterscope_valuescan_read/can_editnone|own|all|filtered|nullcan_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 都互不相干。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 createupdatenoop,並以 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

驗證錯誤

Audience 與 grant value 的 byte-exact local-only detail:

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 leaves (25) row policy exceeds max 6 link leaves (7)

row policy … 開頭的字串是 Workbench 對 row-policy 文法的本地預檢——節點種類、允許的 key、quantifier 與 require_present 規則、深度(5)、leaf(24)與 link leaf(6)上限、以及 row policy <path> 標籤都與伺服器的 custom_table_row_policy.py 相同,因此本地過檢的 policy 形狀一定是伺服器接受的形狀。預檢會對照文件解析本表每個 scalar leaf 的 column 與每個 link_targetlink 欄位;link_targettarget 內的 leaf 屬於被連結的表,由伺服器 plan 解析。Operator、token 與欄位型別的配對同樣由伺服器判定。

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

前四類模板(audience 兩類、can_insert、access level)目前由工作台本機穩定攔截;server 尚未穩定序列化相同 validator detail。精確來源:components/iac/parse.ts

動手試試

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

Last updated on