Entity access

The entity grant — which of your app's own tables it may read and write, per operation, and how that grant shapes the generated typed client.

Which of your own tables the app may touch, and how. Shipped, and the grant every app writes first.

manifest.json
{ "entity": "device_serials", "access": ["read", "create", "update"] }
AccessAllows
readReading rows
createInserting rows
updateUpdating rows
deleteDeleting rows

Declare one entry per entity in your schema.json, and grant only what the app actually does.

The grant shapes the generated client

This is the part that makes the grant more than paperwork. revenexx apps generate reads manifest.json alongside schema.json, and only generates the methods you granted:

GrantedThe client has
readlist, page, get
createcreate
updateupdate
deletedelete
manifest.json
{ "entity": "audit_entries", "access": ["read", "create"] }
src/main.js
await db.audit_entries.create({});   // fine
await db.audit_entries.update(id, {}); // TypeError: not a function

So the boundary is enforced in the types, not only at runtime. An append-only ledger cannot be rewritten by a bug, a bad merge, or a Cockpit action, because there is no method to call. That is a real safety property and it costs you one array.

Widen the grant, regenerate, and the methods appear:

Terminal
revenexx apps generate

Forgetting that step is the usual explanation for db.x.update is not a function right after you edited the manifest.

Grant per operation

The asymmetry is the useful part. Read each entity's purpose before you grant on it:

The entity isGrant
An append-only log, ledger or audit trailread, create
Reference data your app maintainsread, create, update
Rows an operator genuinely deletesall four
Something you only readread

["read", "create", "update", "delete"] on everything is the shape to avoid: it tells the merchant nothing, and it removes the one guard that costs you nothing to keep.

It stops at the app boundary

An entity grant is not how you reach another app's data. You cannot name another app's entity here, and there is no grant that would let you. Foreign keys and grants both stop at the app boundary — the way in is that app's capabilities:

manifest.json
"permissions": [
  { "entity": "device_serials", "access": ["read", "create", "update"] },
  { "capability": "products.get", "compatible": "^1.0" }
]

See Calling another app and Relationships.

What it does not do

It is not tenant isolation. Scoping to the calling tenant is unconditional and applies whatever you grant — see Tenant isolation.

It is not a public route. A grant lets your code touch the table. Whether anything outside can is a capability, and mountCrud's only option is a second, independent fence — see CRUD.

It is not an operator permission. Whether this Cockpit user may edit a row is the view's own permissions array and provides_permissions, not this.

The three fences compose, and it is worth setting all of them deliberately for an entity that matters:

text
manifest.permissions   → what your code may do at all
mountCrud only         → what is reachable over the public API
cockpit view permissions → what an operator sees and can act on

Next steps

Was this page helpful?