fix(api): dedupe access_pairs and map invalid-id/unknown-perm to 4xx#1657
fix(api): dedupe access_pairs and map invalid-id/unknown-perm to 4xx#1657AmanGIT07 wants to merge 1 commit into
Conversation
Group successCheckPairs by resource id in ListProjectsByCurrentUser, ListServiceUserProjects, and ListCurrentUserGroups so each resource appears once. Resolve permissions once in fetchAccessPairsOnResource, drop unknown names and duplicate inputs. Validate Principal id in project.Service.List and service-user id in serviceuser.Service.Get and map the typed errors to InvalidArgument in the handlers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR tightens input validation across project and service-user services, adds permission resolution to filter unknown permissions, and updates API handler error mapping and access pair aggregation. Validation errors now return specific sentinel types instead of generic messages and map to InvalidArgument in gRPC responses. ChangesInput Validation and Permission Handling
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage Report for CI Build 26513272720Coverage increased (+0.2%) to 43.055%Details
Uncovered Changes
Coverage Regressions50 previously-covered lines in 1 file lost coverage.
Coverage Stats
💛 - Coveralls |
Sandbox RPC test resultsExercised the changed RPCs against a local Frontier built from this branch. Scaffold: one org with 3 projects, 1 group, 1 service user ( Listed deltas
Note on direct Additional behavioral checks
|
Summary
Three independent bugs in the project / service-user / current-user-groups listing handlers, and a bundled fix for the same
access_pairsduplication inListCurrentUserGroups.Fixes #1647.
1.
access_pairsduplicated per resourceListProjectsByCurrentUser,ListServiceUserProjects, andListCurrentUserGroupsemitted oneAccessPairper(resource, permission)CheckPairand inside each iteration filtered the full slice for the same resource id. With M permissions per resource that produced M copies of the same row.Fix: group
successCheckPairsby resource id once and emit one entry per resource.2. Unknown permission name returned 5xx / 404
fetchAccessPairsOnResourcecalledgetPermissionNameper(resource, permission)pair, which mappedpermission.ErrNotExisttoCodeNotFound.ListProjectsByCurrentUserthen re-wrapped everything asInternal;ListServiceUserProjectspassedNotFoundthrough. Both responses were wrong: the caller asked which of these permissions the principal holds; the answer for an unknown permission is "none".Fix: new
resolvePermissionNamehelper returns(name, ok, err).fetchAccessPairsOnResourceresolves each requested permission once, drops unknown names and duplicate inputs, and reservesInternalfor genuine repository failures.getPermissionNameis kept as a thin wrapper for callers that should reject unknown permissions (CheckResourcePermission,CheckFederatedResourcePermission,BatchCheckPermission).3. Empty / malformed
idreturned 5xx instead of 400After the
ListByUser→List(Filter{Principal})migration,project.Service.Listreturned an untypedfmt.Errorffor invalid principals; non-UUID ids flowed to the SQL layer and surfaced as generic DB errors. Both producedInternalin the handlers.ListServiceUserProjectshad the same shape via the interceptor'sGetServiceUsercall.Fix:
project.Service.Listreturnsproject.ErrInvalidUUIDfor empty/non-UUIDPrincipal.IDandproject.ErrInvalidPrincipalTypefor emptyPrincipal.Type.serviceuser.Service.Getrejects non-UUID ids withserviceuser.ErrInvalidID(consistent withuser.Service.Enable/Disable). TheGetServiceUserhandler mapsErrInvalidIDtoInvalidArgument, which propagates through the authorization interceptor.ListProjectsByUser,ListServiceUserProjectsmapproject.ErrInvalidUUID/project.ErrInvalidPrincipalTypetoInvalidArgument. The deaduser.ErrInvalidUUIDcase inListProjectsByUseris removed.RPCs and status-code changes
ListProjectsByCurrentUserwithPermissions=["update","delete"], N projectsaccess_pairsListProjectsByCurrentUserListServiceUserProjectsListServiceUserProjectsaccess_pairsListServiceUserProjectsidListProjectsByUseridGetServiceUseridListCurrentUserGroupsaccess_pairsListCurrentUserGroupsFrontend impact
None.
useOrganizationProjectsanduseOrganizationTeamsalready collapse the response viaacc[id] = permissions(last-write-wins). The pre-fix duplicate rows were identical, so old and new responses produce the same final map.ListServiceUserProjectsfrontend callers don't readaccess_pairs.Test plan
go test ./core/project/... ./core/serviceuser/... ./internal/api/v1beta1connect/...go vet ./...access_pairsrow per project forwithPermissions=["update","delete"]ListServiceUserProjectswith non-UUIDidreturns 400ListProjectsByCurrentUserwithwithPermissions=["bogus_perm"]returns 200 with emptyaccess_pairs🤖 Generated with Claude Code