Skip to content

feat: CreateCurrentUserPAT RPC implementation#1401

Merged
AmanGIT07 merged 8 commits intomainfrom
feat/create-pat-rpc
Mar 6, 2026
Merged

feat: CreateCurrentUserPAT RPC implementation#1401
AmanGIT07 merged 8 commits intomainfrom
feat/create-pat-rpc

Conversation

@AmanGIT07
Copy link
Contributor

@AmanGIT07 AmanGIT07 commented Feb 20, 2026

Title: feat: add CreateCurrentUserPersonalToken RPC

Summary

  • Implements the CreateCurrentUserPAT RPC — the first endpoint for Personal Access Tokens (PATs), allowing users to create org-scoped tokens with configurable prefix, expiry, and metadata.
  • Adds full vertical slice: proto codegen, domain model, config, Postgres repository + migration, service layer with token generation (SHA-256 hashed, base64url-encoded), ConnectRPC handler, and authorization interceptor
    wiring.
  • Includes service-level audit logging
  • Adds SpiceDB constants in preparation for future policy integration.

@vercel
Copy link

vercel bot commented Feb 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Mar 6, 2026 11:07am

@coderabbitai
Copy link

coderabbitai bot commented Feb 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Personal Access Token (PAT) system: config, domain types, service logic, persistence (Postgres + migrations), API endpoints (Connect handlers, protobufs, validation), authorization and bootstrap changes, audit integration, and extensive tests and mocks.

Changes

