GizStack
View .mdOpen in ChatGPTOpen in Claude

gizdb:gate

who may read and write which rows of a Shape. It is the one place that applies the Policy (grants on records and the ancestry of records, db/policy.giz) to a Shape's rows, so a page, an API, an agent's tool and a background job that act through a Db with a Scope (db/data.giz) are all judged the same way, by the same function.

A stored Shape is a record of the Policy named SPACE/table/NAME, and each of its rows is SPACE/NAME/KEY below it (or below the row that its @Within field names). A grant on the table reaches every row; a grant on one row reaches that row and its children. A read adds a condition to the query, so a row the actor may not read is never selected; a field the actor may not read is selected as NULL. A write is checked before it runs, and a row is placed in the Policy in the transaction that inserts it.

gizlang
import * as Gate from "gizdb:gate";

Types

Scope

gizlang
type Scope = { space: string; actor: Security.Principal; now: i64; held: Task.Cell<Vec<Held>>; }

Who acts: the actor, the Space whose records they are, and the time (ms since 1970). A Scope is for one request: it remembers what the Policy said of the actor's roles on the tables, so the reads of a page ask once. Rows change no grant on a table; provision forgets what it knew.

  • space: string
  • actor: gizlang_security.Principal
  • now: i64
  • held: gizlang_task.Cell<Vec<M50.Held>>

Access

gizlang
type Access = { readable: Vec<bool>; writable: Vec<bool>; role: Security.Role; mayWrite: bool; }

What a role may do with the fields of a Shape. A field with a @Read role is read when the role is at least it; a field with a @Write role is written when the role is at least it and also the Shape's write role; a key and a computed field are never written.

  • readable: Vec<bool>
  • writable: Vec<bool>
  • role: gizlang_security.Role
  • mayWrite: bool

Masks

gizlang
type Masks = { conds: Vec<string>; slots: Vec<Typed.Slot>; params: Vec<Value>; }

The masks of the fields with a @Read role: for each field a SQL condition that is true on the rows where the actor may read it (empty for a field that any reader sees), with its parameters numbered from first. A role is judged once however many fields have it.

  • conds: Vec<string>
  • slots: Vec<M54.Slot>
  • params: Vec<M55.Value>

Plan

gizlang
type Plan = { set: Vec<bool>; writes: Vec<Policy.Write>; }

What a write sets: set flags the fields that it writes, and writes are the Policy statements that go in its transaction.

  • set: Vec<bool>
  • writes: Vec<M60.Write>

Functions

scope

gizlang
function scope(space: string, actor: Security.Principal, now: i64): Result<Scope, string>

A Scope. A Space is named as a reference part is: 1 to 64 of a-z 0-9 _ . -

Effects: fail, io.

checked

gizlang
function checked(shape: Model.Shape): Result<bool, Model.Rejection>

Whether a Shape can be judged: stored under a table that names a Policy record, with a key of text or integers.

Effects: fail.

keyOf

gizlang
function keyOf(shape: Model.Shape, values: Vec<Value>): Result<string, Model.Rejection>

The key text of a row's values (the parts of a composite key are joined by /).

Effects: fail.

readable

gizlang
function readable(source: Source, s: Scope, shape: Model.Shape, first: i64): Result<Policy.Condition, Model.Rejection>

The condition that selects only the rows that the actor may read, with its parameters numbered from first.

Effects: fail, read, write, console, io.

access

gizlang
function access(source: Source, s: Scope, shape: Model.Shape, ref: Security.ResourceRef): Result<Access, Model.Rejection>

The access of the actor to the record ref (a row, or the table for a row that does not exist yet).

Effects: fail, read, write, console, io.

accessToTable

gizlang
function accessToTable(source: Source, s: Scope, shape: Model.Shape): Result<Access, Model.Rejection>

The access to a row that is created below the table (the row is not there yet).

Effects: fail, read, write, console, io.

accessToRow

gizlang
function accessToRow(source: Source, s: Scope, shape: Model.Shape, values: Vec<Value>): Result<Access, Model.Rejection>

The access to the row with these key values.

Effects: fail, read, write, console, io.

masks

gizlang
function masks(source: Source, s: Scope, shape: Model.Shape, first: i64): Result<Masks, Model.Rejection>

The masks of the fields of SHAPE that the actor of S may read only on some rows, with parameters numbered from FIRST (Masks).

Effects: fail, read, write, console, io.

admitCreate

gizlang
function admitCreate(source: Source, s: Scope, shape: Model.Shape, values: Vec<Value>): Result<Plan, Model.Rejection>

Admit a new row: the actor holds the Shape's write role on its parent. The Plan places the row.

Effects: fail, read, write, console, io.

admitUpdate

gizlang
function admitUpdate(source: Source, s: Scope, shape: Model.Shape, old: Vec<Value>, values: Vec<Value>): Result<Plan, Model.Rejection>

Admit a change of the row old (as the actor reads it) to values: the actor holds the write role on the row, and on the new parent when a @Within field moves it.

Effects: fail, read, write, console, io.

admitRemove

gizlang
function admitRemove(source: Source, s: Scope, shape: Model.Shape, old: Vec<Value>): Result<Plan, Model.Rejection>

Admit the removal of the row old: the actor holds the write role on it. The Plan removes its grants and its place.

Effects: fail, read, write, console, io.

provision

gizlang
function provision(s: Scope, shapes: Vec<Model.Shape>): Result<Vec<Policy.Write>, Model.Rejection>

The statements that make the Policy tables and place the table record of each Shape, with the actor as its owner. Run them once for each Space; they can run again.

Effects: fail, read, write, console, io.