use std::error::Error;
use liminal_protocol::lifecycle::CredentialAttachLiveReceipt;
use liminal_protocol::wire::{
AttachAttemptToken, AttachBound, AttachSecret, BindingEpoch, ConnectionIncarnation,
CredentialDigest, Generation,
};
use super::capacity::{OccupancyEntry, ResourceKind};
use super::log::{
StoredAttachRequest, StoredBindingEpoch, StoredDetachRequest, StoredEnrollmentAllocation,
StoredEnrollmentRequest, StoredLeaveRequest, StoredRecordAdmissionRequest, StoredU128,
};
use super::log_v2::StoredAttachAllocationV2;
use super::log_v3::{StoredAttachAllocation, StoredCredentialReissue};
use super::occupancy::ProvenanceMember;
use super::restore_checkpoint_history_key::HistoryEntryKey;
use super::state::AttachReceiptState;
use crate::credential_debug_tests::{shows_none_of, token_shaped};
const EPOCH: StoredBindingEpoch = StoredBindingEpoch {
server_incarnation: 1,
connection_ordinal: 2,
capability_generation: 3,
};
fn token() -> [u8; 16] {
token_shaped::<16>(16)
}
fn secret() -> [u8; 32] {
token_shaped::<32>(32)
}
#[test]
fn a_stored_record_admission_request_debug_shows_no_token_byte() {
let request = StoredRecordAdmissionRequest {
conversation_id: 1,
participant_id: 2,
capability_generation: 3,
token: token(),
payload: vec![4],
};
shows_none_of(&request, &token());
}
#[test]
fn a_stored_leave_request_debug_shows_no_secret_or_token_byte() {
let request = StoredLeaveRequest {
conversation_id: 1,
participant_id: 2,
capability_generation: 3,
attach_secret: secret(),
token: token(),
};
shows_none_of(&request, &secret());
shows_none_of(&request, &token());
}
#[test]
fn a_stored_enrollment_request_debug_shows_no_token_byte() {
let request = StoredEnrollmentRequest {
conversation_id: 1,
token: token(),
};
shows_none_of(&request, &token());
}
#[test]
fn a_stored_enrollment_allocation_debug_shows_no_secret_byte() {
let allocation = StoredEnrollmentAllocation {
participant_id: 1,
identity_limit: 2,
attach_secret: secret(),
origin_epoch: EPOCH,
attached_order: 4,
attached_seq: 5,
receipt_expires_at: StoredU128([6; 16]),
provenance_expires_at: StoredU128([7; 16]),
enrollment_fingerprint: CredentialDigest::new([8; 32]),
};
shows_none_of(&allocation, &secret());
}
#[test]
fn a_stored_attach_request_debug_shows_no_secret_or_token_byte() {
let request = StoredAttachRequest {
conversation_id: 1,
participant_id: 2,
capability_generation: 3,
attach_secret: secret(),
token: token(),
accept_marker_delivery_seq: Some(4),
};
shows_none_of(&request, &secret());
shows_none_of(&request, &token());
}
#[test]
fn a_stored_detach_request_debug_shows_no_token_byte() {
let request = StoredDetachRequest {
conversation_id: 1,
participant_id: 2,
capability_generation: 3,
token: token(),
};
shows_none_of(&request, &token());
}
#[test]
fn a_v2_attach_allocation_debug_shows_no_secret_byte() {
let allocation = StoredAttachAllocationV2 {
binding_epoch: EPOCH,
attach_secret: secret(),
attached_order: 4,
attached_seq: 5,
receipt_expires_at: StoredU128([6; 16]),
provenance_expires_at: StoredU128([7; 16]),
admitted_now_ms: 8,
superseded_terminal_seq: Some(9),
};
shows_none_of(&allocation, &secret());
}
#[test]
fn a_v3_attach_allocation_debug_shows_no_secret_byte() {
let allocation = StoredAttachAllocation {
binding_epoch: EPOCH,
attach_secret: secret(),
attached_order: 4,
attached_seq: 5,
receipt_expires_at: StoredU128([6; 16]),
provenance_expires_at: StoredU128([7; 16]),
admitted_now_ms: 8,
};
shows_none_of(&allocation, &secret());
}
#[test]
fn a_stored_credential_reissue_debug_shows_no_verifier_byte() {
let reissue = StoredCredentialReissue {
participant_id: 1,
presented_generation: 2,
issued_generation: 3,
attach_secret_verifier: secret(),
admitted_now_ms: 4,
};
shows_none_of(&reissue, &secret());
}
#[test]
fn an_occupancy_entry_debug_shows_no_token_byte() {
let entry = OccupancyEntry {
expires_at: 1,
conversation_id: 2,
participant_id: 3,
kind: ResourceKind::AttachProvenance,
token: token(),
};
shows_none_of(&entry, &token());
}
#[test]
fn a_provenance_member_debug_shows_no_token_byte() {
let member = ProvenanceMember::Attach {
expires_at: 1,
token: token(),
};
shows_none_of(&member, &token());
}
#[test]
fn a_history_entry_key_debug_shows_no_token_byte() {
for key in [
HistoryEntryKey::EnrollmentReverse { token: token() },
HistoryEntryKey::CommittedAdmission {
token: token(),
participant_id: 1,
fingerprint: [2; 32],
},
HistoryEntryKey::AttachProvenance {
participant_id: 1,
token: token(),
},
HistoryEntryKey::RetiredAdmission {
token: token(),
participant_id: 1,
fingerprint: [2; 32],
},
] {
shows_none_of(&key, &token());
}
}
#[test]
fn an_attach_receipt_state_debug_shows_no_verifier_byte() -> Result<(), Box<dyn Error>> {
let generation = |value| Generation::new(value).ok_or("a nonzero generation");
let outcome = AttachBound::ordinary(
1,
AttachAttemptToken::new([2; 16]),
3,
generation(1)?,
AttachSecret::new([4; 32]),
BindingEpoch::new(ConnectionIncarnation::new(5, 6), generation(2)?),
0,
1_000,
2_000,
)
.ok_or("generation 2 succeeds generation 1")?;
let state = AttachReceiptState {
token: AttachAttemptToken::new([2; 16]),
receipt: CredentialAttachLiveReceipt::from_commit(outcome.clone()),
outcome,
verifier: secret(),
result_generation: generation(2)?,
receipt_expires_at: 1_000,
provenance_expires_at: 2_000,
};
shows_none_of(&state, &secret());
Ok(())
}