Skip to content

ateapi: [Part 2] Runtime Authorization check for Actor and ActorTemplate CRUD - #1980

Merged
Benjamin Elder (BenTheElder) merged 4 commits into
agent-substrate:mainfrom
SHRUTI6991:authz_actor_and_template_checks
Oct 7, 2026
Merged

Benjamin Elder (BenTheElder) merged 4 commits into
agent-substrate:mainfrom
SHRUTI6991:authz_actor_and_template_checks

Conversation

@SHRUTI6991

@SHRUTI6991 Shruti Nair (SHRUTI6991) commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Working on #1563

Fixes #1699

Adds OpenFGA authorization checks for Actor and ActorTemplate CRUD RPCs, enforced when --experimental-enable-authz is set. AccessPolicy RPCs are still always enforced.

Checks

RPC Check(s)
CreateActorTemplate can_create_actor_template on atespace
Get/DeleteActorTemplate can_get / can_delete on actor_template
ListActorTemplates can_list_actor_templates on atespace (or global:root)
CreateActor can_create_actor on atespace + can_use_template on template
UpdateActor can_update on actor + can_use_template on template
Get/DeleteActor can_get / can_delete on actor
ListActors can_list_actors on atespace (or global:root)

Notes

  • A rule can produce more than one check, and every check must pass.
  • The interceptor authenticates the caller before it reads the request.
  • Missing or invalid identifiers fail closed with InvalidArgument and the field path. No check is skipped, so this does not depend on handler validation.
  • Parent links (actor/actor_template → atespace → global:root) are passed as contextual tuples, so creating or deleting a resource writes no tuples. Global owners, stored or bootstrap, reach actors and templates through these links.
  • UpdateActor always checks can_use_template on the template. Checking only when the template changes is left for a follow-up.

Testing

  • Registry tests for each RPC, plus fail-closed cases for bad identifiers.
  • Interceptor tests against Postgres-backed OpenFGA, covering editors, viewers, cross-atespace templates, and global and bootstrap owners.
  • OpenFGA model tests for the new relations.

@SHRUTI6991 Shruti Nair (SHRUTI6991) changed the title Authz actor and template checks ateapi: [Part 2] Runtime Authorization check for Actor and ActorTemplate CRUD Sep 29, 2026
@SHRUTI6991
Shruti Nair (SHRUTI6991) marked this pull request as ready for review September 29, 2026 16:31
@mayawang Maya Wang (mayawang) added area/api User-facing API changes area/security Security related issue/pr kind/feature An enhancement / feature request or implementation labels Sep 29, 2026
@SHRUTI6991
Shruti Nair (SHRUTI6991) force-pushed the authz_actor_and_template_checks branch from 4a9ff16 to ded45ff Compare September 30, 2026 17:24
Actor and ActorTemplate RPCs were not covered by the authz interceptor,
so with --experimental-enable-authz set, callers could read and modify
them in any atespace.

The registry now maps each RPC to a list of checks, all of which must
pass. CreateActor needs can_create_actor on the atespace and UpdateActor
needs can_update on the actor; both also need can_use on the referenced
actor template, which may live in another atespace. Get and Delete check
the resource, and List checks the atespace, or global:root when the
atespace is empty.

Actors and templates are identified as actor:<atespace>/<name> and
actor_template:<atespace>/<name>. Their parent atespace is derived from
the ID and sent as contextual tuples, so no tuples are written on create
or delete. '/' is escaped in each component so every ID names exactly
one resource.
The check extractors used to leave out a check whose atespace or name was
missing and rely on the handler to reject the request. For UpdateActor,
whose request validation does not descend into the actor, that left the
template check to validation run deep inside the store transaction.
Names OpenFGA cannot accept in an object ID also surfaced as Internal.

Extractors now require every identifier a check needs to be present and a
valid resource name, and return InvalidArgument with the field path
otherwise, so no check is skipped and OpenFGA never sees a malformed ID.
The interceptor authenticates before extracting, so unauthenticated
callers still get Unauthenticated.
Actor and actor template checks reach global:root only through the
contextual actor -> atespace -> global:root links. Cover a global owner
and a bootstrap owner, which has no stored tuples, on get, update, and
delete, and a global viewer being denied the writes.
The actor_template relation that gates running actors from a template is
now can_use_template, so the permission name says what is being used.
@SHRUTI6991
Shruti Nair (SHRUTI6991) force-pushed the authz_actor_and_template_checks branch from 0f54ab7 to 5d3e2ea Compare October 7, 2026 18:37
// tuples in PostgreSQL.
//
// Why contextual tuples are used instead of storing `parent_global` in the database:
// Why contextual tuples are used instead of storing parent links in the database:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This is a longer-term comment we should think about, but doesn't block submitting this PR).

Why not do everything with contextual tuples? Why do we need to to use OpenFGA's relation table at all, if all of the information in it is redundant with information stored in the Substrate tables.

I think the answer (if there is one) is that OpenFGA should be doing its graph search during retrieval from the relation table, rather than loading everything into memory and doing the graph search there. So are we harming the ability for that to happen by using contextual tuples for things that OpenFGA expects to be concrete in the relation table?)

(My mental model of contextual tuples is that they are for things that are inherently request-scoped, for example, the fact that a user authenticated with a client cert or a JWT, or the geolocation of their calling IP)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1,

May be I am over abusing contextual tuples. Let me create a task to think through if we should store the structural links during creation of the resource.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 7, 2026
@BenTheElder
Benjamin Elder (BenTheElder) added this pull request to the merge queue Oct 7, 2026
Merged via the queue into agent-substrate:main with commit 756c2a5 Oct 7, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api User-facing API changes area/security Security related issue/pr kind/feature An enhancement / feature request or implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Runtime authorization check for Actor and ActorTemplate

7 participants