feat: configure auth channel mismatch formats

This commit is contained in:
fawney19
2026-05-03 00:49:22 +08:00
parent 3a770306cc
commit e3ea2d1451
63 changed files with 585 additions and 39 deletions

View File

@@ -470,6 +470,7 @@ CREATE TABLE IF NOT EXISTS public.provider_api_keys (
note character varying(500),
internal_priority integer DEFAULT 50,
rpm_limit integer,
concurrent_limit integer,
allowed_models json,
capabilities json,
learned_rpm_limit integer,
@@ -497,6 +498,7 @@ CREATE TABLE IF NOT EXISTS public.provider_api_keys (
provider_id character varying(36) NOT NULL,
api_formats json,
auth_type_by_format json,
allow_auth_channel_mismatch_formats json,
rate_multipliers json,
health_by_format jsonb,
circuit_breaker_by_format jsonb,

View File

@@ -0,0 +1,80 @@
ALTER TABLE public.provider_api_keys
ADD COLUMN IF NOT EXISTS allow_auth_channel_mismatch_formats json;
ALTER TABLE public.provider_api_keys
ADD COLUMN IF NOT EXISTS concurrent_limit integer;
CREATE OR REPLACE FUNCTION public.aether_default_auth_mismatch_api_format(value text)
RETURNS text
LANGUAGE sql
IMMUTABLE
AS $$
SELECT CASE LOWER(BTRIM(COALESCE(value, '')))
WHEN 'openai:cli' THEN 'openai:responses'
WHEN 'openai:compact' THEN 'openai:responses:compact'
WHEN 'claude:chat' THEN 'claude:messages'
WHEN 'claude:cli' THEN 'claude:messages'
WHEN 'gemini:chat' THEN 'gemini:generate_content'
WHEN 'gemini:cli' THEN 'gemini:generate_content'
ELSE LOWER(BTRIM(COALESCE(value, '')))
END
$$;
WITH supported_formats AS (
SELECT
pak.id,
public.aether_default_auth_mismatch_api_format(format.value) AS api_format,
0 AS source_priority,
MIN(format.ordinality) AS first_ordinality
FROM public.provider_api_keys AS pak
CROSS JOIN LATERAL json_array_elements_text(
CASE
WHEN pak.api_formats IS NOT NULL
AND json_typeof(pak.api_formats) = 'array'
THEN pak.api_formats
ELSE '[]'::json
END
) WITH ORDINALITY AS format(value, ordinality)
WHERE pak.api_formats IS NOT NULL
AND json_typeof(pak.api_formats) = 'array'
GROUP BY pak.id, api_format
UNION ALL
SELECT
pak.id,
public.aether_default_auth_mismatch_api_format(endpoint.api_format) AS api_format,
1 AS source_priority,
0 AS first_ordinality
FROM public.provider_api_keys AS pak
INNER JOIN public.provider_endpoints AS endpoint
ON endpoint.provider_id = pak.provider_id
WHERE pak.api_formats IS NULL
OR json_typeof(pak.api_formats) <> 'array'
),
deduplicated_formats AS (
SELECT
id,
api_format,
MIN(source_priority) AS source_priority,
MIN(first_ordinality) AS first_ordinality
FROM supported_formats
WHERE api_format <> ''
GROUP BY id, api_format
),
rebuilt AS (
SELECT
id,
json_agg(api_format ORDER BY source_priority, first_ordinality, api_format) AS api_formats
FROM deduplicated_formats
GROUP BY id
)
UPDATE public.provider_api_keys AS pak
SET
allow_auth_channel_mismatch_formats = rebuilt.api_formats,
updated_at = NOW()
FROM rebuilt
WHERE pak.id = rebuilt.id
AND pak.allow_auth_channel_mismatch_formats IS NULL;
DROP FUNCTION public.aether_default_auth_mismatch_api_format(text);

View File

@@ -8,7 +8,7 @@ use tracing::{error, info, warn};
static MIGRATOR: Migrator = sqlx::migrate!("./migrations");
static BASELINE_V2_SQL: &str = include_str!("../bootstrap/20260413020000_baseline_v2.sql");
const BASELINE_V2_CUTOFF_VERSION: i64 = 20260428000000;
const BASELINE_V2_CUTOFF_VERSION: i64 = 20260502000000;
const MIGRATIONS_TABLE_EXISTS_SQL: &str =
"SELECT to_regclass('public._sqlx_migrations') IS NOT NULL";
const PUBLIC_BASE_TABLE_COUNT_SQL: &str = r#"
@@ -665,6 +665,7 @@ SELECT EXISTS (
20260423000000,
20260424000000,
20260428000000,
20260502000000,
]
);
}
@@ -732,7 +733,20 @@ SELECT EXISTS (
.sql
.contains("api_formats json DEFAULT '[]'::json NOT NULL"));
assert!(BASELINE_V2_SQL.contains("api_formats json,"));
assert!(BASELINE_V2_SQL.contains("concurrent_limit integer,"));
assert!(BASELINE_V2_SQL.contains("allow_auth_channel_mismatch_formats json,"));
assert!(!BASELINE_V2_SQL.contains("api_formats json DEFAULT '[]'::json NOT NULL"));
let auth_mismatch_migration = MIGRATOR
.iter()
.find(|migration| migration.version == 20260502000000)
.expect("auth mismatch migration should be embedded");
assert!(auth_mismatch_migration
.sql
.contains("allow_auth_channel_mismatch_formats = rebuilt.api_formats"));
assert!(auth_mismatch_migration
.sql
.contains("pak.allow_auth_channel_mismatch_formats IS NULL"));
}
#[test]
@@ -1256,6 +1270,7 @@ ORDER BY id
20260423000000,
20260424000000,
20260428000000,
20260502000000,
]
);
}

