Hardswap Invariants in tests + Quota fixes

This commit is contained in:
Alexey
2026-09-20 00:28:52 +03:00
parent 89dacbd17e
commit d706b3f3ba
66 changed files with 1821 additions and 505 deletions
+54 -15
View File
@@ -5,6 +5,22 @@ pub(in crate::api) async fn patch_user(
body: PatchUserRequest,
expected_revision: Option<String>,
shared: &ApiShared,
) -> Result<(UserInfo, String), ApiFailure> {
let shared = shared.clone();
let user = user.to_string();
shared
.clone()
.run_mutation_completion(async move {
patch_user_to_completion(&user, body, expected_revision, &shared).await
})
.await
}
async fn patch_user_to_completion(
user: &str,
body: PatchUserRequest,
expected_revision: Option<String>,
shared: &ApiShared,
) -> Result<(UserInfo, String), ApiFailure> {
let touches_users = body.secret.is_some();
let touches_user_ad_tags = !matches!(&body.user_ad_tag, Patch::Unchanged);
@@ -138,6 +154,19 @@ pub(in crate::api) async fn patch_user(
cfg.validate()
.map_err(|e| ApiFailure::bad_request(format!("config validation failed: {}", e)))?;
let staged_credential = if touches_users || touches_user_enabled {
let secret = cfg
.access
.users
.get(user)
.ok_or_else(|| ApiFailure::internal("updated user secret is missing"))?;
Some(
credential_id_from_hex(secret)
.ok_or_else(|| ApiFailure::internal("validated user secret could not be decoded"))?,
)
} else {
None
};
let mut touched_sections = Vec::new();
if touches_users {
@@ -176,16 +205,10 @@ pub(in crate::api) async fn patch_user(
)
.await?
};
if touches_users || touches_user_enabled {
let secret = cfg
.access
.users
.get(user)
.ok_or_else(|| ApiFailure::internal("updated user secret is missing"))?;
if let Some(credential_id) = staged_credential {
shared
.proxy_shared
.stage_user(user, secret, cfg.access.is_user_enabled(user))
.ok_or_else(|| ApiFailure::internal("failed to stage user admission policy"))?;
.stage_user_credential(user, credential_id, cfg.access.is_user_enabled(user));
}
match max_unique_ips_change {
Some(Some(limit)) => shared.ip_tracker.set_user_limit(user, limit).await,
@@ -216,6 +239,22 @@ pub(in crate::api) async fn set_user_enabled(
enabled: bool,
expected_revision: Option<String>,
shared: &ApiShared,
) -> Result<(UserInfo, String), ApiFailure> {
let shared = shared.clone();
let user = user.to_string();
shared
.clone()
.run_mutation_completion(async move {
set_user_enabled_to_completion(&user, enabled, expected_revision, &shared).await
})
.await
}
async fn set_user_enabled_to_completion(
user: &str,
enabled: bool,
expected_revision: Option<String>,
shared: &ApiShared,
) -> Result<(UserInfo, String), ApiFailure> {
let _guard = shared.mutation_lock.lock().await;
let (mut cfg, base_revision) =
@@ -237,6 +276,12 @@ pub(in crate::api) async fn set_user_enabled(
cfg.validate()
.map_err(|e| ApiFailure::bad_request(format!("config validation failed: {}", e)))?;
let credential_id = cfg
.access
.users
.get(user)
.and_then(|secret| credential_id_from_hex(secret))
.ok_or_else(|| ApiFailure::internal("validated user secret could not be decoded"))?;
let revision = save_access_sections_to_disk_if_revision(
&shared.config_path,
&cfg,
@@ -244,15 +289,9 @@ pub(in crate::api) async fn set_user_enabled(
Some(&base_revision),
)
.await?;
let secret = cfg
.access
.users
.get(user)
.ok_or_else(|| ApiFailure::internal("updated user secret is missing"))?;
shared
.proxy_shared
.stage_user(user, secret, enabled)
.ok_or_else(|| ApiFailure::internal("failed to stage user admission policy"))?;
.stage_user_credential(user, credential_id, enabled);
drop(_guard);
let (detected_ip_v4, detected_ip_v6) = shared.detected_link_ips();