Skip to content

fix: enforce case-insensitive PAT title uniqueness#1489

Merged
AmanGIT07 merged 1 commit intomainfrom
fix/enforce-case-insensitive-PAT-title-uniqueness
Mar 31, 2026
Merged

fix: enforce case-insensitive PAT title uniqueness#1489
AmanGIT07 merged 1 commit intomainfrom
fix/enforce-case-insensitive-PAT-title-uniqueness

Conversation

@AmanGIT07
Copy link
Copy Markdown
Contributor

Description:

Summary

  • Replace case-sensitive unique index on PAT titles with case-insensitive one using LOWER(title)
  • Aligns the DB constraint with the CheckCurrentUserPATTitle RPC which already checks case-insensitively

Problem

The PAT title uniqueness has a mismatch between the availability check and the database constraint:

  • Availability check (CheckCurrentUserPATTitle RPC): Uses LOWER(title) — treats "Token" and "token" as the same title
  • Database unique index: Uses raw title — treats "Token" and "token" as different titles

This means:

  1. User checks "Token" availability → API says "taken" (because "token" exists)
  2. User tries a different title, but a direct API caller could still create "Token" bypassing the check
  3. Two PATs with titles "Token" and "token" can coexist in the same user+org, which is confusing

The fix aligns the DB constraint with the availability check by making both case-insensitive.

Pre-migration check

Run before applying to ensure no existing case-insensitive duplicates:

  SELECT user_id, org_id, LOWER(title), COUNT(*)
  FROM user_pats WHERE deleted_at IS NULL
  GROUP BY user_id, org_id, LOWER(title)
  HAVING COUNT(*) > 1;

If any results, manually rename duplicates before running the migration.

Changes

  • internal/store/postgres/migrations/20260330100000_user_pats_title_case_insensitive.up.sql — replaces index with LOWER(title) version
  • internal/store/postgres/migrations/20260330100000_user_pats_title_case_insensitive.down.sql — reverts to case-sensitive index

Test plan

  • Run pre-migration check query — confirm no duplicates
  • Apply migration: go run . server migrate
  • Verify: CREATE PAT("Token") then CREATE PAT("token") for same user+org → duplicate key error
  • Verify: CheckCurrentUserPATTitle("token") returns false when "Token" exists

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

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

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Personal access token titles are now case-insensitive, ensuring consistent handling across different character cases.

Walkthrough

Introduces a PostgreSQL migration to modify the uniqueness constraint on user PAT titles. The up migration replaces the case-sensitive unique index with a case-insensitive version using the LOWER() function, while the down migration reverts this change.

Changes

Cohort / File(s) Summary
User PAT Uniqueness Index Migration
internal/store/postgres/migrations/20260330100000_user_pats_title_case_insensitive.up.sql, internal/store/postgres/migrations/20260330100000_user_pats_title_case_insensitive.down.sql
Bidirectional migration pair: up migration replaces case-sensitive unique index with case-insensitive variant using LOWER(title); down migration reverts to original case-sensitive index. Both maintain partial uniqueness constraint on (user_id, org_id, title) for non-deleted records.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~4 minutes

Suggested reviewers

  • rsbh

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
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: 1

🧹 Nitpick comments (1)
internal/store/postgres/migrations/20260330100000_user_pats_title_case_insensitive.up.sql (1)

2-3: The drop-then-create pattern is safe due to implicit transaction wrapping, but a safer approach is still recommended.

In this codebase, migrations using golang-migrate/v4 with PostgreSQL execute multiple semicolon-separated statements within an implicit single transaction. The two statements in this migration (DROP and CREATE) will be atomic, so the index will not be left in an unprotected state if the CREATE fails.

However, the suggested approach (CREATE with a temporary name first, then DROP the old index, then RENAME) remains preferable because it:

  • Validates the new index can be built before removing the old one
  • Eliminates the brief intermediate state where the constraint doesn't exist, even if transactional
  • Is more resilient to future framework or implementation changes

The actual risk here is data validation: if existing data contains case-insensitive duplicates (e.g., records with titles "Test" and "test" for the same user_id and org_id), the CREATE UNIQUE INDEX will fail and the migration will be marked dirty. Verify no such duplicates exist before deploying.

Safer migration ordering
--- Replace case-sensitive unique index with case-insensitive one
-DROP INDEX IF EXISTS idx_user_pats_unique_title;
-CREATE UNIQUE INDEX idx_user_pats_unique_title ON user_pats(user_id, org_id, LOWER(title)) WHERE deleted_at IS NULL;
+CREATE UNIQUE INDEX idx_user_pats_unique_title_ci
+  ON user_pats(user_id, org_id, LOWER(title))
+  WHERE deleted_at IS NULL;
+DROP INDEX IF EXISTS idx_user_pats_unique_title;
+ALTER INDEX idx_user_pats_unique_title_ci RENAME TO idx_user_pats_unique_title;

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f7a12ad3-b652-4464-a653-c199c91aff39

📥 Commits

Reviewing files that changed from the base of the PR and between 6d3f564 and 78836b1.

📒 Files selected for processing (2)
  • internal/store/postgres/migrations/20260330100000_user_pats_title_case_insensitive.down.sql
  • internal/store/postgres/migrations/20260330100000_user_pats_title_case_insensitive.up.sql

@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 23743518746

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 41.668%

Totals Coverage Status
Change from base Build 23742561695: 0.0%
Covered Lines: 15048
Relevant Lines: 36114

💛 - Coveralls

@AmanGIT07 AmanGIT07 merged commit 2d8d0cc into main Mar 31, 2026
8 checks passed
@AmanGIT07 AmanGIT07 deleted the fix/enforce-case-insensitive-PAT-title-uniqueness branch March 31, 2026 07:04
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