View File

@@ -141,6 +141,7 @@ SELECT
is_active,
api_formats,
auth_type_by_format,
allow_auth_channel_mismatch_formats,
api_key,
auth_config,
note,
@@ -198,6 +199,7 @@ SELECT
is_active,
api_formats,
auth_type_by_format,
allow_auth_channel_mismatch_formats,
api_key,
auth_config,
note,
@@ -1234,7 +1236,8 @@ INSERT INTO provider_api_keys (
circuit_breaker_by_format,
is_active,
created_at,
updated_at
updated_at,
allow_auth_channel_mismatch_formats
) VALUES (
$1,
$2,
@@ -1310,7 +1313,8 @@ INSERT INTO provider_api_keys (
CASE
WHEN $51::double precision IS NULL THEN NOW()
ELSE TO_TIMESTAMP($51::double precision)
END
END,
$52
)
"#,
)
@@ -1373,7 +1377,7 @@ INSERT INTO provider_api_keys (
.bind(key.is_active)
.bind(key.created_at_unix_ms.map(|value| value as f64))
.bind(key.updated_at_unix_secs.map(|value| value as f64))
.bind(key.expires_at_unix_secs.map(|value| value as f64))
.bind(&key.allow_auth_channel_mismatch_formats)
.execute(&self.pool)
.await
.map_postgres_err()?;
@@ -1723,6 +1727,7 @@ SET
provider_id = $2,
api_formats = $3,
auth_type_by_format = $39,
allow_auth_channel_mismatch_formats = $40,
auth_type = $4,
api_key = $5,
auth_config = $6,
@@ -1818,6 +1823,7 @@ WHERE id = $1
.bind(key.updated_at_unix_secs.map(|value| value as f64))
.bind(key.expires_at_unix_secs.map(|value| value as f64))
.bind(&key.auth_type_by_format)
.bind(&key.allow_auth_channel_mismatch_formats)
.execute(&self.pool)
.await
.map_postgres_err()?
@@ -2479,6 +2485,8 @@ fn map_key_row(row: &PgRow) -> Result<StoredProviderCatalogKey, DataLayerError>
);
key.note = row.try_get("note").ok();
key.auth_type_by_format = row.try_get("auth_type_by_format").ok();
key.allow_auth_channel_mismatch_formats =
row.try_get("allow_auth_channel_mismatch_formats").ok();
key.internal_priority = row.try_get("internal_priority").unwrap_or(50);
key.cache_ttl_minutes = row.try_get("cache_ttl_minutes").unwrap_or(5);
key.max_probe_interval_minutes = row.try_get("max_probe_interval_minutes").unwrap_or(32);