///|
pub(all) enum ErrorCategory {
Authentication
Freshness
Identity
Routing
ProviderConfig
Replay
UnknownCategory
} derive(Eq, Debug)
///|
pub fn categorize(code : DiagnosticCode) -> ErrorCategory {
match code {
MissingSignature | SignatureMismatch => Authentication
MissingTimestamp | TimestampOutsideWindow => Freshness
MissingEventId | DuplicateIdempotencyKey => Identity
UnknownEvent => Routing
ProviderMismatch => ProviderConfig
ReplayDetected => Replay
AcceptedDiagnostic => UnknownCategory
}
}
///|
pub fn category_name(category : ErrorCategory) -> String {
match category {
Authentication => "authentication"
Freshness => "freshness"
Identity => "identity"
Routing => "routing"
ProviderConfig => "provider_config"
Replay => "replay"
UnknownCategory => "unknown"
}
}
///|
pub fn remediation(code : DiagnosticCode) -> String {
match code {
MissingSignature =>
"Ensure the provider signature header is forwarded to the handler."
SignatureMismatch =>
"Check the shared secret and canonical payload construction."
MissingTimestamp =>
"Require a timestamp header from the provider or disable freshness only for trusted tests."
TimestampOutsideWindow =>
"Reject stale requests or increase tolerance for known clock skew."
MissingEventId =>
"Require provider delivery id or configure an idempotency fallback."
ReplayDetected =>
"Keep nonce storage active and reject duplicate signed deliveries."
DuplicateIdempotencyKey => "Treat duplicate event ids as already processed."
UnknownEvent => "Add a route rule or explicitly allow unhandled events."
ProviderMismatch =>
"Use the provider profile that matches the inbound request."
AcceptedDiagnostic => "No action required."
}
}
///|
pub fn diagnostic_to_help(diagnostic : GuardDiagnostic) -> String {
diagnostic_name(diagnostic.code) +
" [" +
category_name(categorize(diagnostic.code)) +
"]: " +
remediation(diagnostic.code)
}
///|
pub fn result_help(result : VerificationResult) -> String {
let builder = StringBuilder::new()
for i in 0.. Bool {
for i in 0..