feat(core): wire ConfigIdentityProvider to PeerEntry multi-credential path (core/config-identity-provider-peerentry)

This commit is contained in:
2026-06-28 21:36:15 +00:00
parent e980fcc27f
commit 50abd346a4

View File

@@ -152,7 +152,7 @@ mod tests {
}
}
fn config_with_fingerprint(peer_id: &str, fingerprint: &str) -> DynamicConfig {
fn config_with_peer_entry(peer_id: &str, fingerprint: &str) -> DynamicConfig {
DynamicConfig {
auth: AuthPolicy {
peers: vec![peer_entry_with_fingerprint(peer_id, fingerprint)],
@@ -172,6 +172,14 @@ mod tests {
}
}
fn compute_token_hash(token: &str) -> String {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(token.as_bytes());
let result = hasher.finalize();
format!("sha256:{}", hex::encode(result))
}
#[test]
fn identity_fields_and_equality() {
let mut resources = HashMap::new();
@@ -213,7 +221,7 @@ mod tests {
#[test]
fn fingerprint_resolution_known_returns_some() {
let (provider, _) = make_provider(config_with_fingerprint("worker-a", "SHA256:abc123"));
let (provider, _) = make_provider(config_with_peer_entry("worker-a", "SHA256:abc123"));
let identity = provider
.resolve_from_fingerprint("SHA256:abc123")
.expect("known fingerprint resolves");
@@ -224,7 +232,7 @@ mod tests {
#[test]
fn fingerprint_resolution_unknown_returns_none() {
let (provider, _) = make_provider(config_with_fingerprint("worker-a", "SHA256:abc123"));
let (provider, _) = make_provider(config_with_peer_entry("worker-a", "SHA256:abc123"));
assert!(provider
.resolve_from_fingerprint("SHA256:unknown")
.is_none());
@@ -326,7 +334,7 @@ mod tests {
let (provider, arc_swap) = make_provider(DynamicConfig::default());
assert!(provider.resolve_from_fingerprint("SHA256:abc123").is_none());
let new_config = config_with_fingerprint("worker-a", "SHA256:abc123");
let new_config = config_with_peer_entry("worker-a", "SHA256:abc123");
arc_swap.store(Arc::new(new_config));
assert!(provider.resolve_from_fingerprint("SHA256:abc123").is_some());
@@ -335,7 +343,7 @@ mod tests {
#[test]
fn config_reload_removes_fingerprint_access_immediately() {
let (provider, arc_swap) =
make_provider(config_with_fingerprint("worker-a", "SHA256:abc123"));
make_provider(config_with_peer_entry("worker-a", "SHA256:abc123"));
assert!(provider.resolve_from_fingerprint("SHA256:abc123").is_some());
arc_swap.store(Arc::new(DynamicConfig::default()));
@@ -352,7 +360,7 @@ mod tests {
assert!(provider.resolve_from_fingerprint("SHA256:abc123").is_none());
handle.reload(config_with_fingerprint("worker-a", "SHA256:abc123"));
handle.reload(config_with_peer_entry("worker-a", "SHA256:abc123"));
assert!(provider.resolve_from_fingerprint("SHA256:abc123").is_some());
}
@@ -364,6 +372,94 @@ mod tests {
assert_provider::<ConfigIdentityProvider>();
assert_not_store::<ConfigIdentityProvider>();
}
#[test]
fn token_resolution_via_peer_entry_auth_token_hash_returns_peer_id() {
let token_str = "peer-bearer-secret";
let mut entry = peer_entry_with_fingerprint("worker-a", "SHA256:abc123");
entry.auth_token_hash = Some(compute_token_hash(token_str));
let config = DynamicConfig {
auth: AuthPolicy {
peers: vec![entry],
api_keys: Vec::new(),
},
rate_limits: RateLimitConfig::default(),
};
let (provider, _) = make_provider(config);
let token = AuthToken {
raw: token_str.as_bytes().to_vec(),
};
let identity = provider
.resolve_from_token(&token)
.expect("matching PeerEntry.auth_token_hash resolves");
assert_eq!(identity.id, "worker-a");
assert_eq!(identity.scopes, vec!["relay:connect".to_string()]);
}
#[test]
fn token_resolution_falls_through_to_api_key_when_no_peer_entry_matches() {
let api_token = "alk_test_secret";
let mut entry = peer_entry_with_fingerprint("worker-a", "SHA256:abc123");
entry.auth_token_hash = Some(compute_token_hash("different-token"));
let api_entry = ApiKeyEntry {
prefix: "alk_test".to_string(),
hash: compute_api_key_hash(api_token),
scopes: vec!["admin".to_string()],
description: "fall-through key".to_string(),
expires_at: None,
};
let config = DynamicConfig {
auth: AuthPolicy {
peers: vec![entry],
api_keys: vec![api_entry],
},
rate_limits: RateLimitConfig::default(),
};
let (provider, _) = make_provider(config);
let token = AuthToken {
raw: api_token.as_bytes().to_vec(),
};
let identity = provider
.resolve_from_token(&token)
.expect("api key fall-through resolves");
assert_eq!(identity.id, "alk_test");
assert_eq!(identity.scopes, vec!["admin".to_string()]);
}
#[test]
fn disabled_peer_entry_returns_none_on_fingerprint_resolution() {
let mut entry = peer_entry_with_fingerprint("worker-a", "SHA256:abc123");
entry.enabled = false;
let config = DynamicConfig {
auth: AuthPolicy {
peers: vec![entry],
api_keys: Vec::new(),
},
rate_limits: RateLimitConfig::default(),
};
let (provider, _) = make_provider(config);
assert!(provider.resolve_from_fingerprint("SHA256:abc123").is_none());
}
#[test]
fn disabled_peer_entry_returns_none_on_token_resolution() {
let token_str = "peer-bearer-secret";
let mut entry = peer_entry_with_fingerprint("worker-a", "SHA256:abc123");
entry.auth_token_hash = Some(compute_token_hash(token_str));
entry.enabled = false;
let config = DynamicConfig {
auth: AuthPolicy {
peers: vec![entry],
api_keys: Vec::new(),
},
rate_limits: RateLimitConfig::default(),
};
let (provider, _) = make_provider(config);
let token = AuthToken {
raw: token_str.as_bytes().to_vec(),
};
assert!(provider.resolve_from_token(&token).is_none());
}
}
#[cfg(test)]