release: secrets-mcp 0.5.2
Some checks failed
Secrets MCP — Build & Release / 检查 / 构建 / 发版 (push) Successful in 6m7s
Secrets MCP — Build & Release / 部署 secrets-mcp (push) Failing after 6s

Bump version: secrets-mcp-0.5.1 tag already existed while crates had further changes.

Made-with: Cursor
This commit is contained in:
2026-04-05 10:38:50 +08:00
parent aefad33870
commit dd24f7cc44
15 changed files with 787 additions and 66 deletions

View File

@@ -16,14 +16,17 @@ pub struct OAuthProfile {
/// Find or create a user from an OAuth profile.
/// Returns (user, is_new) where is_new indicates first-time registration.
pub async fn find_or_create_user(pool: &PgPool, profile: OAuthProfile) -> Result<(User, bool)> {
// Check if this OAuth account already exists
// Use a transaction with FOR UPDATE to prevent TOCTOU race conditions
let mut tx = pool.begin().await?;
// Check if this OAuth account already exists (with row lock)
let existing: Option<OauthAccount> = sqlx::query_as(
"SELECT id, user_id, provider, provider_id, email, name, avatar_url, created_at \
FROM oauth_accounts WHERE provider = $1 AND provider_id = $2",
FROM oauth_accounts WHERE provider = $1 AND provider_id = $2 FOR UPDATE",
)
.bind(&profile.provider)
.bind(&profile.provider_id)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if let Some(oa) = existing {
@@ -32,8 +35,9 @@ pub async fn find_or_create_user(pool: &PgPool, profile: OAuthProfile) -> Result
FROM users WHERE id = $1",
)
.bind(oa.user_id)
.fetch_one(pool)
.fetch_one(&mut *tx)
.await?;
tx.commit().await?;
return Ok((user, false));
}
@@ -43,8 +47,6 @@ pub async fn find_or_create_user(pool: &PgPool, profile: OAuthProfile) -> Result
.clone()
.unwrap_or_else(|| profile.email.clone().unwrap_or_else(|| "User".to_string()));
let mut tx = pool.begin().await?;
let user: User = sqlx::query_as(
"INSERT INTO users (email, name, avatar_url) \
VALUES ($1, $2, $3) \
@@ -125,13 +127,16 @@ pub async fn bind_oauth_account(
user_id: Uuid,
profile: OAuthProfile,
) -> Result<OauthAccount> {
// Check if this provider_id is already linked to someone else
// Use a transaction with FOR UPDATE to prevent TOCTOU race conditions
let mut tx = pool.begin().await?;
// Check if this provider_id is already linked to someone else (with row lock)
let conflict: Option<(Uuid,)> = sqlx::query_as(
"SELECT user_id FROM oauth_accounts WHERE provider = $1 AND provider_id = $2",
"SELECT user_id FROM oauth_accounts WHERE provider = $1 AND provider_id = $2 FOR UPDATE",
)
.bind(&profile.provider)
.bind(&profile.provider_id)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if let Some((existing_user_id,)) = conflict {
@@ -148,11 +153,11 @@ pub async fn bind_oauth_account(
}
let existing_provider_for_user: Option<(String,)> = sqlx::query_as(
"SELECT provider_id FROM oauth_accounts WHERE user_id = $1 AND provider = $2",
"SELECT provider_id FROM oauth_accounts WHERE user_id = $1 AND provider = $2 FOR UPDATE",
)
.bind(user_id)
.bind(&profile.provider)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if existing_provider_for_user.is_some() {
@@ -174,9 +179,10 @@ pub async fn bind_oauth_account(
.bind(&profile.email)
.bind(&profile.name)
.bind(&profile.avatar_url)
.fetch_one(pool)
.fetch_one(&mut *tx)
.await?;
tx.commit().await?;
Ok(account)
}