use std::time::{Duration, SystemTime};
use crate::authority::capability::CapabilityKind;
use crate::authority::predicate::{BindFailureReason, BindOutcomeRepr, DenialReason, SemVer};
use crate::authority::ModerationCaseId;
use crate::identity::{KeyId, ServiceIdentity, SessionDigest, SessionId, TraceId};
use crate::ingress::{AttributionChain, Requester};
use crate::oracle::OracleKind;
use crate::proto::{Did, Nsid};
use crate::resolver::PeerKind;
use crate::target::TargetRepresentation;
use super::bounded_string::BoundedString;
use super::composite::CompositeOpId;
use super::sinks::SinkKind;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "audit-serde-json", derive(serde::Serialize, serde::Deserialize))]
pub enum PayloadCompleteness {
Full,
PartialV01,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum UserAuditEvent {
CapabilityIssuanceDenied {
trace_id: TraceId,
requester: Requester,
capability: CapabilityKind,
target_repr: TargetRepresentation,
reason: DenialReason,
attribution: AttributionChain,
at: SystemTime,
},
CapabilityBound {
trace_id: TraceId,
requester: Did,
subject_repr: TargetRepresentation,
capability: CapabilityKind,
outcome: BindOutcomeRepr,
attribution: AttributionChain,
at: SystemTime,
},
ReborrowFailed {
trace_id: TraceId,
requester: Did,
subject_repr: TargetRepresentation,
capability: CapabilityKind,
reason: BindFailureReason,
at: SystemTime,
},
DerivedContext {
trace_id: TraceId,
from: Requester,
to: Requester,
narrowing_kind: NarrowingKind,
outcome: DerivationOutcome,
at: SystemTime,
},
CompositeRollbackMarker {
trace_id: TraceId,
composite_op_id: CompositeOpId,
failing_sink: SinkKind,
at: SystemTime,
},
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum ChannelAuditEvent {
ChannelBound {
trace_id: TraceId,
peer: ServiceIdentity,
session_digest: SessionDigest,
endpoint: CapabilityKind,
outcome: BindOutcomeRepr,
payload_completeness: PayloadCompleteness,
at: SystemTime,
},
ChannelIssuanceDenied {
trace_id: TraceId,
peer: ServiceIdentity,
endpoint: CapabilityKind,
reason: DenialReason,
at: SystemTime,
},
ChannelReborrowFailed {
trace_id: TraceId,
peer: ServiceIdentity,
session_digest: SessionDigest,
endpoint: CapabilityKind,
reason: BindFailureReason,
payload_completeness: PayloadCompleteness,
at: SystemTime,
},
SyncBatchRejected {
trace_id: TraceId,
peer: ServiceIdentity,
session_digest: SessionDigest,
perspective: SyncPerspective,
reason: BatchRejectionReason,
at: SystemTime,
},
ChannelClosed {
trace_id: TraceId,
peer: ServiceIdentity,
session_digest: SessionDigest,
cause: ChannelCloseCause,
at: SystemTime,
},
UnknownSessionMessage {
trace_id: TraceId,
session_id_received: SessionId,
peer_identity: Option<ServiceIdentity>,
at: SystemTime,
},
CompositeRollbackMarker {
trace_id: TraceId,
composite_op_id: CompositeOpId,
failing_sink: SinkKind,
at: SystemTime,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SyncPerspective {
LocalAsSender,
LocalAsReceiver,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BatchRejectionReason {
LexiconSetMajorVersionMismatch {
local: SemVer,
peer: SemVer,
},
UnauthorizedPeer,
HandshakeSignatureInvalid,
HandshakeTimeout,
HandshakeNonceReplay {
first_seen_at: SystemTime,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChannelCloseCause {
CleanClose,
PeerDisconnected,
Timeout,
SubstrateShutdown,
ProtocolError {
detail: &'static str,
},
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum SubstrateAuditEvent {
ScopeBound {
trace_id: TraceId,
service: ServiceIdentity,
scope_repr: TargetRepresentation,
capability: CapabilityKind,
outcome: BindOutcomeRepr,
payload_completeness: PayloadCompleteness,
at: SystemTime,
},
ScopeIssuanceDenied {
trace_id: TraceId,
service: ServiceIdentity,
capability: CapabilityKind,
reason: DenialReason,
at: SystemTime,
},
LexiconSetVersionChanged {
trace_id: TraceId,
from_version: SemVer,
to_version: SemVer,
deprecations: Vec<DeprecationEventDetail>,
additions: Vec<Nsid>,
at: SystemTime,
},
DeprecatedWriteDuringGrace {
trace_id: TraceId,
nsid: &'static str,
capability: CapabilityKind,
requester: Did,
since_version: SemVer,
grace_until: SystemTime,
successor: Option<&'static str>,
at: SystemTime,
},
OracleFreshnessTransition {
trace_id: TraceId,
oracle: OracleKind,
from_state: OracleFreshnessState,
to_state: OracleFreshnessState,
sync_age: Duration,
at: SystemTime,
},
RateLimitTriggered {
trace_id: TraceId,
requester: Requester,
bucket: RateLimitBucket,
at: SystemTime,
},
CompositeRollbackMarker {
trace_id: TraceId,
composite_op_id: CompositeOpId,
failing_sink: SinkKind,
at: SystemTime,
},
DidDocumentRotated {
trace_id: TraceId,
did: Did,
previous_methods: Vec<KeyId>,
current_methods: Vec<KeyId>,
at: SystemTime,
},
DidDocumentInvalidated {
trace_id: TraceId,
did: Did,
invalidated_by: InvalidationSource,
at: SystemTime,
},
PeerTrustGranted {
trace_id: TraceId,
peer: ServiceIdentity,
operation: PeerOperation,
kind: PeerKind,
constraints: Option<PeerTrustConstraints>,
at: SystemTime,
},
PeerTrustDenied {
trace_id: TraceId,
peer: ServiceIdentity,
operation: PeerOperation,
reason: &'static str,
at: SystemTime,
},
PeerTrustUnknown {
trace_id: TraceId,
peer: ServiceIdentity,
operation: PeerOperation,
fallback_applied: FallbackTrustPolicy,
interim_decision_applied: PeerTrustDecision,
at: SystemTime,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct DeprecationEventDetail {
pub nsid: Nsid,
pub since_version: SemVer,
pub successor: Option<Nsid>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OracleFreshnessState {
Fresh,
Stale {
exceeded_bound_by: Duration,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RateLimitBucket {
PerDidActive,
LongTailDidClass,
ServiceClass,
AnonymousClass,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InvalidationSource {
Operator,
Substrate {
reason: &'static str,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PeerOperation {
AcceptSyncHandshake,
AcceptCapabilityClaim,
ReplicateRecord,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct PeerTrustConstraints {}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FallbackTrustPolicy {
PromptOperator,
DefaultDeny,
DefaultAllow,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PeerTrustDecision {
Accept,
Reject,
Deferred,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum ModerationAuditEvent {
ModeratorInspected {
trace_id: TraceId,
moderator: Did,
case: ModerationCaseId,
target_repr: TargetRepresentation,
rationale: ModeratorRationale,
payload_completeness: PayloadCompleteness,
at: SystemTime,
},
ModeratorTookDown {
trace_id: TraceId,
moderator: Did,
case: ModerationCaseId,
target_repr: TargetRepresentation,
outcome: BindOutcomeRepr,
rationale: ModeratorRationale,
payload_completeness: PayloadCompleteness,
at: SystemTime,
},
ModeratorRestored {
trace_id: TraceId,
moderator: Did,
case: ModerationCaseId,
target_repr: TargetRepresentation,
outcome: BindOutcomeRepr,
rationale: ModeratorRationale,
payload_completeness: PayloadCompleteness,
at: SystemTime,
},
ModerationIssuanceDenied {
trace_id: TraceId,
moderator: Did,
capability: CapabilityKind,
reason: DenialReason,
at: SystemTime,
},
CompositeRollbackMarker {
trace_id: TraceId,
composite_op_id: CompositeOpId,
failing_sink: SinkKind,
at: SystemTime,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModeratorRationale {
Declared(BoundedString<MAX_RATIONALE_LEN>),
}
pub const MAX_RATIONALE_LEN: usize = 4096;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum FallbackAuditEvent {
SinkPanicked {
sink: SinkKind,
trace_id: TraceId,
capability: CapabilityKind,
at: SystemTime,
},
CompositeFailure {
trace_id: TraceId,
composite_op_id: CompositeOpId,
sinks_committed: smallvec::SmallVec<[SinkKind; 4]>,
sinks_failed: smallvec::SmallVec<[SinkKind; 4]>,
at: SystemTime,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NarrowingKind {
ToAnonymous,
NarrowCapabilities,
ServiceToService,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DerivationOutcome {
Success,
ChainTooDeep,
IllegalNarrowing,
UndeclaredServiceTrust,
NarrowingExceedsAuthority,
}
#[cfg(test)]
mod tests {
use std::time::{Duration, SystemTime};
use super::*;
use crate::authority::capability::CapabilityKind;
use crate::authority::predicate::{BindFailureReason, BindOutcomeRepr, DenialReason, SemVer};
use crate::identity::{
KeyId, PublicKey, ServiceIdentity, SessionDigest, SessionId, SignatureAlgorithm, TraceId,
};
use crate::ingress::{AttributionChain, Requester};
use crate::oracle::{BlockOracleQuery, OracleKind, OracleQueryKind};
use crate::proto::Did;
use crate::target::{StructuralRepresentation, TargetRepresentation};
fn sample_did() -> Did {
Did::new("did:plc:phase3test").unwrap()
}
fn sample_target_repr() -> TargetRepresentation {
TargetRepresentation::structural_only(StructuralRepresentation::Resource {
did: sample_did(),
nsid: crate::Nsid::new("tools.kryphocron.feed.postPrivate").unwrap(),
})
}
fn sample_trace_id() -> TraceId {
TraceId::from_bytes([0u8; 16])
}
fn sample_service_identity() -> ServiceIdentity {
ServiceIdentity::new_internal(
sample_did(),
KeyId::from_bytes([0u8; 32]),
PublicKey {
algorithm: SignatureAlgorithm::Ed25519,
bytes: [0u8; 32],
},
None,
)
}
fn sample_session_digest() -> SessionDigest {
SessionDigest::from_bytes([0u8; 32])
}
#[test]
fn user_audit_event_v1_variant_set_pinned() {
let trace_id = sample_trace_id();
let at = SystemTime::UNIX_EPOCH;
let cap = CapabilityKind::ViewPrivate;
let target = sample_target_repr();
let denied = UserAuditEvent::CapabilityIssuanceDenied {
trace_id,
requester: Requester::Anonymous,
capability: cap,
target_repr: target.clone(),
reason: DenialReason::OwnershipCheckFailed,
attribution: AttributionChain::empty(),
at,
};
let bound = UserAuditEvent::CapabilityBound {
trace_id,
requester: sample_did(),
subject_repr: target.clone(),
capability: cap,
outcome: BindOutcomeRepr::Success,
attribution: AttributionChain::empty(),
at,
};
let reborrow = UserAuditEvent::ReborrowFailed {
trace_id,
requester: sample_did(),
subject_repr: target,
capability: cap,
reason: BindFailureReason::OracleStale {
oracle: OracleKind::Block,
query: OracleQueryKind::Block(
BlockOracleQuery::RequesterVsResourceOwner,
),
},
at,
};
let derived = UserAuditEvent::DerivedContext {
trace_id,
from: Requester::Did(sample_did()),
to: Requester::Anonymous,
narrowing_kind: NarrowingKind::ToAnonymous,
outcome: DerivationOutcome::Success,
at,
};
let rollback = UserAuditEvent::CompositeRollbackMarker {
trace_id,
composite_op_id: CompositeOpId::from_bytes([0u8; 16]),
failing_sink: SinkKind::Channel,
at,
};
for ev in [denied, bound, reborrow, derived, rollback] {
match ev {
UserAuditEvent::CapabilityIssuanceDenied { .. }
| UserAuditEvent::CapabilityBound { .. }
| UserAuditEvent::ReborrowFailed { .. }
| UserAuditEvent::DerivedContext { .. }
| UserAuditEvent::CompositeRollbackMarker { .. } => {}
}
}
}
#[test]
fn user_audit_event_carries_trace_id_and_at_per_6_1() {
let trace_id = sample_trace_id();
let at = SystemTime::UNIX_EPOCH + Duration::from_secs(123);
let bound = UserAuditEvent::CapabilityBound {
trace_id,
requester: sample_did(),
subject_repr: sample_target_repr(),
capability: CapabilityKind::ViewPrivate,
outcome: BindOutcomeRepr::Success,
attribution: AttributionChain::empty(),
at,
};
let UserAuditEvent::CapabilityBound { trace_id: t, at: a, .. } = &bound else {
panic!("expected CapabilityBound");
};
assert_eq!(*t, trace_id);
assert_eq!(*a, at);
}
#[test]
fn user_audit_event_attribution_chain_present_on_denial_and_bind() {
let chain = AttributionChain::empty();
let _denied = UserAuditEvent::CapabilityIssuanceDenied {
trace_id: sample_trace_id(),
requester: Requester::Anonymous,
capability: CapabilityKind::ViewPrivate,
target_repr: sample_target_repr(),
reason: DenialReason::OwnershipCheckFailed,
attribution: chain.clone(),
at: SystemTime::UNIX_EPOCH,
};
let _bound = UserAuditEvent::CapabilityBound {
trace_id: sample_trace_id(),
requester: sample_did(),
subject_repr: sample_target_repr(),
capability: CapabilityKind::ViewPrivate,
outcome: BindOutcomeRepr::Success,
attribution: chain,
at: SystemTime::UNIX_EPOCH,
};
}
#[test]
fn channel_audit_event_v1_variant_set_pinned() {
let trace_id = sample_trace_id();
let at = SystemTime::UNIX_EPOCH;
let peer = sample_service_identity();
let digest = sample_session_digest();
let endpoint = CapabilityKind::ViewPrivate;
let bound = ChannelAuditEvent::ChannelBound {
trace_id,
peer: peer.clone(),
session_digest: digest,
endpoint,
outcome: BindOutcomeRepr::Success,
payload_completeness: PayloadCompleteness::PartialV01,
at,
};
let denied = ChannelAuditEvent::ChannelIssuanceDenied {
trace_id,
peer: peer.clone(),
endpoint,
reason: DenialReason::OwnershipCheckFailed,
at,
};
let reborrow = ChannelAuditEvent::ChannelReborrowFailed {
trace_id,
peer: peer.clone(),
session_digest: digest,
endpoint,
reason: BindFailureReason::AuditUnavailable,
payload_completeness: PayloadCompleteness::PartialV01,
at,
};
let batch = ChannelAuditEvent::SyncBatchRejected {
trace_id,
peer: peer.clone(),
session_digest: digest,
perspective: SyncPerspective::LocalAsReceiver,
reason: BatchRejectionReason::UnauthorizedPeer,
at,
};
let closed = ChannelAuditEvent::ChannelClosed {
trace_id,
peer,
session_digest: digest,
cause: ChannelCloseCause::CleanClose,
at,
};
let unknown = ChannelAuditEvent::UnknownSessionMessage {
trace_id,
session_id_received: SessionId::from_bytes([0u8; 32]),
peer_identity: None,
at,
};
let rollback = ChannelAuditEvent::CompositeRollbackMarker {
trace_id,
composite_op_id: CompositeOpId::from_bytes([0u8; 16]),
failing_sink: SinkKind::User,
at,
};
for ev in [bound, denied, reborrow, batch, closed, unknown, rollback] {
match ev {
ChannelAuditEvent::ChannelBound { .. }
| ChannelAuditEvent::ChannelIssuanceDenied { .. }
| ChannelAuditEvent::ChannelReborrowFailed { .. }
| ChannelAuditEvent::SyncBatchRejected { .. }
| ChannelAuditEvent::ChannelClosed { .. }
| ChannelAuditEvent::UnknownSessionMessage { .. }
| ChannelAuditEvent::CompositeRollbackMarker { .. } => {}
}
}
}
#[test]
fn sync_perspective_v1_variant_set_pinned() {
for p in [SyncPerspective::LocalAsSender, SyncPerspective::LocalAsReceiver] {
match p {
SyncPerspective::LocalAsSender | SyncPerspective::LocalAsReceiver => {}
}
}
}
#[test]
fn batch_rejection_reason_v1_variant_set_pinned() {
let v1 = BatchRejectionReason::LexiconSetMajorVersionMismatch {
local: SemVer::new(1, 0, 0),
peer: SemVer::new(2, 0, 0),
};
let v2 = BatchRejectionReason::UnauthorizedPeer;
let v3 = BatchRejectionReason::HandshakeSignatureInvalid;
let v4 = BatchRejectionReason::HandshakeTimeout;
let v5 = BatchRejectionReason::HandshakeNonceReplay {
first_seen_at: SystemTime::UNIX_EPOCH,
};
for r in [v1, v2, v3, v4, v5] {
match r {
BatchRejectionReason::LexiconSetMajorVersionMismatch { .. }
| BatchRejectionReason::UnauthorizedPeer
| BatchRejectionReason::HandshakeSignatureInvalid
| BatchRejectionReason::HandshakeTimeout
| BatchRejectionReason::HandshakeNonceReplay { .. } => {}
}
}
}
#[test]
fn channel_close_cause_v1_variant_set_pinned() {
for c in [
ChannelCloseCause::CleanClose,
ChannelCloseCause::PeerDisconnected,
ChannelCloseCause::Timeout,
ChannelCloseCause::SubstrateShutdown,
ChannelCloseCause::ProtocolError { detail: "test" },
] {
match c {
ChannelCloseCause::CleanClose
| ChannelCloseCause::PeerDisconnected
| ChannelCloseCause::Timeout
| ChannelCloseCause::SubstrateShutdown
| ChannelCloseCause::ProtocolError { .. } => {}
}
}
}
#[test]
fn substrate_audit_event_v1_variant_set_pinned() {
let trace_id = sample_trace_id();
let at = SystemTime::UNIX_EPOCH;
let svc = sample_service_identity();
let cap = CapabilityKind::ViewPrivate;
let target = sample_target_repr();
let bound = SubstrateAuditEvent::ScopeBound {
trace_id,
service: svc.clone(),
scope_repr: target.clone(),
capability: cap,
outcome: BindOutcomeRepr::Success,
payload_completeness: PayloadCompleteness::PartialV01,
at,
};
let denied = SubstrateAuditEvent::ScopeIssuanceDenied {
trace_id,
service: svc.clone(),
capability: cap,
reason: DenialReason::OwnershipCheckFailed,
at,
};
let lex = SubstrateAuditEvent::LexiconSetVersionChanged {
trace_id,
from_version: SemVer::new(1, 0, 0),
to_version: SemVer::new(1, 1, 0),
deprecations: vec![DeprecationEventDetail {
nsid: crate::Nsid::new("tools.kryphocron.feed.like").unwrap(),
since_version: SemVer::new(1, 1, 0),
successor: None,
}],
additions: vec![],
at,
};
let dep = SubstrateAuditEvent::DeprecatedWriteDuringGrace {
trace_id,
nsid: "tools.kryphocron.feed.like",
capability: cap,
requester: sample_did(),
since_version: SemVer::new(1, 1, 0),
grace_until: SystemTime::UNIX_EPOCH + Duration::from_secs(3600),
successor: None,
at,
};
let oracle = SubstrateAuditEvent::OracleFreshnessTransition {
trace_id,
oracle: OracleKind::Block,
from_state: OracleFreshnessState::Fresh,
to_state: OracleFreshnessState::Stale {
exceeded_bound_by: Duration::from_secs(5),
},
sync_age: Duration::from_secs(60),
at,
};
let rl = SubstrateAuditEvent::RateLimitTriggered {
trace_id,
requester: Requester::Anonymous,
bucket: RateLimitBucket::AnonymousClass,
at,
};
let rollback = SubstrateAuditEvent::CompositeRollbackMarker {
trace_id,
composite_op_id: CompositeOpId::from_bytes([0u8; 16]),
failing_sink: SinkKind::User,
at,
};
let did_rot = SubstrateAuditEvent::DidDocumentRotated {
trace_id,
did: sample_did(),
previous_methods: vec![KeyId::from_bytes([0u8; 32])],
current_methods: vec![KeyId::from_bytes([1u8; 32])],
at,
};
let did_inv = SubstrateAuditEvent::DidDocumentInvalidated {
trace_id,
did: sample_did(),
invalidated_by: InvalidationSource::Operator,
at,
};
let trust_g = SubstrateAuditEvent::PeerTrustGranted {
trace_id,
peer: svc.clone(),
operation: PeerOperation::AcceptSyncHandshake,
kind: PeerKind::Federation,
constraints: None,
at,
};
let trust_d = SubstrateAuditEvent::PeerTrustDenied {
trace_id,
peer: svc.clone(),
operation: PeerOperation::ReplicateRecord,
reason: "test",
at,
};
let trust_u = SubstrateAuditEvent::PeerTrustUnknown {
trace_id,
peer: svc,
operation: PeerOperation::AcceptCapabilityClaim,
fallback_applied: FallbackTrustPolicy::PromptOperator,
interim_decision_applied: PeerTrustDecision::Deferred,
at,
};
for ev in [
bound, denied, lex, dep, oracle, rl, rollback, did_rot, did_inv, trust_g,
trust_d, trust_u,
] {
match ev {
SubstrateAuditEvent::ScopeBound { .. }
| SubstrateAuditEvent::ScopeIssuanceDenied { .. }
| SubstrateAuditEvent::LexiconSetVersionChanged { .. }
| SubstrateAuditEvent::DeprecatedWriteDuringGrace { .. }
| SubstrateAuditEvent::OracleFreshnessTransition { .. }
| SubstrateAuditEvent::RateLimitTriggered { .. }
| SubstrateAuditEvent::CompositeRollbackMarker { .. }
| SubstrateAuditEvent::DidDocumentRotated { .. }
| SubstrateAuditEvent::DidDocumentInvalidated { .. }
| SubstrateAuditEvent::PeerTrustGranted { .. }
| SubstrateAuditEvent::PeerTrustDenied { .. }
| SubstrateAuditEvent::PeerTrustUnknown { .. } => {}
}
}
}
#[test]
fn oracle_freshness_state_v1_variant_set_pinned() {
for s in [
OracleFreshnessState::Fresh,
OracleFreshnessState::Stale {
exceeded_bound_by: Duration::from_millis(1),
},
] {
match s {
OracleFreshnessState::Fresh | OracleFreshnessState::Stale { .. } => {}
}
}
}
#[test]
fn rate_limit_bucket_v1_variant_set_pinned() {
for b in [
RateLimitBucket::PerDidActive,
RateLimitBucket::LongTailDidClass,
RateLimitBucket::ServiceClass,
RateLimitBucket::AnonymousClass,
] {
match b {
RateLimitBucket::PerDidActive
| RateLimitBucket::LongTailDidClass
| RateLimitBucket::ServiceClass
| RateLimitBucket::AnonymousClass => {}
}
}
}
#[test]
fn invalidation_source_v1_variant_set_pinned() {
for s in [
InvalidationSource::Operator,
InvalidationSource::Substrate { reason: "test" },
] {
match s {
InvalidationSource::Operator | InvalidationSource::Substrate { .. } => {}
}
}
}
#[test]
fn peer_operation_v1_variant_set_pinned() {
for o in [
PeerOperation::AcceptSyncHandshake,
PeerOperation::AcceptCapabilityClaim,
PeerOperation::ReplicateRecord,
] {
match o {
PeerOperation::AcceptSyncHandshake
| PeerOperation::AcceptCapabilityClaim
| PeerOperation::ReplicateRecord => {}
}
}
}
#[test]
fn fallback_trust_policy_v1_variant_set_pinned() {
for p in [
FallbackTrustPolicy::PromptOperator,
FallbackTrustPolicy::DefaultDeny,
FallbackTrustPolicy::DefaultAllow,
] {
match p {
FallbackTrustPolicy::PromptOperator
| FallbackTrustPolicy::DefaultDeny
| FallbackTrustPolicy::DefaultAllow => {}
}
}
}
#[test]
fn peer_trust_decision_v1_variant_set_pinned() {
for d in [
PeerTrustDecision::Accept,
PeerTrustDecision::Reject,
PeerTrustDecision::Deferred,
] {
match d {
PeerTrustDecision::Accept
| PeerTrustDecision::Reject
| PeerTrustDecision::Deferred => {}
}
}
}
fn sample_rationale() -> ModeratorRationale {
ModeratorRationale::Declared(
BoundedString::<MAX_RATIONALE_LEN>::new("test rationale").unwrap(),
)
}
fn sample_case() -> ModerationCaseId {
ModerationCaseId::from_bytes([0u8; 16])
}
#[test]
fn moderation_audit_event_v1_variant_set_pinned() {
let trace_id = sample_trace_id();
let at = SystemTime::UNIX_EPOCH;
let moderator = sample_did();
let case = sample_case();
let target = sample_target_repr();
let rationale = sample_rationale();
let inspected = ModerationAuditEvent::ModeratorInspected {
trace_id,
moderator: moderator.clone(),
case,
target_repr: target.clone(),
rationale: rationale.clone(),
payload_completeness: PayloadCompleteness::PartialV01,
at,
};
let took_down = ModerationAuditEvent::ModeratorTookDown {
trace_id,
moderator: moderator.clone(),
case,
target_repr: target.clone(),
outcome: BindOutcomeRepr::Success,
rationale: rationale.clone(),
payload_completeness: PayloadCompleteness::PartialV01,
at,
};
let restored = ModerationAuditEvent::ModeratorRestored {
trace_id,
moderator: moderator.clone(),
case,
target_repr: target,
outcome: BindOutcomeRepr::Success,
rationale,
payload_completeness: PayloadCompleteness::PartialV01,
at,
};
let denied = ModerationAuditEvent::ModerationIssuanceDenied {
trace_id,
moderator,
capability: CapabilityKind::ViewPrivate,
reason: DenialReason::OwnershipCheckFailed,
at,
};
let rollback = ModerationAuditEvent::CompositeRollbackMarker {
trace_id,
composite_op_id: CompositeOpId::from_bytes([0u8; 16]),
failing_sink: SinkKind::Substrate,
at,
};
for ev in [inspected, took_down, restored, denied, rollback] {
match ev {
ModerationAuditEvent::ModeratorInspected { .. }
| ModerationAuditEvent::ModeratorTookDown { .. }
| ModerationAuditEvent::ModeratorRestored { .. }
| ModerationAuditEvent::ModerationIssuanceDenied { .. }
| ModerationAuditEvent::CompositeRollbackMarker { .. } => {}
}
}
}
#[test]
fn max_rationale_len_pinned_at_4096() {
assert_eq!(MAX_RATIONALE_LEN, 4096);
}
#[test]
fn moderator_rationale_boundary_at_max_rationale_len() {
let exact = "a".repeat(MAX_RATIONALE_LEN);
let over = "a".repeat(MAX_RATIONALE_LEN + 1);
let ok = BoundedString::<MAX_RATIONALE_LEN>::new(exact).unwrap();
let _r = ModeratorRationale::Declared(ok);
let err = BoundedString::<MAX_RATIONALE_LEN>::new(over).unwrap_err();
assert_eq!(err.bound, MAX_RATIONALE_LEN);
assert_eq!(err.len, MAX_RATIONALE_LEN + 1);
}
#[test]
fn moderator_rationale_v1_variant_set_pinned() {
let r = sample_rationale();
match r {
ModeratorRationale::Declared(_) => {}
}
}
#[test]
fn fallback_audit_event_v1_variant_set_pinned() {
let trace_id = sample_trace_id();
let at = SystemTime::UNIX_EPOCH;
let panicked = FallbackAuditEvent::SinkPanicked {
sink: SinkKind::User,
trace_id,
capability: CapabilityKind::ViewPrivate,
at,
};
let composite = FallbackAuditEvent::CompositeFailure {
trace_id,
composite_op_id: CompositeOpId::from_bytes([0u8; 16]),
sinks_committed: smallvec::smallvec![SinkKind::User, SinkKind::Substrate],
sinks_failed: smallvec::smallvec![SinkKind::Channel],
at,
};
for ev in [panicked, composite] {
match ev {
FallbackAuditEvent::SinkPanicked { .. }
| FallbackAuditEvent::CompositeFailure { .. } => {}
}
}
}
#[test]
fn fallback_composite_failure_uses_smallvec_inline_for_le_4_sinks() {
let four: smallvec::SmallVec<[SinkKind; 4]> = smallvec::smallvec![
SinkKind::User,
SinkKind::Channel,
SinkKind::Substrate,
SinkKind::Moderation,
];
assert!(!four.spilled());
}
#[test]
fn payload_completeness_v1_variant_set_pinned() {
let _full = PayloadCompleteness::Full;
let _partial = PayloadCompleteness::PartialV01;
assert_ne!(PayloadCompleteness::Full, PayloadCompleteness::PartialV01);
}
#[test]
fn channel_bound_construction_sets_partial_v01() {
let event = ChannelAuditEvent::ChannelBound {
trace_id: sample_trace_id(),
peer: sample_service_identity(),
session_digest: sample_session_digest(),
endpoint: CapabilityKind::EmitToSyncChannel,
outcome: BindOutcomeRepr::Success,
payload_completeness: PayloadCompleteness::PartialV01,
at: SystemTime::UNIX_EPOCH,
};
match event {
ChannelAuditEvent::ChannelBound { payload_completeness, .. } => {
assert_eq!(payload_completeness, PayloadCompleteness::PartialV01);
}
_ => unreachable!(),
}
}
#[test]
fn channel_reborrow_failed_construction_sets_partial_v01() {
let event = ChannelAuditEvent::ChannelReborrowFailed {
trace_id: sample_trace_id(),
peer: sample_service_identity(),
session_digest: sample_session_digest(),
endpoint: CapabilityKind::EmitToSyncChannel,
reason: BindFailureReason::Expired,
payload_completeness: PayloadCompleteness::PartialV01,
at: SystemTime::UNIX_EPOCH,
};
match event {
ChannelAuditEvent::ChannelReborrowFailed { payload_completeness, .. } => {
assert_eq!(payload_completeness, PayloadCompleteness::PartialV01);
}
_ => unreachable!(),
}
}
#[test]
fn scope_bound_construction_sets_partial_v01() {
let event = SubstrateAuditEvent::ScopeBound {
trace_id: sample_trace_id(),
service: sample_service_identity(),
scope_repr: sample_target_repr(),
capability: CapabilityKind::ScanShard,
outcome: BindOutcomeRepr::Success,
payload_completeness: PayloadCompleteness::PartialV01,
at: SystemTime::UNIX_EPOCH,
};
match event {
SubstrateAuditEvent::ScopeBound { payload_completeness, .. } => {
assert_eq!(payload_completeness, PayloadCompleteness::PartialV01);
}
_ => unreachable!(),
}
}
#[test]
fn moderator_inspected_construction_sets_partial_v01() {
let event = ModerationAuditEvent::ModeratorInspected {
trace_id: sample_trace_id(),
moderator: sample_did(),
case: sample_case(),
target_repr: sample_target_repr(),
rationale: sample_rationale(),
payload_completeness: PayloadCompleteness::PartialV01,
at: SystemTime::UNIX_EPOCH,
};
match event {
ModerationAuditEvent::ModeratorInspected { payload_completeness, .. } => {
assert_eq!(payload_completeness, PayloadCompleteness::PartialV01);
}
_ => unreachable!(),
}
}
#[test]
fn moderator_took_down_construction_sets_partial_v01() {
let event = ModerationAuditEvent::ModeratorTookDown {
trace_id: sample_trace_id(),
moderator: sample_did(),
case: sample_case(),
target_repr: sample_target_repr(),
outcome: BindOutcomeRepr::Success,
rationale: sample_rationale(),
payload_completeness: PayloadCompleteness::PartialV01,
at: SystemTime::UNIX_EPOCH,
};
match event {
ModerationAuditEvent::ModeratorTookDown { payload_completeness, .. } => {
assert_eq!(payload_completeness, PayloadCompleteness::PartialV01);
}
_ => unreachable!(),
}
}
#[test]
fn moderator_restored_construction_sets_partial_v01() {
let event = ModerationAuditEvent::ModeratorRestored {
trace_id: sample_trace_id(),
moderator: sample_did(),
case: sample_case(),
target_repr: sample_target_repr(),
outcome: BindOutcomeRepr::Success,
rationale: sample_rationale(),
payload_completeness: PayloadCompleteness::PartialV01,
at: SystemTime::UNIX_EPOCH,
};
match event {
ModerationAuditEvent::ModeratorRestored { payload_completeness, .. } => {
assert_eq!(payload_completeness, PayloadCompleteness::PartialV01);
}
_ => unreachable!(),
}
}
#[cfg(feature = "audit-serde-json")]
#[test]
fn payload_completeness_serde_json_round_trip() {
let partial = PayloadCompleteness::PartialV01;
let s = serde_json::to_string(&partial).expect("serialize");
assert_eq!(s, "\"PartialV01\"");
let back: PayloadCompleteness = serde_json::from_str(&s).expect("deserialize");
assert_eq!(back, PayloadCompleteness::PartialV01);
let full = PayloadCompleteness::Full;
let s = serde_json::to_string(&full).expect("serialize");
assert_eq!(s, "\"Full\"");
let back: PayloadCompleteness = serde_json::from_str(&s).expect("deserialize");
assert_eq!(back, PayloadCompleteness::Full);
}
}