Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion docs/docs/Post Platform Guide/access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,27 @@ query {

You always get the policy actually in force. A record written with only `acl: ["*"]` reports `default_perms: 15` behind an always-passing group rather than returning the array, so you can render one consistent view without caring how the record was written.

## Naming a group instead of a person

A grant or denial can name a group eName, and it resolves to the group's members when the decision is made — so membership changes take effect without rewriting any policy.

```json
{ "v": 1,
"grants": [ { "ename": "@owner", "perms": 15 },
{ "ename": "@9f0e1d2c-3b4a-5968-7766-554433221100", "perms": 1 } ],
"denials": { "enames": [], "conditions": [] },
"default_perms": 0,
"require": [] }
```

You do not have to normalise your group records first. Participants are read from `members`, `memberIds`, `participants`, `participantIds`, `admins` and `owner`, and each entry may be **either an eName or the id of that member's profile record** — the two shapes platforms actually write. A profile id resolves through the record's own `ename` field, falling back to the vault it lives in.

Worth knowing:

- **Admins and the owner count as members.** Every participant field is unioned, so a group grant reaches them too. If you need admins treated differently, name them directly rather than relying on the group.
- **A group grant is the least specific kind.** A direct grant to the user or the platform overrides it entirely and is not combined with it.
- **A group whose record this eVault does not hold cannot be resolved.** A grant naming it hands out nothing; a denial naming it stays in force. Uncertainty never widens access, but it can refuse someone you expected to admit.

## Things that will bite you

**A grant is final.** If your platform is named in `grants`, that grant decides the answer on its own. It never falls through to `default_perms` — so a platform granted `1` on a record whose `default_perms` is `15` has read access, not full access. Being named is not always an upgrade.
Expand Down Expand Up @@ -197,7 +218,6 @@ List queries behave differently again: a record you may not read is **omitted fr

Two parts of the protocol document are specified but not connected, and a policy relying on them will not behave as written:

- **Groups.** Group membership is not resolved, so a grant or denial naming a group matches nobody. A group grant simply fails to apply; a **group denial silently fails to deny**, which is the dangerous direction. Name parties individually for now.
- **Ontology conditions.** No evaluator is wired in, so any condition fails. A `require` group containing conditions can never pass, and a deny condition always fires and refuses everyone. Until that lands, use only `grants`, `denials.enames`, and `require: []` or `require: [[]]`.

Enforcement is eVault-side. Platforms and the adapter do not evaluate policies themselves, so do not treat a policy as a reason to skip your own authorization checks.
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/W3DS Basics/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ An entry in an [ACL](#access-control-list-acl) pairing a party's [eName](#web-30

## Group

An [Entity](#entity): a reference to a number of users within the MetaState that holds its own [W3ID](#web-30-identifier-w3id-ename) and [eVault](#evault). It is often seen as a "group" in social networks.
An [Entity](#entity): a reference to a number of users within the MetaState that holds its own [W3ID](#web-30-identifier-w3id-ename) and [eVault](#evault). It is often seen as a "group" in social networks. In an [ACL](#access-control-list-acl) a group eName is resolved to its members' eNames when a decision is made, so naming a group stays correct as its membership changes.

---

Expand Down
32 changes: 31 additions & 1 deletion docs/docs/W3DS Protocol/Access-Control.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,36 @@ Grants tied at the same specificity — duplicates, or two groups the party belo

A direct grant is final. A named party never falls through to the ontology half, whether its grant allowed the action or not.

### How a group resolves

A group eName is not a party in its own right — it stands for the people in it, and is resolved to their eNames when the decision is made. Naming a group in a policy therefore stays correct as the group's membership changes, with nothing to rewrite.

The group's record is found either in the group's own vault or by its `ename` field naming the group, and its participants are read from whichever fields it carries — `members`, `memberIds`, `participants`, `participantIds`, `admins`, `owner`. A group's members are the union of all of them, so an admin is a member.

A participant may be named two ways, and both are accepted:

| Written as | Example | Resolved by |
|---|---|---|
| An eName | `@7b9c2e1a-…` | Taken as-is. |
| A profile record's id | `4f1a8c30-…` | Following the record to the eName behind it. |

Both occur in practice — `GroupManifest.members` holds eNames while `Group.participantIds` holds profile ids — so a policy naming a group works regardless of which shape the group was written with.

When a participant is given as a profile id, the eName is taken from the record's own `ename` field where it has one, and otherwise from the vault the record lives in. The record's own statement wins because the same profile syncs into several vaults, so the vault it happens to sit in does not reliably identify its subject.

An id that resolves to nothing is skipped rather than treated as a member.

### When membership cannot be determined

A lookup that fails is not the same as a party being shown not to be a member, and the two lead to opposite answers:

- A **grant** to a group applies only on proof of membership. Uncertainty withholds it.
- A **denial** naming a group applies unless the party is shown *not* to be a member. Uncertainty holds the denial.

So a group whose record cannot be read is safe in both directions: it hands out nothing and it stops removing nothing.

Where no group resolver is configured at all, groups simply do not resolve — that is the feature switched off rather than a failed lookup, and group grants and denials alike match nobody.

## Denials

A denial removes access regardless of any grant. **Deny always wins**, with no exceptions — it is the one place where specificity does not decide the outcome.
Expand Down Expand Up @@ -240,9 +270,9 @@ Reserved permission bits exist for the same reason: they are refused today so th

## Current limits

- **Group membership is not resolved yet.** A grant or denial naming a group matches nothing. For grants that is fail-closed; for denials it is fail-**open**, so group denials are not usable yet.
- **Condition evaluation is a seam, not yet connected.** eVault accepts an evaluator but none is wired in, so conditions currently fail closed: a `require` group containing conditions cannot pass, and a deny condition always fires. Until an evaluator is connected, write policies that use `grants`, `denials.enames`, and empty-group `require` only.
- **Enforcement is eVault-side.** The Web3 Adapter and platforms do not evaluate `_acl` yet.
- **Group resolution reads records this eVault holds.** A group whose record has not synced here cannot be resolved, and is treated as undeterminable — see above for what that means in each direction.
- `default_perms` above READ for unnamed parties is unsettled under the current sync model.

## See also
Expand Down
Loading
Loading