use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub const DEFAULT_RECEIPT_LIMIT: usize = 50;
pub const MAX_RECEIPT_LIMIT: usize = 500;
pub fn validate_receipt_limit(limit: usize) -> anyhow::Result<()> {
anyhow::ensure!(
(1..=MAX_RECEIPT_LIMIT).contains(&limit),
"receipt limit must be between 1 and {MAX_RECEIPT_LIMIT}"
);
Ok(())
}
pub fn validate_receipt_lookup(request_id: &str, incarnation: Option<&str>) -> anyhow::Result<()> {
crate::actions::administration::validate_identifier(request_id)?;
if let Some(incarnation) = incarnation {
crate::actions::administration::validate_identifier(incarnation)?;
}
Ok(())
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct ReceiptRetention {
pub incarnation_id: String,
pub capacity: usize,
pub completed_ttl_secs: u64,
pub health: bitrouter_sdk::language_model::receipts::RequestReceiptStoreHealth,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ChecksReport {
pub resolved_via: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub config_state: Option<crate::reload::ConfigurationState>,
pub receipt_retention: ReceiptRetention,
pub checkers: Vec<crate::request_checks::CheckerInfo>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct CheckerProbeReport {
pub synthetic: bool,
pub counts_as_usage: bool,
pub result: crate::request_checks::ProbeResult,
}
impl CheckerProbeReport {
pub fn new(result: crate::request_checks::ProbeResult) -> Self {
Self {
synthetic: true,
counts_as_usage: false,
result,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::request_checks::{
CheckerProbeDecision, ProbeProtocolStatus, ProbeReachability, ProbeResult,
};
#[test]
fn receipt_queries_are_bounded_before_transport() {
assert!(validate_receipt_limit(1).is_ok());
assert!(validate_receipt_limit(MAX_RECEIPT_LIMIT).is_ok());
assert!(validate_receipt_limit(0).is_err());
assert!(validate_receipt_limit(MAX_RECEIPT_LIMIT + 1).is_err());
assert!(validate_receipt_lookup("request-1", Some("incarnation-1")).is_ok());
assert!(validate_receipt_lookup("request\n1", None).is_err());
}
#[test]
fn synthetic_probe_cannot_claim_actual_usage() {
let report = CheckerProbeReport::new(ProbeResult {
checker_id: "company".into(),
reachability: ProbeReachability::Reachable,
protocol: ProbeProtocolStatus::Valid,
latency_ms: Some(4),
implementation_version: Some("fixture-v1".into()),
decision: Some(CheckerProbeDecision::Allow),
error_code: None,
observed_at_unix_ms: 1,
});
assert!(report.synthetic);
assert!(!report.counts_as_usage);
}
}