release(secrets-mcp): 0.5.6
修复 OAuth 解绑时非法聚合 FOR UPDATE,Web OAuth 审计 IP 与 TRUST_PROXY 对齐并校验 IP,账号绑定写入 oauth_state 失败时回滚 bind 标记。回滚条目时恢复 folder/type,导入冲突检查在 DB 失败时传播错误,MCP delete/history 要求已登录用户,全局请求体 10MiB 限制。CI 部署支持 DEPLOY_KNOWN_HOSTS,默认 accept-new;文档与 deploy 示例补充连接池、限流、TRUST_PROXY。移除含明文凭据的 sync-test-to-prod 脚本。
This commit is contained in:
@@ -230,15 +230,6 @@ impl SecretsService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract user_id from the HTTP request parts injected by auth middleware.
|
||||
fn user_id_from_ctx(ctx: &RequestContext<RoleServer>) -> Result<Option<Uuid>, rmcp::ErrorData> {
|
||||
let parts = ctx
|
||||
.extensions
|
||||
.get::<http::request::Parts>()
|
||||
.ok_or_else(mcp_err_missing_http_parts)?;
|
||||
Ok(parts.extensions.get::<AuthUser>().map(|a| a.user_id))
|
||||
}
|
||||
|
||||
/// Get the authenticated user_id (returns error if not authenticated).
|
||||
fn require_user_id(ctx: &RequestContext<RoleServer>) -> Result<Uuid, rmcp::ErrorData> {
|
||||
let parts = ctx
|
||||
@@ -1142,7 +1133,7 @@ impl SecretsService {
|
||||
ctx: RequestContext<RoleServer>,
|
||||
) -> Result<CallToolResult, rmcp::ErrorData> {
|
||||
let t = Instant::now();
|
||||
let user_id = Self::user_id_from_ctx(&ctx)?;
|
||||
let user_id = Self::require_user_id(&ctx)?;
|
||||
|
||||
// Safety: require at least one filter.
|
||||
if input.id.is_none()
|
||||
@@ -1172,9 +1163,9 @@ impl SecretsService {
|
||||
if let Some(ref id_str) = input.id {
|
||||
let eid = parse_uuid(id_str)?;
|
||||
let uid = user_id;
|
||||
let entry = resolve_entry_by_id(&self.pool, eid, uid)
|
||||
let entry = resolve_entry_by_id(&self.pool, eid, Some(uid))
|
||||
.await
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_delete", uid, e))?;
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_delete", Some(uid), e))?;
|
||||
(Some(entry.name), Some(entry.folder))
|
||||
} else {
|
||||
(input.name.clone(), input.folder.clone())
|
||||
@@ -1187,11 +1178,11 @@ impl SecretsService {
|
||||
folder: effective_folder.as_deref(),
|
||||
entry_type: input.entry_type.as_deref(),
|
||||
dry_run: input.dry_run.unwrap_or(false),
|
||||
user_id,
|
||||
user_id: Some(user_id),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_delete", user_id, e))?;
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_delete", Some(user_id), e))?;
|
||||
|
||||
tracing::info!(
|
||||
tool = "secrets_delete",
|
||||
@@ -1218,7 +1209,7 @@ impl SecretsService {
|
||||
ctx: RequestContext<RoleServer>,
|
||||
) -> Result<CallToolResult, rmcp::ErrorData> {
|
||||
let t = Instant::now();
|
||||
let user_id = Self::user_id_from_ctx(&ctx)?;
|
||||
let user_id = Self::require_user_id(&ctx)?;
|
||||
tracing::info!(
|
||||
tool = "secrets_history",
|
||||
?user_id,
|
||||
@@ -1230,9 +1221,9 @@ impl SecretsService {
|
||||
let (resolved_name, resolved_folder): (String, Option<String>) =
|
||||
if let Some(ref id_str) = input.id {
|
||||
let eid = parse_uuid(id_str)?;
|
||||
let entry = resolve_entry_by_id(&self.pool, eid, user_id)
|
||||
let entry = resolve_entry_by_id(&self.pool, eid, Some(user_id))
|
||||
.await
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_history", user_id, e))?;
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_history", Some(user_id), e))?;
|
||||
(entry.name, Some(entry.folder))
|
||||
} else {
|
||||
(input.name.clone(), input.folder.clone())
|
||||
@@ -1243,10 +1234,10 @@ impl SecretsService {
|
||||
&resolved_name,
|
||||
resolved_folder.as_deref(),
|
||||
input.limit.unwrap_or(20),
|
||||
user_id,
|
||||
Some(user_id),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_history", user_id, e))?;
|
||||
.map_err(|e| mcp_err_internal_logged("secrets_history", Some(user_id), e))?;
|
||||
|
||||
tracing::info!(
|
||||
tool = "secrets_history",
|
||||
|
||||
Reference in New Issue
Block a user