fix(secrets-mcp 0.5.20): code review plan — export secret types, env map, rollback, API key, MCP tools, web session & validation

- Export/import: optional secret_types map; AddResult includes entry_id
- env_map: dot→__ segment encoding; collision errors
- rollback: FOR UPDATE + txn-consistent snapshot; restore name from history
- regenerate_api_key: rows_affected guard
- MCP: find count propagates errors; add uses entry_id for relations; rollback no encryption key
- Web: load_session_user_strict + JSON handlers key_version; PATCH length limits
- Tests: ExportEntry serde, env segment
This commit is contained in:
voson
2026-04-11 17:10:16 +08:00
parent 2c7dbf890b
commit d772066210
13 changed files with 266 additions and 141 deletions

View File

@@ -345,15 +345,6 @@ impl SecretsService {
Self::extract_enc_key(ctx)
}
/// Require both user_id and encryption key (header only, no arg fallback).
fn require_user_and_key(
ctx: &RequestContext<RoleServer>,
) -> Result<(Uuid, [u8; 32]), rmcp::ErrorData> {
let user_id = Self::require_user_id(ctx)?;
let key = Self::extract_enc_key(ctx)?;
Ok((user_id, key))
}
/// Require both user_id and encryption key, preferring an explicit argument
/// value over the X-Encryption-Key header.
fn require_user_and_key_or_arg(
@@ -801,10 +792,7 @@ impl SecretsService {
let total_count = secrets_core::service::search::count_entries(&self.pool, &count_params)
.await
.inspect_err(
|e| tracing::warn!(tool = "secrets_find", error = %e, "count_entries failed"),
)
.unwrap_or(0);
.map_err(|e| mcp_err_internal_logged("secrets_find", Some(user_id), e))?;
let relation_map = get_relations_for_entries(
&self.pool,
&result
@@ -1135,11 +1123,8 @@ impl SecretsService {
.await
.map_err(|e| mcp_err_from_anyhow("secrets_add", Some(user_id), e))?;
let created_entry = resolve_entry(&self.pool, &input.name, Some(folder), Some(user_id))
.await
.map_err(|e| mcp_err_internal_logged("secrets_add", Some(user_id), e))?;
for parent_id in parent_ids {
add_parent_relation(&self.pool, parent_id, created_entry.id, Some(user_id))
add_parent_relation(&self.pool, parent_id, result.entry_id, Some(user_id))
.await
.map_err(|e| mcp_err_from_anyhow("secrets_add", Some(user_id), e))?;
}
@@ -1420,7 +1405,7 @@ impl SecretsService {
}
#[tool(
description = "Rollback an entry to a previous version. Requires X-Encryption-Key header. \
description = "Rollback an entry to a previous version. Requires Bearer API key only (no encryption key). \
Omit to_version to restore the most recent snapshot. \
Optionally pass 'id' (from secrets_find) to target directly.",
annotations(title = "Rollback Secret Entry", destructive_hint = true)
@@ -1431,7 +1416,7 @@ impl SecretsService {
ctx: RequestContext<RoleServer>,
) -> Result<CallToolResult, rmcp::ErrorData> {
let t = Instant::now();
let (user_id, _user_key) = Self::require_user_and_key(&ctx)?;
let user_id = Self::require_user_id(&ctx)?;
tracing::info!(
tool = "secrets_rollback",
?user_id,