feat: add access service with Goa API for principal grants RBAC#1882
feat: add access service with Goa API for principal grants RBAC#1882
Conversation
Adds the access service with three endpoints: - listGrants: list grants for an org, optionally filtered by principal URN - upsertGrant: create-or-noop a grant for a principal/scope/resource tuple - removeGrants: remove all grants for a principal in an org Includes Goa design, generated code, service implementation, and server wiring.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
| func (s *Service) ListGrants(ctx context.Context, payload *gen.ListGrantsPayload) (*gen.ListGrantsResult, error) { | ||
| authCtx, ok := contextvalues.GetAuthContext(ctx) | ||
| if !ok || authCtx == nil { | ||
| return nil, oops.C(oops.CodeUnauthorized) | ||
| } | ||
|
|
||
| rows, err := s.repo.ListPrincipalGrantsByOrg(ctx, repo.ListPrincipalGrantsByOrgParams{ | ||
| OrganizationID: authCtx.ActiveOrganizationID, | ||
| PrincipalUrn: conv.PtrValOr(payload.PrincipalUrn, ""), | ||
| }) | ||
| if err != nil { | ||
| return nil, oops.E(oops.CodeUnexpected, err, "list principal grants").Log(ctx, s.logger) | ||
| } | ||
|
|
||
| grants := make([]*gen.Grant, len(rows)) | ||
| for i, row := range rows { | ||
| grants[i] = grantFromRow(row) | ||
| } | ||
|
|
||
| return &gen.ListGrantsResult{Grants: grants}, nil | ||
| } |
There was a problem hiding this comment.
🚩 No authorization beyond authentication for RBAC management endpoints
All three access endpoints (ListGrants, UpsertGrant, RemoveGrants) only check that the user is authenticated (has a valid session with an active organization). There is no additional role-based check to verify the caller has permission to manage grants. This means any authenticated member of an organization can list, create, or delete RBAC grants for that organization. For an RBAC management service, this is a potentially sensitive design choice — typically only admins should be able to modify access control rules. Compare with other services in the codebase that may enforce additional authorization. This may be intentional for an initial implementation, but should be verified.
Was this helpful? React with 👍 or 👎 to provide feedback.
|
|
||
| Meta("openapi:operationId", "listGrants") | ||
| Meta("openapi:extension:x-speakeasy-name-override", "list") | ||
| Meta("openapi:extension:x-speakeasy-react-hook", `{"name": "ListGrants"}`) |
There was a problem hiding this comment.
| Meta("openapi:extension:x-speakeasy-react-hook", `{"name": "ListGrants"}`) | |
| Meta("openapi:extension:x-speakeasy-react-hook", `{"name": "Grants"}`) |
| Meta("openapi:extension:x-speakeasy-react-hook", `{"name": "ListGrants"}`) | ||
| }) | ||
|
|
||
| Method("upsertGrant", func() { |
There was a problem hiding this comment.
This would benefit from being an upsertGrants endpoint (plural) allowing batch upsert instead requiring one API call per grant
| security.SessionPayload() | ||
| }) | ||
|
|
||
| Result(Grant) |
There was a problem hiding this comment.
If you followed the advice above
| Result(Grant) | |
| Result(UpsertGrantsResult) |
and
var UpsertGrantsResult = Type("UpsertGrantsResult", func() {
Required("grants")
Attribute("grants", ArrayOf(Grant), "The list of grants that were added/changed.")
})
There was a problem hiding this comment.
Interestingly I think this service could be the first to have permission enforcement applied to it. Good testing ground before expanding this feature to other parts of Gram. Would suggest you try it out here.
| return nil, oops.C(oops.CodeUnauthorized) | ||
| } | ||
|
|
||
| principal, err := urn.ParsePrincipal(payload.PrincipalUrn) |
There was a problem hiding this comment.
You can probably set the type of payload.PrincipalUrn to urn.Principal in Goa designs.
Summary
accessGoa service with three RPC endpoints for managing principal grants (RBAC):listGrants— list grants for the active org, optionally filtered by principal URNupsertGrant— create-or-noop a grant for a (principal, scope, resource) tupleremoveGrants— remove all grants for a given principal in the orgContext
Builds on PR #1878 (merged) which added the
urn.Principaltype,principal_grantsSQLc queries, and generated repo code. This PR adds the HTTP API layer on top.Part of AGE-1566.
Notes
removeGrantsdeletes all grants for a principal (not individual grant rows)