use crate::client::AgentTrustClient;
use crate::error::Result;
use crate::models::{
IssueWIMSETokenRequest, VerifyWIMSETokenRequest, VerifyWIMSETokenResponse, WIMSETokenResponse,
};
pub struct Wimse<'a> {
pub(crate) client: &'a AgentTrustClient,
}
impl<'a> Wimse<'a> {
pub fn issue_token(&self, req: &IssueWIMSETokenRequest) -> Result<WIMSETokenResponse> {
self.client
.request("POST", "/api/v1/wimse/token", Some(req))
}
pub fn get_jwt_signed_headers(
&self,
req: &IssueWIMSETokenRequest,
) -> Result<Vec<(String, String)>> {
let resp = self.issue_token(req)?;
Ok(vec![
(
"Authorization".to_string(),
format!("Bearer {}", resp.token),
),
("X-WIMSE-Workload-ID".to_string(), resp.workload_id),
("X-WIMSE-Trust-Domain".to_string(), resp.trust_domain),
])
}
pub fn verify_wimse(&self, req: &VerifyWIMSETokenRequest) -> Result<VerifyWIMSETokenResponse> {
self.client
.request("POST", "/api/v1/wimse/verify", Some(req))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::AgentTrustError;
use mockito::Server;
#[test]
fn test_issue_token_success() {
let mut srv = Server::new();
let mock = srv
.mock("POST", "/api/v1/wimse/token")
.with_status(200)
.with_body(
r#"{
"token":"eyJ-abc",
"workload_id":"spiffe://ati/agent-1",
"trust_domain":"ati",
"expires_at":"2026-01-01T00:00:00Z"
}"#,
)
.create();
let client = AgentTrustClient::builder()
.base_url(&srv.url())
.build()
.unwrap();
let resp = client
.wimse()
.issue_token(&IssueWIMSETokenRequest {
agent_id: "agent-1".into(),
service_name: None,
environment: None,
ttl_seconds: None,
})
.unwrap();
assert_eq!(resp.token, "eyJ-abc");
assert_eq!(resp.workload_id, "spiffe://ati/agent-1");
mock.assert();
}
#[test]
fn test_get_jwt_signed_headers_success() {
let mut srv = Server::new();
let mock = srv
.mock("POST", "/api/v1/wimse/token")
.with_status(200)
.with_body(
r#"{"token":"eyJ","workload_id":"spiffe://x","trust_domain":"ati","expires_at":"2026-01-01T00:00:00Z"}"#,
)
.create();
let client = AgentTrustClient::builder()
.base_url(&srv.url())
.build()
.unwrap();
let headers = client
.wimse()
.get_jwt_signed_headers(&IssueWIMSETokenRequest {
agent_id: "agent-1".into(),
service_name: None,
environment: None,
ttl_seconds: None,
})
.unwrap();
let auth = headers
.iter()
.find(|(k, _)| k == "Authorization")
.map(|(_, v)| v.as_str())
.unwrap();
assert_eq!(auth, "Bearer eyJ");
mock.assert();
}
#[test]
fn test_verify_wimse_validation_error() {
let mut srv = Server::new();
let mock = srv
.mock("POST", "/api/v1/wimse/verify")
.with_status(400)
.with_body(r#"{"message":"missing token"}"#)
.create();
let client = AgentTrustClient::builder()
.base_url(&srv.url())
.build()
.unwrap();
let err = client
.wimse()
.verify_wimse(&VerifyWIMSETokenRequest {
token: String::new(),
trust_domain_filter: None,
})
.unwrap_err();
assert!(matches!(err, AgentTrustError::Validation { .. }));
mock.assert();
}
#[test]
fn test_issue_token_server_error() {
let mut srv = Server::new();
let mock = srv
.mock("POST", "/api/v1/wimse/token")
.with_status(500)
.with_body(r#"{"message":"server"}"#)
.create();
let client = AgentTrustClient::builder()
.base_url(&srv.url())
.build()
.unwrap();
let err = client
.wimse()
.issue_token(&IssueWIMSETokenRequest {
agent_id: "x".into(),
service_name: None,
environment: None,
ttl_seconds: None,
})
.unwrap_err();
match err {
AgentTrustError::Api { status, .. } => assert_eq!(status, 500),
other => panic!("unexpected: {:?}", other),
}
mock.assert();
}
}