use schemars::{Schema, SchemaGenerator, json_schema};
use serde::{Deserialize, Serialize};
use crate::auth::PrincipalKindTag;
pub const REASON_MAX_BYTES: u32 = 1_024;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[cfg_attr(feature = "server", derive(utoipa::ToSchema))]
#[serde(deny_unknown_fields)]
pub struct RevokePrincipalRequest {
pub principal_kind: PrincipalKindTag,
#[schemars(schema_with = "reason_schema")]
pub reason: String,
}
fn reason_schema(_gen: &mut SchemaGenerator) -> Schema {
json_schema!({ "type": "string", "minLength": 1, "maxLength": REASON_MAX_BYTES })
}
#[cfg(test)]
mod tests {
use super::RevokePrincipalRequest;
use crate::auth::PrincipalKindTag;
#[test]
fn revoke_principal_request_roundtrips() {
let request = RevokePrincipalRequest {
principal_kind: PrincipalKindTag::Service,
reason: "operator requested rotation".to_owned(),
};
let value = serde_json::to_value(&request).expect("serializes");
assert_eq!(value["principal_kind"], "service");
assert_eq!(
serde_json::from_value::<RevokePrincipalRequest>(value).expect("deserializes"),
request
);
}
#[test]
fn revoke_principal_request_requires_kind_and_reason() {
let missing_kind = serde_json::json!({ "reason": "incident response" });
let missing_reason = serde_json::json!({ "principal_kind": "user" });
assert!(serde_json::from_value::<RevokePrincipalRequest>(missing_kind).is_err());
assert!(serde_json::from_value::<RevokePrincipalRequest>(missing_reason).is_err());
}
#[test]
fn revoke_principal_request_rejects_unknown_fields() {
let request = serde_json::json!({
"principal_kind": "agent",
"reason": "incident response",
"extra": true
});
assert!(serde_json::from_value::<RevokePrincipalRequest>(request).is_err());
}
}