Add complete system qualification evidence

This commit is contained in:
ms2k 2026-07-18 14:09:04 +09:00
commit 6952767503

View file

@ -47,6 +47,14 @@ pub async fn revoke_remora_grants() -> Result<(), String> {
}
}
pub async fn restore_remora_grants() -> Result<(), String> {
match required_env("REMORA_OIDC_PROVIDER").as_str() {
"keycloak" => restore_keycloak_remora_roles().await,
"zitadel" => restore_zitadel_remora_roles().await,
provider => Err(format!("unsupported OIDC provider {provider}")),
}
}
async fn mint_keycloak_token() -> Result<String, String> {
let response = Client::new()
.post(format!(
@ -262,6 +270,103 @@ async fn revoke_keycloak_remora_roles() -> Result<(), String> {
}
}
async fn restore_keycloak_remora_roles() -> Result<(), String> {
let realm = required_env("REMORA_OIDC_TENANT");
let client_id = required_env("REMORA_OIDC_CLIENT_ID");
let username = required_env("REMORA_OIDC_USERNAME");
let client = Client::new();
let admin_response = client
.post("http://keycloak.remora.test:8080/realms/master/protocol/openid-connect/token")
.form(&[
("grant_type", "password"),
("client_id", "admin-cli"),
("username", "remora-admin"),
("password", "synthetic-keycloak"),
])
.send()
.await
.map_err(|error| error.to_string())?;
let admin_body: Value = admin_response
.json()
.await
.map_err(|error| error.to_string())?;
let admin_token = admin_body["access_token"]
.as_str()
.ok_or_else(|| "keycloak admin token missing".to_owned())?;
let users: Value = client
.get(format!(
"http://keycloak.remora.test:8080/admin/realms/{realm}/users?username={username}&exact=true"
))
.bearer_auth(admin_token)
.send()
.await
.map_err(|error| error.to_string())?
.json()
.await
.map_err(|error| error.to_string())?;
let user_id = users
.as_array()
.and_then(|rows| rows.first())
.and_then(|row| row["id"].as_str())
.ok_or_else(|| "keycloak user missing".to_owned())?;
let clients: Value = client
.get(format!(
"http://keycloak.remora.test:8080/admin/realms/{realm}/clients?clientId={client_id}"
))
.bearer_auth(admin_token)
.send()
.await
.map_err(|error| error.to_string())?
.json()
.await
.map_err(|error| error.to_string())?;
let client_uuid = clients
.as_array()
.and_then(|rows| rows.first())
.and_then(|row| row["id"].as_str())
.ok_or_else(|| "keycloak client missing".to_owned())?;
let roles: Value = client
.get(format!(
"http://keycloak.remora.test:8080/admin/realms/{realm}/clients/{client_uuid}/roles"
))
.bearer_auth(admin_token)
.send()
.await
.map_err(|error| error.to_string())?
.json()
.await
.map_err(|error| error.to_string())?;
let storage_role = required_env("REMORA_OIDC_STORAGE_ROLE");
let roles = roles
.as_array()
.cloned()
.unwrap_or_default()
.into_iter()
.filter(|role| {
role["name"]
.as_str()
.is_some_and(|name| name == "remora:v1:admin" || name == storage_role)
})
.collect::<Vec<_>>();
let response = client
.post(format!(
"http://keycloak.remora.test:8080/admin/realms/{realm}/users/{user_id}/role-mappings/clients/{client_uuid}"
))
.bearer_auth(admin_token)
.json(&roles)
.send()
.await
.map_err(|error| error.to_string())?;
if response.status().is_success() {
Ok(())
} else {
Err(format!(
"keycloak role restore failed: {}",
response.status()
))
}
}
async fn revoke_zitadel_remora_roles() -> Result<(), String> {
let issuer = required_env("REMORA_OIDC_ISSUER");
let organization = required_env("REMORA_OIDC_TENANT");
@ -316,3 +421,64 @@ async fn revoke_zitadel_remora_roles() -> Result<(), String> {
))
}
}
async fn restore_zitadel_remora_roles() -> Result<(), String> {
let issuer = required_env("REMORA_OIDC_ISSUER");
let organization = required_env("REMORA_OIDC_TENANT");
let user_id = required_env("REMORA_OIDC_USER_ID");
let project_id = required_env("REMORA_OIDC_PROJECT_ID");
let token = required_env("REMORA_OIDC_MGMT_TOKEN");
let host = issuer
.strip_prefix("http://")
.or_else(|| issuer.strip_prefix("https://"))
.unwrap_or(&issuer);
let client = Client::new();
let grants: Value = client
.post(format!("{issuer}/management/v1/users/grants/_search"))
.header("Host", host)
.bearer_auth(&token)
.header("x-zitadel-orgid", &organization)
.json(&json!({ "queries": [{ "userIdQuery": { "userId": user_id } }] }))
.send()
.await
.map_err(|error| error.to_string())?
.json()
.await
.map_err(|error| error.to_string())?;
let grant_id = grants["result"]
.as_array()
.and_then(|rows| {
rows.iter().find(|row| {
row["projectId"]
.as_str()
.is_some_and(|value| value == project_id)
})
})
.and_then(|row| row["id"].as_str())
.ok_or_else(|| "zitadel project grant missing".to_owned())?;
let response = client
.put(format!(
"{issuer}/management/v1/users/{user_id}/grants/{grant_id}"
))
.header("Host", host)
.bearer_auth(token)
.header("x-zitadel-orgid", organization)
.json(&json!({
"roleKeys": [
"test-user",
"remora:v1:admin",
required_env("REMORA_OIDC_STORAGE_ROLE")
]
}))
.send()
.await
.map_err(|error| error.to_string())?;
if response.status().is_success() {
Ok(())
} else {
Err(format!(
"zitadel role restore failed: {}",
response.status()
))
}
}