Access control with Spaces
Content, datasets, and cases each belong to exactly one Space, the primary access control boundary in Perpetual. One Perpetual deployment usually serves several groups that should not see each other's events, whether that is a subsidiary, a region, a team handling something under legal hold, or one client of the service provider operating the deployment. A Space is what keeps them apart inside it.
A user's access to a Space comes from the roles they hold
A permission pairs one target with one access level, and it lives on a role. An organization owner assigns that role to a user's membership, and the user gains what the role grants. All grants are defined by roles, so every path from a user to a Space runs through one.
A role is an access shape defined once and handed to many people. A membership with no role gains nothing, so adding someone to an organization and giving them something to do are two separate acts.
A user can hold several roles at once, and on any one Space the highest level any of them grants is the level that applies. Working out what one person can reach means reading every role they hold, because no single record carries the answer.
A user sees only the Spaces their roles reach
Perpetual works out the set of targets a user's roles reach and folds that set into the read itself, so rows outside it never come back. A query compiles against the catalog the filter left behind, which means a dataset a user cannot reach is not a name their query can use.
A Space a user's roles do not reach does not appear at all, and neither do the datasets and cases inside it. There is no denial to notice.
A grant names one of three access levels
One level answers what someone may do across the whole Space.
readsees the Space's content and datasets, and queries the datasets.writeedits the content.executeinvokes the HTTP Tools and MCP Servers the Space configures.
The three form one ordered scale, and a grant at any level carries every level
beneath it. A check reads the ladder from the other side, so a check at write
passes for anyone holding write or execute.
execute sits at the top because invoking one of those tools takes action
outside Perpetual, using credentials the Space holds, and those actions can be
hazardous. Every level below it stays inside the platform.
A query's output is saved across a Space boundary only when allowed by the source Space's configuration
Who can reach a Space settles nothing about whether one Space's data may reach
another. The source Space declares that itself, through
dataFlowAuthorizedTo, naming the other
Spaces allowed to use its datasets. Working in a Space, the datasets a query can
name are that Space's own plus those in the Spaces authorized to send it data.
Seeing a dataset and building on it are governed separately. Whoever asks has to be allowed to see it, and the Space they are working in has to be allowed to build on it.
Each authorization runs one way. A Space authorizing another to use its datasets gains nothing in return, and the reverse direction is its own entry. Perpetual checks a cross-Space dependency when you commit the content that creates it.
Sharing data between two Spaces that must not reach each other means putting it in a Space upstream of both. Aggregating across them means a Space downstream of both. That is what keeps them from reaching each other directly. The rules check one hop at a time. A Space that both receives from one and sends to another passes data along, so the shape is yours to keep clean.
An agent writes only inside a Space. An attempt to create or change anything without one fails, and an agent working inside one can reach only that Space. A chat that is not scoped to a Space reads whatever the user's roles reach and writes nothing at all.
The same data can stay separate for one group and be queryable together by another.
Access to the access configuration is a grant like any other
A permission can target a role, which puts the access configuration under the
same machinery as everything else. A role target accepts only read and
write, and Perpetual rejects execute over one.
The two grants answer different questions. A grant over a Space decides what someone can do with content and data. A grant over a role decides who can change the role.
Some resources and grants are organization-wide
Some content is organization-wide rather than living in a Space, so no Space grant reaches it and no split of Spaces narrows access to it. Other resources carry no Space at all, among them changesets, schemas, and threat reports, and any member of the organization can read them.
A role carries capabilities as well as permissions. A capability is an organization-wide administrative grant over how the organization itself is configured, and it names no Space.
Splitting a Space is the only way to draw a narrower boundary
Perpetual has no subtractive grant. Nothing denies a level another grant allowed, and a second role only raises a user's level, so taking access away means removing or lowering the grant that supplies it.
So the way to draw a narrower boundary is a narrower Space. Splitting one in two lets you grant someone access to one half, the other, or both.