aarondb/identity
identity — durable node trust, mTLS policy, and safe recovery reference surface
This is a policy model, not a socket implementation. A real transport presents
peer certificate facts here before it delivers a Raft RPC. Durable adapters
persist TrustStore and RecoveryState atomically with their authority files.
Types
pub type Certificate {
Certificate(
node: String,
fingerprint: String,
issuer: String,
state: CertificateState,
)
}
Constructors
-
Certificate( node: String, fingerprint: String, issuer: String, state: CertificateState, )
pub type CertificateState {
Active(epoch: Int)
Rotated(epoch: Int)
Revoked
}
Constructors
-
Active(epoch: Int) -
Rotated(epoch: Int) -
Revoked
pub type PeerError {
UnknownCertificate
WrongCertificate(
expected_node: String,
certificate_node: String,
)
UntrustedIssuer(String)
InactiveCertificate
RevokedCertificate
UnauthorizedMember(String)
InvalidRpcSize(actual: Int, maximum: Int)
InvalidReconnectLimit
ReconnectExhausted(attempts: Int)
BootstrapDenied
}
Constructors
-
UnknownCertificate -
WrongCertificate(expected_node: String, certificate_node: String) -
UntrustedIssuer(String) -
InactiveCertificate -
RevokedCertificate -
UnauthorizedMember(String) -
InvalidRpcSize(actual: Int, maximum: Int) -
InvalidReconnectLimit -
ReconnectExhausted(attempts: Int) -
BootstrapDenied
pub type RecoveryAlarm {
UnsafeRecoveryAcknowledged(reason: String)
TrustMaterialMissing
MembershipMismatch(
expected: List(String),
actual: List(String),
)
}
Constructors
-
UnsafeRecoveryAcknowledged(reason: String) -
TrustMaterialMissing -
MembershipMismatch(expected: List(String), actual: List(String))
pub type RecoveryState {
RecoveryState(
alarms: List(RecoveryAlarm),
force_recovery_used: Bool,
)
}
Constructors
-
RecoveryState( alarms: List(RecoveryAlarm), force_recovery_used: Bool, )
pub type RpcLimits {
RpcLimits(maximum_bytes: Int, maximum_attempts: Int)
}
Constructors
-
RpcLimits(maximum_bytes: Int, maximum_attempts: Int)
pub type TrustStore {
TrustStore(
cluster: String,
trusted_issuers: List(String),
certificates: List(Certificate),
members: List(String),
)
}
Constructors
-
TrustStore( cluster: String, trusted_issuers: List(String), certificates: List(Certificate), members: List(String), )
Values
pub fn admit_peer(
store: TrustStore,
expected_node: String,
fingerprint: String,
limits: RpcLimits,
rpc_bytes: Int,
) -> Result(Nil, PeerError)
Mutual TLS admission: issuer, presented identity, active certificate, and committed membership must all agree. Nothing reaches Raft before this passes.
pub fn authorize_bootstrap(
store: TrustStore,
requested_members: List(String),
) -> Result(Nil, PeerError)
New-cluster bootstrap may install the initial member set only when the trust store is empty. Existing clusters require committed membership changes.
pub fn clean_recovery() -> RecoveryState
pub fn fingerprint_for(
store: TrustStore,
node: String,
) -> option.Option(String)
pub fn force_recovery(
state: RecoveryState,
reason: String,
) -> RecoveryState
A forced repair is an operator action, not an automatic healing path. Its durable alarm remains until an operator explicitly records the incident.
pub fn inspect_recovery(
state: RecoveryState,
expected_members: List(String),
actual_members: List(String),
trust_material_present: Bool,
) -> RecoveryState
pub fn new(
cluster: String,
trusted_issuers: List(String),
members: List(String),
) -> TrustStore
pub fn put_certificate(
store: TrustStore,
certificate: Certificate,
) -> TrustStore
Replacing a fingerprint is an explicit rotation. Existing certificates are
retained only as Rotated evidence, never as valid transport credentials.
pub fn reconnect(
limits: RpcLimits,
attempt: Int,
) -> Result(Nil, PeerError)
attempt is zero based. Callers must stop after this returns exhaustion;
this deliberately refuses an unbounded retry loop disguised as resilience.
pub fn revoke(
store: TrustStore,
fingerprint: String,
) -> TrustStore