Skip to content

fix(acl): let the role an agent runs as reach the room oracle - #1275

Merged
stormer78 merged 1 commit into
mainfrom
fix/agent-role-room-capabilities
Sep 7, 2026
Merged

fix(acl): let the role an agent runs as reach the room oracle#1275
stormer78 merged 1 commit into
mainfrom
fix/agent-role-room-capabilities

Conversation

@stormer78

Copy link
Copy Markdown
Contributor

Second of two found while writing the data-rooms operator guide (#1273); the other is #1274.

The room presentation oracle exists for exactly one consumer — an agent holding strictly less than its human, asking its principal's VTA to mint a scoped presentation (rooms/keys/present) and to open what it cannot decrypt (rooms/keys/open). application is the role such an agent runs as; vta-agent-memory grants exactly it. It held neither RoomPresent nor RoomOpen, so the one consumer the oracle was built for could not call it.

There was no way around it per-entry either: the gates call role_has_capability, which reads the role and nothing else. The workaround an operator reaches for is worse than the grant — running the agent as initiator, which carries KeyMint and DeviceAdmin besides.

Why this is not a widening

RoomPresent mints a leaf attenuated from the principal's own room authority — one action, one room, four hours, bound to the caller. The role already holds Sign: the principal's key over arbitrary bytes, and therefore strictly more
RoomOpen decrypts a room record under a group key the VTA already holds. The same role can already read the credential vault

Reader and Monitor get neither, and a test pins it: minting a credential on a principal's behalf is not a read.

Two doc comments that described enforcement that does not exist

AclEntry::capabilities said the auth layer falls back to the role-derived set when it is empty — which reads as "and uses this set when it is not". It does not. No gate consults the field, the authenticated claims carry no capability set, and nothing over the wire can set it; it is read in exactly one place, to describe a registered device's authority in a binding listing. A reader who believed otherwise would think an entry was least-privileged when it holds everything its role does. The field and role_has_capability now say what is true.

Making it real — carrying the set in the claims, and giving the ACL surface a way to set it — is a separate change with its own design question: may an entry's capability set widen beyond its role, or only narrow within it? Worth doing, not worth smuggling in here.

The room presentation oracle exists for one consumer: an agent holding
strictly less than its human, asking its principal's VTA to mint a scoped
presentation and to open what it cannot decrypt. `application` is the role
such an agent runs as - `vta-agent-memory` grants exactly it - and it held
neither `RoomPresent` nor `RoomOpen`, so the one consumer the oracle was
built for could not call it.

The gates are role-derived (`role_has_capability` reads the role and nothing
else), so there was no way to grant the capability to a particular entry
either. The workaround an operator reaches for is worse than the grant:
running the agent as `initiator`, which carries `KeyMint` and `DeviceAdmin`
besides.

Neither capability widens what this role can do. `RoomPresent` mints a leaf
attenuated from the principal's own room authority - one action, one room,
four hours, bound to the caller - and the role already holds `Sign`, which is
the principal's key over arbitrary bytes and therefore strictly more.
`RoomOpen` decrypts a room record under a group key the VTA already holds,
and the same role can already read the credential vault. `Reader` and
`Monitor` get neither, and a test pins that: minting a credential on a
principal's behalf is not a read.

Also corrects two doc comments that described enforcement that does not
exist. `AclEntry::capabilities` said the auth layer falls back to the
role-derived set when it is empty, which reads as "and uses this set when it
is not" - but no gate consults the field, the authenticated claims carry no
capability set, and nothing over the wire can set it. It is read in exactly
one place, to describe a registered device's authority in a binding listing.
A reader who believed otherwise would think an entry was least-privileged
when it holds everything its role does, so the field and
`role_has_capability` now say what is true. Making it real means carrying the
set in the claims and giving the ACL surface a way to set it - a separate
change with its own design question about whether an entry's set may widen
beyond its role or only narrow within it.

Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
@stormer78
stormer78 requested a review from a team as a code owner September 7, 2026 07:17
@stormer78
stormer78 merged commit 1c28148 into main Sep 7, 2026
16 checks passed
@stormer78
stormer78 deleted the fix/agent-role-room-capabilities branch September 7, 2026 07:28
stormer78 added a commit that referenced this pull request Sep 7, 2026
Two of the four findings the guide surfaced are closed by #1274 (registration
is authorized: the signer must be the owner it names) and #1275 (the role an
agent runs as carries the room capabilities). The guide described both as
live gaps, so it goes stale the moment either merges.

The room-creation caveat becomes what creation actually checks, and what it
still does not: the request's own proof establishes the owner, and nothing
yet governs which parties may create a room on a given host. The
agent-capability catch becomes how to grant the oracle - by role, since the
per-entry capability list is descriptive rather than enforced, which is worth
saying where an operator would otherwise reach for it. Both the markdown and
the HTML page carry the same correction, plus a refusal-table row for the
registration error an operator will now meet.

Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant