Files
lancedb/docs/web/governance/authorization.mdx
T
Will JonesandClaude Opus 5.5 4d7a64712f docs: adopt Embedded/Distributed terminology across docs and SDKs (#4713)
## Summary

Adopts the product terminology guide across the docs site pages, SDK
docstrings and error messages. "LanceDB OSS" and local mode become
**LanceDB Embedded**. "Remote" as the execution model becomes **LanceDB
Distributed**, which LanceDB Enterprise provides. Where free vs paid is
the point, pages contrast "LanceDB Embedded (open source)" with "LanceDB
Enterprise". This is a first trial of the Embedded name, so reviewers
can judge it in context.

- **Embedded vs Distributed** for where execution runs (`optimize()`,
consistency, branching, maintenance). Main pages define it once:
"LanceDB Enterprise runs LanceDB Distributed: …"
- **LanceDB Cloud** is kept only for legacy-Cloud specifics (`db://`
region, the brute-force KNN limit) and marked legacy. "Cloud and
Enterprise" becomes Enterprise or Distributed.
- **Plan executor** becomes "executor" or the fleet name.
- **Error messages** change, e.g. `optimize is not supported for remote
tables.` → `... in LanceDB Distributed.` Tests that match on them are
updated.
- **Vale rules** (`EmbeddedName`, `OSSProduct`, `RemoteExecution`,
`DistributedEnterprise`, `LegacyCloud`, `InternalNames`) enforce the
terms in prose.

Unchanged: identifiers (`availability.oss`, the `remote` module and
feature, `RemoteTable`, `db://`), heading anchors, internal code
comments, and Geneva.

## Evidence

- Rust lib tests for the changed messages and the Python tests in
`test_remote_db.py`, `test_materialized_views.py` and `test_table.py`
pass locally.
- Not run locally:
- The Node tests: `remote.test.ts` and `table.test.ts` have updated
assertions.
  - Vale.
  - The `experimental_functions`-marked materialized-view tests.
- `docs/src` API reference was hand-edited to match the docstrings
rather than regenerated.

## Merge Risk

**Door:** two-way; prose and message text only.
**Blast Radius:** `docs`, `error-messages`: callers matching on old
error strings would break.

Companion PRs: lancedb/docs (assembler labels, STYLE.md) and sophon
(Enterprise pages).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 14:04:41 -07:00

150 lines
5.6 KiB
Plaintext

---
title: "Authorization"
sidebarTitle: "Authorization"
description: "Who may do what: privileges granted on catalog objects to principals, groups, roles, and API keys."
icon: shield-halved
keywords: ["authorization", "authz", "privileges", "rbac", "access control"]
availability:
oss: unavailable
enterprise: available
summary: >-
Enterprise supports catalog privileges when its administrator configures enforcement. LanceDB Embedded has no catalog authorization layer: access is whatever the object store allows.
---
[Authentication](/enterprise/authentication) establishes who is calling.
Authorization decides what they may do.
An access control entry grants **one privilege** on **one object** to **one
subject**. Everything below is a consequence of that shape.
## Subjects {#subjects}
A grant is held by one of four kinds of subject, distinguished by a prefix:
| Prefix | Subject |
| --- | --- |
| `p:` | a principal, by ID (`P:` by name) |
| `g:` | a group, by ID (`G:` by name) |
| `r:` | a role |
| `a:` | the principal holding an API key, named by the key |
Granting to a group or role rather than a principal is what keeps the entry
count manageable: a principal's effective privileges are the union of what it
holds directly and what it inherits.
`P:`, `G:` and `a:` are ways of naming a subject when you make a request. The
entry is stored against the ID they resolve to, so a grant to `a:` belongs to
the principal holding that key and carries that principal's full authority,
not a narrower one.
## Objects {#objects}
Objects are addressed by kind and path:
```
system
database:db
namespace:db:ns
table:db:ns$table
view:db:ns$view
```
{/*
Draft for the Functions release. Replaces the object kinds above:
```
system
database:db
namespace:db:ns
table:db:ns$table
view:db:ns$view
function:db:ns$function
secret:db:ns$secret
```
*/}
A nested namespace joins its path with `$`, as in `namespace:db:parent$child`
or `table:db:parent$child$table`.
The hierarchy is not decorative. Reaching a table requires `USAGE` on the
namespace containing it and on the database containing that. A grant on the
table alone is not enough to traverse to it.
## Privileges {#privileges}
| Privilege | Granted on | Allows |
| --- | --- | --- |
| `OWNERSHIP` | any object but `system` | ownership, conveying full authority |
| `USAGE` | system | listing jobs and their events, and looking up other identities |
| `USAGE` | database | accessing the namespaces inside |
| `USAGE` | namespace | accessing the tables inside |
| `SELECT` | table, view | reading rows |
| `INSERT` | table | appending rows |
| `UPDATE` | table | modifying existing rows |
| `DELETE` | table | deleting rows |
| `CREATE_DATABASE` | system | creating a database |
| `CREATE_NAMESPACE` | database, namespace | creating immediate child namespaces |
| `CREATE_TABLE` | namespace | creating a table in it |
| `CREATE_MATERIALIZED_VIEW` | namespace | creating a materialized view in it |
| `CREATE_VIEW` | namespace | creating a non-materialized view in it |
| `OPERATE` | system | describing and controlling jobs, managing caches, and reading server configuration |
{/*
Draft for the Functions release. Add these rows to the table above.
After the `USAGE` row for namespace:
| `USAGE` | function | binding it to a column, and refreshing a column it computes |
| `USAGE` | secret | binding and resolving it |
After the `UPDATE` row for table:
| `UPDATE` | secret | rotating it, without the right to bind or read it |
After the `CREATE_VIEW` row:
| `CREATE_FUNCTION` | namespace | registering a function in it |
| `CREATE_SECRET` | namespace | creating a secret in it |
*/}
The four data privileges map onto the four
[ingestion operations](/ingestion), so a principal that may append but not
modify is expressed by granting `INSERT` without `UPDATE`.
<Note>
`CREATE_MATERIALIZED_VIEW` and `CREATE_VIEW` are separate privileges because
[the two objects differ](/basics/catalog): one stores rows and is refreshed,
the other stores only a query. Granting the ability to create one does not
grant the other.
</Note>
## Creation privileges resolve upward {#upward}
A subtlety worth knowing, because it explains grants that appear to work on
objects that do not exist yet.
When you create an object, the deployment checks the database and each
namespace that will contain it. One that **has no owner** (because it does
not exist yet, or predates per-object authorization) is treated as one you are
creating: the check falls back to `CREATE_DATABASE` on `system` for the
database, or to `CREATE_NAMESPACE` on its parent for a namespace, and you become
its owner. One that has an owner needs `USAGE` as usual.
So a principal holding `CREATE_DATABASE` can create a table in a database that
has not been created, which is what makes creation possible at all, and why
an empty ACL set is not the same as a deny. The fallback applies only when
creating; other operations on a database or namespace need `USAGE` on it.
## Listing grants {#listing}
Entries can be listed filtered by object, by subject, or both:
```
object = table:db:ns$documents
subject = G:data-science
```
Results paginate through a continuation token. A page holds at most 100 stored
`(object, subject)` tuples, and a tuple carrying several privileges expands
into several entries in the response, so a page can return more than 100
entries: the count reflects privileges rather than tuples. Keep requesting with
the returned token until a page comes back without one.
Listing by subject answers "what can this team reach"; listing by object
answers "who can reach this table". Both are worth running before changing a
grant.