merge: 同步主线并解决用户侧验证冲突

This commit is contained in:
Entropy.Xu
2026-05-16 01:25:42 +08:00
349 changed files with 1737 additions and 73751 deletions

View File

@@ -1490,11 +1490,12 @@ pub fn admin_system_config_default_value(key: &str) -> Option<serde_json::Value>
"provider_priority_mode" => Some(json!("provider")),
"scheduling_mode" => Some(json!("cache_affinity")),
"auto_delete_expired_keys" => Some(json!(false)),
"turnstile_enabled" => Some(json!(false)),
"turnstile_site_key" => Some(serde_json::Value::Null),
"turnstile_secret_key" => Some(serde_json::Value::Null),
"turnstile_allowed_hostnames" => Some(json!([])),
"email_suffix_mode" => Some(json!("none")),
"email_suffix_list" => Some(json!([])),
"turnstile_enabled" => Some(json!(false)),
"turnstile_site_key" => Some(json!("")),
"turnstile_allowed_hostnames" => Some(json!([])),
"enable_format_conversion" => Some(json!(false)),
"enable_model_directives" => Some(json!(false)),
"model_directives" => Some(json!({
@@ -2825,6 +2826,20 @@ mod tests {
assert!(is_sensitive_admin_system_config_key("smtp_password"));
assert!(is_sensitive_admin_system_config_key("SMTP_PASSWORD"));
assert!(is_sensitive_admin_system_config_key("turnstile_secret_key"));
assert!(is_sensitive_admin_system_config_key("TURNSTILE_SECRET_KEY"));
assert!(!is_sensitive_admin_system_config_key("site_name"));
}
#[test]
fn build_admin_system_config_detail_masks_turnstile_secret_key() {
let payload = build_admin_system_config_detail_payload(
"turnstile_secret_key",
Some(json!("encrypted-turnstile-secret")),
)
.expect("turnstile secret detail should build");
assert_eq!(payload["key"], "turnstile_secret_key");
assert_eq!(payload["value"], serde_json::Value::Null);
assert_eq!(payload["is_set"], json!(true));
}
}

View File

@@ -0,0 +1 @@
ALTER TYPE public.userrole ADD VALUE IF NOT EXISTS 'audit_admin';

View File

@@ -91,6 +91,7 @@ END $mig$;
DO $mig$ BEGIN
CREATE TYPE public.userrole AS ENUM (
'admin',
'audit_admin',
'user'
);
EXCEPTION WHEN duplicate_object THEN NULL;

View File

@@ -7,7 +7,7 @@ use tracing::info;
// Generated by build.rs from schema/bootstrap/postgres.
pub(crate) static EMPTY_DATABASE_SNAPSHOT_SQL: &str =
include_str!(concat!(env!("OUT_DIR"), "/empty_database_snapshot.sql"));
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260512110000;
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260515000000;
const PUBLIC_BASE_TABLE_COUNT_SQL: &str = r#"
SELECT COUNT(*)::BIGINT

View File

@@ -304,12 +304,14 @@ fn empty_database_snapshot_covers_current_cutoff_versions() {
20260512000000,
20260512090000,
20260512110000,
20260515000000,
]
);
}
#[test]
fn empty_database_snapshot_sql_includes_usage_body_blobs() {
fn empty_database_snapshot_sql_includes_usage_body_blobs_and_audit_admin_role() {
assert!(EMPTY_DATABASE_SNAPSHOT_SQL.contains("'audit_admin'"));
assert!(
EMPTY_DATABASE_SNAPSHOT_SQL.contains("CREATE TABLE IF NOT EXISTS public.usage_body_blobs")
);
@@ -1116,6 +1118,7 @@ fn pending_migrations_from_applied_skips_versions_already_applied() {
20260512000000,
20260512090000,
20260512110000,
20260515000000,
]
);
}
@@ -1443,6 +1446,17 @@ async fn prepare_database_for_startup_bootstraps_clean_database() {
.await
.expect("api_keys.total_tokens lookup should succeed"));
let audit_admin_exists: bool = query_scalar(
"SELECT EXISTS (SELECT 1 FROM pg_enum WHERE enumtypid = 'public.userrole'::regtype AND enumlabel = 'audit_admin')",
)
.fetch_one(&pool)
.await
.expect("public.userrole audit_admin lookup should succeed");
assert!(
audit_admin_exists,
"fresh database snapshot should include public.userrole.audit_admin"
);
let applied_count: i64 = query_scalar("SELECT COUNT(*)::BIGINT FROM public._sqlx_migrations")
.fetch_one(&pool)
.await

View File

@@ -136,7 +136,7 @@ fn lifecycle_status_and_billing(event_type: UsageEventType) -> (&'static str, &'
UsageEventType::Streaming => ("streaming", "pending"),
UsageEventType::Completed => ("completed", "pending"),
UsageEventType::Failed => ("failed", "void"),
UsageEventType::Cancelled => ("cancelled", "void"),
UsageEventType::Cancelled => ("cancelled", "pending"),
}
}
@@ -181,6 +181,30 @@ mod tests {
assert_eq!(record.finalized_at_unix_secs, Some(1_700_000_000));
}
#[test]
fn cancelled_terminal_event_remains_billable() {
let record = build_upsert_usage_record_from_event(&UsageEvent {
event_type: UsageEventType::Cancelled,
request_id: "req-cancelled-1".to_string(),
timestamp_ms: 1_700_000_000_000,
data: UsageEventData {
user_id: Some("user-cancelled-1".to_string()),
provider_name: "OpenAI".to_string(),
model: "gpt-5".to_string(),
input_tokens: Some(10),
output_tokens: Some(4),
total_tokens: Some(14),
status_code: Some(499),
..UsageEventData::default()
},
})
.expect("record should build");
assert_eq!(record.status, "cancelled");
assert_eq!(record.billing_status, "pending");
assert_eq!(record.total_tokens, Some(14));
}
#[test]
fn sanitizes_request_metadata_before_building_upsert_record() {
let record = build_upsert_usage_record_from_event(&UsageEvent {