Skip to content

feat: implement RegenerateCurrentUserPAT RPC#1468

Merged
AmanGIT07 merged 5 commits intomainfrom
feat/regenerate-current-user-pat
Mar 23, 2026
Merged

feat: implement RegenerateCurrentUserPAT RPC#1468
AmanGIT07 merged 5 commits intomainfrom
feat/regenerate-current-user-pat

Conversation

@AmanGIT07
Copy link
Copy Markdown
Contributor

Description:

Summary

  • Add RegenerateCurrentUserPAT RPC that creates a new secret and updates expiry for an existing PAT
  • Scope (roles, projects) and SpiceDB policies are preserved — only secret_hash and expires_at change in Postgres
  • Expired PATs can be regenerated; active count limit is checked when reviving an expired PAT

Changes

  • Proto: RegenerateCurrentUserPAT RPC, request (UUID-validated id, required expires_at), response with PAT (includes new plaintext token)
  • Repository: Regenerate method — updates secret_hash + expires_at via RETURNING, handles ErrNotFound
  • Service: Regenerate method — ownership check, expiry validation, limit check for expired PATs, new secret generation, audit record
  • Handler: principal auth, validation, error mapping (FailedPrecondition/NotFound/ResourceExhausted/InvalidArgument/Internal)
  • Authorization: added to skip endpoints (ownership enforced in service layer)
  • Audit: added PATRegeneratedEvent with expires_at and old_expires_at in metadata
  • Tests: 9 service test cases, 8 handler test cases

Design decisions

  • In-place update: Scope doesn't change, so policies and SpiceDB tuples stay untouched.
  • Expired PATs allowed: GetByID doesn't filter by expiry (only deleted_at), so expired PATs can be regenerated.
  • Limit check only for expired PATs: regenerating an active PAT doesn't change the active count. Reviving an expired PAT increases it, so limit is checked only in that case.

Manual test verification

  • PAT secret-hash and expiry updated correctly in Postgres after RPC call.
  • Invalid inputs (non-existent PAT, invalid expiry etc) return appropriate error codes
  • Audit record created with pat.regenerated event, including old and new expiry date
  • API calls using the old secret returns unauthenticated.
  • API calls with new secret works as per scope.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 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 23, 2026 7:10am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 20, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Regenerate Personal Access Tokens: Users can now refresh existing tokens with a new secret and expiration date while preserving their current role and project scope permissions.
    • New token regeneration endpoint: Supports automated token rotation and expiration management without requiring token deletion and recreation. All regeneration events are audited for security and compliance tracking.

Walkthrough

This PR introduces PAT regeneration functionality by extending the repository interface with a Regenerate method, implementing service-layer logic with validation and audit recording, adding a new Connect handler endpoint with error mapping, and including corresponding proto messages, mocks, and tests. The Proton version in the Makefile is also updated.

Changes

Cohort / File(s) Summary
Build & Infrastructure
Makefile
Updated PROTON_COMMIT variable to a new git commit hash for Proton archive.
Repository Interface & Mocks
core/userpat/userpat.go, core/userpat/mocks/repository.go
Added Regenerate(ctx, id, secretHash, expiresAt) method to the Repository interface and corresponding mock implementation with call tracking and return value helpers.
Repository Implementation
internal/store/postgres/userpat_repository.go
Implemented Regenerate method performing SQL UPDATE to set secret_hash and expires_at, with error mapping for NoRows, DuplicateKey, and database errors.
Service Layer
core/userpat/service.go, core/userpat/service_test.go
Added Service.Regenerate method with validation (enablement, ownership, expiry), active-count enforcement for expired PATs, secret generation, persistence, scope enrichment, and audit recording; comprehensive table-driven test covering all error paths and success cases.
API Service Interface & Mocks
internal/api/v1beta1connect/interfaces.go, internal/api/v1beta1connect/mocks/user_pat_service.go
Extended UserPATService interface with Regenerate method and added corresponding mock with call tracking and expectation helpers.
Connect Handler
internal/api/v1beta1connect/user_pat.go, internal/api/v1beta1connect/user_pat_test.go
Implemented RegenerateCurrentUserPAT handler with authentication validation, request validation including non-nil expires_at check, service invocation, and comprehensive error-to-Connect code mapping; added test suite covering authentication, validation, all error conditions, and success case.
Proto Messages & Validation
proto/v1beta1/frontier.pb.validate.go
Added Validate() and ValidateAll() methods for RegenerateCurrentUserPATRequest and RegenerateCurrentUserPATResponse, including UUID validation for request ID and embedded message validation, with MultiError and ValidationError types.
Proto Connect Procedures
proto/v1beta1/frontierv1beta1connect/frontier.connect.go
Added RegenerateCurrentUserPAT RPC procedure with client/handler implementations, unimplemented stub, and HTTP route dispatch.
Audit & Authorization
pkg/auditrecord/consts.go, pkg/server/connect_interceptors/authorization.go
Added PATRegeneratedEvent constant to audit record events; updated authorization skip list to include the new RegenerateCurrentUserPAT endpoint.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • whoAbhishekSah
  • rohilsurana

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.

@coveralls
Copy link
Copy Markdown

coveralls commented Mar 20, 2026

Pull Request Test Coverage Report for Build 23425613145

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

  • 64 of 106 (60.38%) changed or added relevant lines in 3 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.08%) to 41.032%

Changes Missing Coverage Covered Lines Changed/Added Lines %
core/userpat/service.go 32 38 84.21%
internal/api/v1beta1connect/user_pat.go 32 40 80.0%
internal/store/postgres/userpat_repository.go 0 28 0.0%
Totals Coverage Status
Change from base Build 23425182386: 0.08%
Covered Lines: 14550
Relevant Lines: 35460

💛 - Coveralls

Copy link
Copy Markdown
Contributor

@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: 3

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

2148-2371: Strengthen regenerate tests with return-value and boundary assertions.
Current success cases only verify err == nil; please also assert returned PAT fields/token and add a case where existing expiry is exactly now to lock the active-limit boundary behavior.

internal/api/v1beta1connect/user_pat_test.go (1)

1169-1252: Add explicit coverage for ErrExpiryExceeded mapping.
RegenerateCurrentUserPAT maps both expiry errors to CodeInvalidArgument; this suite currently asserts only ErrExpiryInPast.

core/userpat/service.go (1)

167-183: Consider documenting or hardening the count-then-regenerate race window.
CountActive + Regenerate is non-atomic, so concurrent revivals can exceed MaxPerUserPerOrg. Create already documents a similar TOCTOU risk; this path should get equivalent treatment (comment or atomic DB guard strategy).


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dfed0060-a853-4392-ac7f-108e4a9ee92b

📥 Commits

Reviewing files that changed from the base of the PR and between 2b9782b and c59cff6.

⛔ Files ignored due to path filters (1)
  • proto/v1beta1/frontier.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (14)
  • Makefile
  • 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/store/postgres/userpat_repository.go
  • pkg/auditrecord/consts.go
  • pkg/server/connect_interceptors/authorization.go
  • proto/v1beta1/frontier.pb.validate.go
  • proto/v1beta1/frontierv1beta1connect/frontier.connect.go

Base automatically changed from feat/update-current-user-pat to main March 23, 2026 06:54
@AmanGIT07 AmanGIT07 enabled auto-merge (squash) March 23, 2026 07:09
@AmanGIT07 AmanGIT07 merged commit 6f1b83f into main Mar 23, 2026
7 of 8 checks passed
@AmanGIT07 AmanGIT07 deleted the feat/regenerate-current-user-pat branch March 23, 2026 07:14
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