Cohort / File(s) Summary
Build & Config
Makefile, pkg/server/config.go
Updated Proton commit hash in Makefile; added PAT config field to server Config.
Core PAT Domain
core/userpat/userpat.go, core/userpat/config.go, core/userpat/errors.go
Defined PAT type, Repository interface, Config with expiry/limits/prefix and helpers, and domain error variables.
Core PAT Service & Tests
core/userpat/service.go, core/userpat/service_test.go
Implemented userpat.Service with Create flow (validation, limits, role/policy handling, token generation, audit); comprehensive unit tests.
Core PAT Mocks
core/userpat/mocks/*
Generated testify mocks for repository, role/org/policy services, and audit repo.
API Wiring & Dependencies
cmd/serve.go, internal/api/api.go
Instantiated Postgres UserPATRepository and userpat.Service; exposed UserPATService in API dependencies.
Connect API & Mocks
internal/api/v1beta1connect/interfaces.go, internal/api/v1beta1connect/user_pat.go, internal/api/v1beta1connect/user_pat_test.go, internal/api/v1beta1connect/mocks/*, internal/api/v1beta1connect/v1beta1connect.go
Added UserPATService interface, Connect handler CreateCurrentUserPAT, handler tests, transformer to protobuf PAT, and generated mocks and connect wiring.
Authorization & Interceptors
pkg/server/connect_interceptors/authorization.go
Added authorization rule for CreateCurrentUserPAT referencing organization permission check.
Postgres: Model, Repo, Tests, Migrations
internal/store/postgres/userpat.go, internal/store/postgres/userpat_repository.go, internal/store/postgres/userpat_repository_test.go, internal/store/postgres/migrations/20260218100000_create_user_pats.*.sql, internal/store/postgres/postgres.go
Added user_pats model, repository with Create and CountActive, tests, table migration (indexes, trigger), and TABLE_USER_PATS constant.
Policy/Grant Relation Changes & Migrations
core/policy/policy.go, core/policy/service.go, internal/store/postgres/migrations/20260226100000_add_grant_relation_to_policies.*.sql, internal/store/postgres/policy*.go
Added GrantRelation field to policies, persisted via DB changes and repository updates, and validation/enforcement in policy service.
Role Service Adjustments & Tests
core/role/service.go, core/role/service_test.go
Extended role service to accept patDeniedPerms, create/delete PAT principal relations conditionally, updated tests and constructor signature.
Bootstrap & Schema Updates
internal/bootstrap/schema/base_schema.zed, internal/bootstrap/schema/schema.go, internal/bootstrap/generator.go, internal/bootstrap/service.go, internal/bootstrap/service_test.go, internal/bootstrap/testdata/compiled_schema.zed
Added app/pat entity, pat_granted relation, included PAT in bearer/permission logic, introduced relation service and PAT migration in bootstrap with tests.
Audit Integration
pkg/auditrecord/consts.go
Added PATCreatedEvent and PATType audit constants.
Protobufs & Validation & API Docs
proto/v1beta1/frontier.pb.validate.go, proto/v1beta1/models.pb.validate.go, proto/v1beta1/frontierv1beta1connect/frontier.connect.go, proto/apidocs.swagger.yaml
Added validation methods for request/response and PAT message; added RPC CreateCurrentUserPAT to connect surface; documented v1beta1PAT in swagger with token field.
Various Generated Mocks & Utilities
core/authenticate/mocks/*, core/userpat/mocks/*, internal/api/v1beta1connect/mocks/*
Added multiple autogenerated mocks used by new tests and handlers.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • rohilsurana
  • rsbh

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/bootstrap/schema/schema.go (1)

255-260: ⚠️ Potential issue | 🟡 Minor

Include PATPrincipal in IsSystemNamespace() for consistency with other principals.

All other principals—UserPrincipal, ServiceUserPrincipal, SuperUserPrincipal, GroupPrincipal—are included in the check, but PATPrincipal (defined at line 75) is omitted. Since PATPrincipal is recognized as a valid namespace alias in ParseNamespaceAliasIfRequired(), it should be treated the same way as other principals to maintain consistent behavior.

🧹 Nitpick comments (9)
pkg/auditrecord/consts.go (1)

57-58: Consider adding a PATDeletedEvent / PATRevokedEvent constant for completeness.

Every other audited resource with a lifecycle (service users, sessions, billing entities) has at minimum a deletion/revocation event alongside the creation event. If PAT revocation or deletion is planned, pre-declaring the constant here keeps the audit vocabulary consistent and avoids a follow-up PR solely to add "pat.deleted" or "pat.revoked".

♻️ Proposed addition
 	// PAT Events
 	PATCreatedEvent Event = "pat.created"
+	PATDeletedEvent Event = "pat.deleted"
core/userpat/errors.go (1)

1-14: LGTM — clean, idiomatic sentinel error set.

The var block with errors.New is the canonical Go pattern for package-level sentinel errors. All eight values are exported, clearly named with the Err prefix, and carry descriptive messages that unambiguously attribute them to the PAT domain. The distinction between ErrExpiryInPast (creation-time validation) and ErrExpiryExceeded (lifetime cap) is a nice touch.

One optional consideration: adding a short package prefix such as "userpat: personal access token not found" to each message can improve discoverability when these errors are wrapped and appear deep in a multi-layer error chain or log stream. Since "personal access token" already appears in every string, the attribution is already clear—this is purely a style preference.

cmd/serve.go (1)

391-436: userPATRepo declaration is separated from userPATService creation by ~45 unrelated lines.

Every other repo/service pair in this function is declared back-to-back (e.g., prospectRepository/prospectService at lines 388-389). Moving userPATRepo immediately before userPATService would keep the locality consistent.

♻️ Suggested repositioning
-	userPATRepo := postgres.NewUserPATRepository(dbc)
-
 	svUserRepo := postgres.NewServiceUserRepository(dbc)
 	// ... (lines 393-435 unchanged) ...
 
 	organizationService := organization.NewService(...)
+
+	userPATRepo := postgres.NewUserPATRepository(dbc)
 	userPATService := userpat.NewService(userPATRepo, cfg.App.PAT, organizationService, auditRecordRepository)
core/userpat/config.go (1)

10-10: DefaultTokenLifetime has no DefaultExpiry() helper to match MaxExpiry().

Any code that needs the parsed default lifetime must replicate the time.ParseDuration + fallback logic inline, risking divergence. Adding a symmetric helper ensures consistent parsing behaviour.

♻️ Proposed addition
+func (c Config) DefaultExpiry() time.Duration {
+	d, err := time.ParseDuration(c.DefaultTokenLifetime)
+	if err != nil {
+		return 90 * 24 * time.Hour // matches the "2160h" default
+	}
+	return d
+}
internal/api/v1beta1connect/user_pat.go (1)

84-89: Silently swallowed metadata conversion error may hide data loss.

If ToStructPB() fails (e.g., due to unsupported value types in metadata), the error is ignored and metadata is silently omitted from the response. Consider logging the error so operators can diagnose missing metadata.

🔧 Proposed fix
 	if pat.Metadata != nil {
 		metaPB, err := pat.Metadata.ToStructPB()
 		if err == nil {
 			pbPAT.Metadata = metaPB
+		} else {
+			// Log metadata conversion failure so it's diagnosable
+			zap.L().Warn("failed to convert PAT metadata to protobuf", zap.String("pat_id", pat.ID), zap.Error(err))
 		}
 	}
core/userpat/service.go (2)

88-88: Roles and ProjectIDs are silently discarded

Both fields flow through CreateRequest, are passed into the audit metadata, but the TODO means no policies are created. Any caller relying on the returned token having the scoped access they requested will get an over-privileged (or under-privileged) token with no error surfaced.

Would you like me to open a tracking issue or scaffold the policy-creation step once the role/project model is available?


107-108: maps.Copy silently overwrites "user_id" if targetMetadata contains that key

maps.Copy copies all key/value pairs from src into dst; when a key in src is already present in dst, the value in dst is overwritten. If any future caller of createAuditRecord passes "user_id" inside targetMetadata, the explicitly set pat.UserID binding will be silently replaced. Build the merged map in the other order to give the explicit user_id precedence:

♻️ Proposed fix
-	metadata := map[string]any{"user_id": pat.UserID}
-	maps.Copy(metadata, targetMetadata)
+	metadata := maps.Clone(targetMetadata)
+	metadata["user_id"] = pat.UserID  // always authoritative
core/userpat/service_test.go (2)

272-301: "should hash the full token string" test case verifies nothing about the stored hash

The assertion — that sha256(tokenValue) produces a 64-character hex string — is trivially true for any non-empty input and carries zero coverage value. It does not capture SecretHash from the mock call or compare it to the token. TestService_Create_HashVerification (lines 428-458) already does the correct end-to-end hash verification. Consider removing this table case or replacing it with a comment referencing the standalone test.


353-372: Table case "should generate unique tokens on each call" makes only one Create call

Within the table loop body (lines 374-394) each case calls Create exactly once, so this case cannot demonstrate uniqueness. It reads as an ownership claim that the table runner doesn't fulfil. TestService_Create_UniqueTokens (lines 397-426) already covers uniqueness correctly. Rename this case to something that reflects its actual intent (e.g., "should succeed when count is 0") or remove it as a duplicate.

@coveralls
Copy link

coveralls commented Feb 20, 2026

Pull Request Test Coverage Report for Build 22760765153

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 372 of 445 (83.6%) changed or added relevant lines in 15 files are covered.
  • 2 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.6%) to 40.425%

Changes Missing Coverage Covered Lines Changed/Added Lines %
internal/api/v1beta1connect/v1beta1connect.go 0 1 0.0%
internal/api/v1beta1connect/user_pat.go 68 70 97.14%
internal/store/postgres/userpat.go 16 18 88.89%
internal/bootstrap/schema/schema.go 0 3 0.0%
pkg/server/connect_interceptors/authorization.go 0 4 0.0%
internal/bootstrap/service.go 27 32 84.38%
cmd/serve.go 0 8 0.0%
internal/store/postgres/userpat_repository.go 45 54 83.33%
core/role/service.go 17 34 50.0%
core/userpat/service.go 163 185 88.11%
Files with Coverage Reduction New Missed Lines %
core/role/service.go 1 49.52%
internal/bootstrap/service.go 1 14.29%
Totals Coverage Status
Change from base Build 22750894336: 0.6%
Covered Lines: 13968
Relevant Lines: 34553

💛 - Coveralls

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
internal/api/v1beta1connect/user_pat.go (2)

87-91: Log metadata serialisation failure in transformPATToPB instead of silently dropping it.

If ToStructPB() fails, the response silently returns nil metadata. A caller receiving a token with no metadata has no way to distinguish "empty metadata" from "serialisation error". At minimum, log at warn so it surfaces during debugging.

🛠️ Proposed fix
 	if pat.Metadata != nil {
 		metaPB, err := pat.Metadata.ToStructPB()
 		if err == nil {
 			pbPAT.Metadata = metaPB
+		} else {
+			// log and continue: the token is valid, only metadata rendering failed
+			// h.logger.Warn("failed to convert PAT metadata to protobuf", zap.Error(err))
 		}
 	}

32-46: Reuse expiresAt instead of calling .AsTime() twice.

request.Msg.GetExpiresAt().AsTime() is invoked at line 32 and again at line 46 inside the CreateRequest literal. Reuse the already-computed value.

🛠️ Proposed fix
 	expiresAt := request.Msg.GetExpiresAt().AsTime()
 	if !expiresAt.After(time.Now()) {
 		return nil, connect.NewError(connect.CodeInvalidArgument, userpat.ErrExpiryInPast)
 	}
 	if expiresAt.After(time.Now().Add(h.patConfig.MaxExpiry())) {
 		return nil, connect.NewError(connect.CodeInvalidArgument, userpat.ErrExpiryExceeded)
 	}

 	created, tokenValue, err := h.userPATService.Create(ctx, userpat.CreateRequest{
 		...
-		ExpiresAt:  request.Msg.GetExpiresAt().AsTime(),
+		ExpiresAt:  expiresAt,
 		...
 	})

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
core/userpat/config.go (1)

14-19: ⚠️ Potential issue | 🟡 Minor

Avoid silent fallback for invalid MaxLifetime.

Line 15–18 still masks bad duration config by defaulting to 365 days, which can unintentionally alter PAT lifetime policy.

#!/bin/bash
# Verify whether PAT config has explicit validation and where MaxExpiry is consumed.
rg -nP --type go 'func\s+\(c\s+Config\)\s+Validate\s*\('
rg -nP --type go '\bMaxExpiry\s*\('
rg -nP --type go '\bMaxLifetime\b|\bDefaultLifetime\b'
internal/api/v1beta1connect/user_pat.go (1)

44-59: ⚠️ Potential issue | 🟡 Minor

Move LogServiceError to the default case — expected errors pollute error logs.

LogServiceError fires unconditionally for all errors, so ErrDisabled, ErrConflict, and ErrLimitExceeded — all normal user-facing outcomes — generate error-level log entries. This degrades log signal and can trigger false alerts.

🛠️ Proposed fix
-	errorLogger.LogServiceError(ctx, request, "CreateCurrentUserPAT", err,
-		zap.String("user_id", principal.User.ID),
-		zap.String("org_id", request.Msg.GetOrgId()))
-
 	switch {
 	case errors.Is(err, userpat.ErrDisabled):
 		return nil, connect.NewError(connect.CodeFailedPrecondition, err)
 	case errors.Is(err, userpat.ErrConflict):
 		return nil, connect.NewError(connect.CodeAlreadyExists, err)
 	case errors.Is(err, userpat.ErrLimitExceeded):
 		return nil, connect.NewError(connect.CodeResourceExhausted, err)
 	default:
+		errorLogger.LogServiceError(ctx, request, "CreateCurrentUserPAT", err,
+			zap.String("user_id", principal.User.ID),
+			zap.String("org_id", request.Msg.GetOrgId()))
 		return nil, connect.NewError(connect.CodeInternal, ErrInternalServerError)
 	}
internal/store/postgres/userpat_repository_test.go (1)

10-10: ⚠️ Potential issue | 🟡 Minor

Update import to use dockertest v3.

The import path github.com/ory/dockertest references the old v2 version, but the project uses v3.10.0 (github.com/ory/dockertest/v3). This was flagged in a previous review and should be updated.

-	"github.com/ory/dockertest"
+	"github.com/ory/dockertest/v3"
🧹 Nitpick comments (6)
core/userpat/service_test.go (1)

35-36: Make audit expectations strict for successful create paths.

Line 35 marks AuditRecordRepository.Create as optional. That allows success tests to pass even if audit logging is skipped. For success-path helpers, require at least one audit call.

🛠️ Proposed fix
 	auditRepo := mocks.NewAuditRecordRepository(t)
 	auditRepo.On("Create", mock.Anything, mock.Anything).
-		Return(models.AuditRecord{}, nil).Maybe()
+		Return(models.AuditRecord{}, nil)
internal/api/v1beta1connect/user_pat.go (2)

31-33: Potential nil pointer dereference on GetExpiresAt().

If request.Msg.GetExpiresAt() returns nil, calling .AsTime() on it will return the zero time (0001-01-01), which then gets passed to ValidateExpiry. While this would fail the "expiry in future" check, it's cleaner to validate presence explicitly before conversion to provide a more specific error message.

🔧 Optional: explicit nil check for clearer error
+	if request.Msg.GetExpiresAt() == nil {
+		return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("expires_at is required"))
+	}
+
 	if err := h.userPATService.ValidateExpiry(request.Msg.GetExpiresAt().AsTime()); err != nil {
 		return nil, connect.NewError(connect.CodeInvalidArgument, err)
 	}

82-87: Metadata conversion error is silently swallowed.

If pat.Metadata.ToStructPB() fails, the error is ignored and metadata is simply omitted from the response. Consider logging a warning so operators can diagnose conversion issues.

🔧 Optional: log metadata conversion failure
 	if pat.Metadata != nil {
 		metaPB, err := pat.Metadata.ToStructPB()
-		if err == nil {
+		if err != nil {
+			// Consider logging: metadata conversion failed
+		} else {
 			pbPAT.Metadata = metaPB
 		}
 	}
internal/store/postgres/userpat_repository.go (1)

28-28: Consider using pointer receiver for consistency.

The Create method uses a value receiver (r UserPATRepository) while many Go codebases prefer pointer receivers for struct methods. This is a minor stylistic point; the current implementation works correctly since the struct only holds a pointer field.

♻️ Optional: use pointer receiver for consistency
-func (r UserPATRepository) Create(ctx context.Context, pat userpat.PAT) (userpat.PAT, error) {
+func (r *UserPATRepository) Create(ctx context.Context, pat userpat.PAT) (userpat.PAT, error) {

Apply the same change to CountActive on line 66.

internal/store/postgres/migrations/20260218100000_create_user_pats.up.sql (1)

15-24: Consider a composite index for CountActive query optimization.

The CountActive query filters by (user_id, org_id, deleted_at IS NULL, expires_at > now). The current idx_user_pats_expires_active index only covers expires_at, which may not be optimal.

The existing idx_user_pats_user_org_active on (user_id, org_id) WHERE deleted_at IS NULL should help, but adding expires_at to it could further optimize the count query.

💡 Optional: enhanced composite index
-- Replace idx_user_pats_user_org_active with a version that includes expires_at
CREATE INDEX idx_user_pats_user_org_expires_active 
ON user_pats(user_id, org_id, expires_at) WHERE deleted_at IS NULL;

This would allow the CountActive query to be fully covered by a single index scan.

core/userpat/service.go (1)

56-66: Minor: Two time.Now() calls may cause edge-case inconsistency.

The validation at lines 59 and 62 each call time.Now() separately. In an extremely rare edge case where the clock ticks between calls, a time that's exactly at the boundary could pass one check but fail the other. Consider capturing time.Now() once.

🔧 Optional: single time capture
 func (s *Service) ValidateExpiry(expiresAt time.Time) error {
-	if !expiresAt.After(time.Now()) {
+	now := time.Now()
+	if !expiresAt.After(now) {
 		return ErrExpiryInPast
 	}
-	if expiresAt.After(time.Now().Add(s.config.MaxExpiry())) {
+	if expiresAt.After(now.Add(s.config.MaxExpiry())) {
 		return ErrExpiryExceeded
 	}
 	return nil
 }

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f50b76 and 89ff6fe.

⛔ Files ignored due to path filters (3)
  • proto/v1beta1/frontier.pb.go is excluded by !**/*.pb.go
  • proto/v1beta1/frontier_grpc.pb.go is excluded by !**/*.pb.go
  • proto/v1beta1/models.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (22)
  • Makefile
  • core/userpat/config.go
  • core/userpat/mocks/repository.go
  • core/userpat/service.go
  • core/userpat/service_test.go
  • core/userpat/userpat.go
  • internal/api/v1beta1connect/interfaces.go
  • internal/api/v1beta1connect/mocks/user_pat_service.go
  • internal/api/v1beta1connect/user_pat.go
  • internal/api/v1beta1connect/user_pat_test.go
  • internal/api/v1beta1connect/v1beta1connect.go
  • internal/store/postgres/migrations/20260218100000_create_user_pats.down.sql
  • internal/store/postgres/migrations/20260218100000_create_user_pats.up.sql
  • internal/store/postgres/postgres.go
  • internal/store/postgres/userpat.go
  • internal/store/postgres/userpat_repository.go
  • internal/store/postgres/userpat_repository_test.go
  • pkg/server/connect_interceptors/authorization.go
  • proto/apidocs.swagger.yaml
  • proto/v1beta1/frontier.pb.validate.go
  • proto/v1beta1/frontierv1beta1connect/frontier.connect.go
  • proto/v1beta1/models.pb.validate.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • internal/api/v1beta1connect/interfaces.go
  • pkg/server/connect_interceptors/authorization.go
  • Makefile
  • internal/api/v1beta1connect/v1beta1connect.go
  • internal/store/postgres/postgres.go
  • internal/api/v1beta1connect/user_pat_test.go
  • core/userpat/mocks/repository.go

@AmanGIT07 AmanGIT07 changed the title feat: CreateCurrentUserPersonalToken RPC implementation feat: CreateCurrentUserPAT RPC implementation Feb 27, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
core/userpat/service_test.go (1)

203-204: Hardcoded expiry date will cause test flakiness after June 2026

The test uses a hardcoded time.Date(2026, 6, 1, ...) which will become a past date after June 2026. While a past review flagged this, the code still contains the hardcoded value. Consider using a relative timestamp:

stableExpiry := time.Now().UTC().Add(24 * time.Hour).Truncate(time.Second)

This applies to lines 203, 228-229, and 238-239.

internal/bootstrap/service.go (1)

270-304: Consider performance for large deployments.

The migration iterates all roles and all their permissions on every bootstrap. For deployments with many roles/permissions, this could impact startup time. The SpiceDB Touch semantics ensure correctness (idempotent creates), and Delete handles non-existent tuples gracefully.

This is acceptable for the initial implementation, but consider adding logging or metrics if bootstrap times become a concern.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2f2a99b0-2b76-4b4c-891b-73ef6d5d3e7b

📥 Commits

Reviewing files that changed from the base of the PR and between 89ff6fe and 7e05aea.

📒 Files selected for processing (25)
  • cmd/serve.go
  • core/authenticate/mocks/authenticator_func.go
  • core/policy/policy.go
  • core/policy/service.go
  • core/policy/service_test.go
  • core/role/service.go
  • core/role/service_test.go
  • core/userpat/config.go
  • core/userpat/errors.go
  • core/userpat/mocks/policy_service.go
  • core/userpat/mocks/role_service.go
  • core/userpat/service.go
  • core/userpat/service_test.go
  • internal/api/v1beta1connect/user_pat.go
  • internal/api/v1beta1connect/user_pat_test.go
  • internal/bootstrap/generator.go
  • internal/bootstrap/schema/base_schema.zed
  • internal/bootstrap/schema/schema.go
  • internal/bootstrap/service.go
  • internal/bootstrap/service_test.go
  • internal/bootstrap/testdata/compiled_schema.zed
  • internal/store/postgres/migrations/20260226100000_add_grant_relation_to_policies.down.sql
  • internal/store/postgres/migrations/20260226100000_add_grant_relation_to_policies.up.sql
  • internal/store/postgres/policy.go
  • internal/store/postgres/policy_repository.go

AmanGIT07 and others added 7 commits March 6, 2026 15:54
# Conflicts:
#	Makefile
#	pkg/server/config.go
#	proto/apidocs.swagger.yaml
#	proto/v1beta1/frontier.pb.go
#	proto/v1beta1/frontier_grpc.pb.go
#	proto/v1beta1/models.pb.go
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@AmanGIT07 AmanGIT07 merged commit 2f6d0cd into main Mar 6, 2026
8 checks passed
@AmanGIT07 AmanGIT07 deleted the feat/create-pat-rpc branch March 6, 2026 11:11
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.

3 participants