cloud-sdk 0.50.0

no_std-first provider-neutral cloud SDK foundations.
Documentation
use super::fixture::endpoint;
use super::{
    FingerprintScope, MonotonicDuration, MonotonicInstant, RetryController, RetryDecision,
    RetryEvent, RetryPolicyError, build_canonical_fingerprint, policy,
};
use crate::authentication::{AuthenticationScopePolicy, ScopeRequirement};
use crate::operation::{
    ContentTypePolicy, CostIntent, OperationId, OperationImpact, OperationMetadata,
    PreparedRequest, ProviderService, RequestIdPolicy, RequestSemantics, ResponseBodyPolicy,
    ResponsePolicy, RetryEligibility,
};
use crate::transport::{
    AcknowledgedCustomEndpoint, CustomEndpointAcknowledgement, EndpointPolicy, MediaType,
    RawResponsePolicy, RequestHeader, RequestHeaders, RequestTarget, ResponseMediaPolicy,
    StatusCode, TransportRequest,
};
use crate::{Method, ProviderId, ServiceId};

static OK: [StatusCode; 1] = [StatusCode::OK];
static JSON: [MediaType<'static>; 1] = [MediaType::JSON];

#[derive(Clone, Copy)]
enum PolicyVariant {
    Baseline,
    Metadata,
    Replayability,
    EndpointPolicy,
    ResponsePolicy,
    AuthenticationPolicy,
    RawResponsePolicy,
    HeaderSensitivity,
}

#[test]
fn identical_wire_bytes_cannot_launder_any_prepared_policy() {
    for variant in [
        PolicyVariant::Metadata,
        PolicyVariant::Replayability,
        PolicyVariant::EndpointPolicy,
        PolicyVariant::ResponsePolicy,
        PolicyVariant::AuthenticationPolicy,
        PolicyVariant::RawResponsePolicy,
    ] {
        assert_policy_rejected(variant);
    }
}

#[test]
fn header_sensitivity_is_bound_to_fingerprint_and_retry_policy() {
    let Some(endpoint) = endpoint() else { return };
    let Ok(sensitive) = RequestHeader::sensitive("x-retry-secret", "same-value") else {
        return;
    };
    let Ok(public) = RequestHeader::new("x-retry-secret", "same-value") else {
        return;
    };
    let sensitive_headers = [sensitive];
    let public_headers = [public];
    let Ok(sensitive_headers) = RequestHeaders::new(&sensitive_headers) else {
        return;
    };
    let Ok(public_headers) = RequestHeaders::new(&public_headers) else {
        return;
    };
    let Some(initial) = request_with_headers(PolicyVariant::Baseline, sensitive_headers) else {
        return;
    };
    let Some(replay) = request_with_headers(PolicyVariant::HeaderSensitivity, public_headers)
    else {
        return;
    };
    let mut initial_storage = [0_u8; 512];
    let mut replay_storage = [0_u8; 512];
    let Ok(initial_fingerprint) = build_canonical_fingerprint(
        initial,
        endpoint,
        FingerprintScope::Absent,
        &mut initial_storage,
    ) else {
        return;
    };
    let Ok(replay_fingerprint) = build_canonical_fingerprint(
        replay,
        endpoint,
        FingerprintScope::Absent,
        &mut replay_storage,
    ) else {
        return;
    };
    assert!(
        !initial_fingerprint
            .as_ref()
            .matches(replay_fingerprint.as_ref())
    );
    assert!(!initial.has_same_retry_policy(&replay));

    let Some(policy) = policy(2, 0, 20) else {
        return;
    };
    let Ok(mut controller) = RetryController::new(
        initial_fingerprint.subject(),
        None,
        policy,
        MonotonicInstant::new(0),
    ) else {
        return;
    };
    assert!(matches!(
        controller.decide_retry(
            RetryEvent::Response(StatusCode::new(500).unwrap_or(StatusCode::OK)),
            replay_fingerprint.subject(),
            MonotonicDuration::new(0),
            MonotonicInstant::new(5),
        ),
        Err(RetryPolicyError::FingerprintMismatch)
    ));
}

fn assert_policy_rejected(variant: PolicyVariant) {
    let Some(endpoint) = endpoint() else { return };
    let Some(initial) = request(PolicyVariant::Baseline) else {
        return;
    };
    let Some(replay) = request(variant) else {
        return;
    };
    let mut initial_storage = [0_u8; 512];
    let mut replay_storage = [0_u8; 512];
    let Ok(initial_fingerprint) = build_canonical_fingerprint(
        initial,
        endpoint,
        FingerprintScope::Absent,
        &mut initial_storage,
    ) else {
        return;
    };
    let Ok(replay_fingerprint) = build_canonical_fingerprint(
        replay,
        endpoint,
        FingerprintScope::Absent,
        &mut replay_storage,
    ) else {
        return;
    };
    assert!(
        initial_fingerprint
            .as_ref()
            .matches(replay_fingerprint.as_ref())
    );
    let Some(policy) = policy(2, 0, 20) else {
        return;
    };
    let Ok(mut controller) = RetryController::new(
        initial_fingerprint.subject(),
        None,
        policy,
        MonotonicInstant::new(0),
    ) else {
        return;
    };

    assert!(matches!(
        controller.decide_retry(
            RetryEvent::Response(StatusCode::new(500).unwrap_or(StatusCode::OK)),
            replay_fingerprint.subject(),
            MonotonicDuration::new(0),
            MonotonicInstant::new(5),
        ),
        Err(RetryPolicyError::ReplayPolicyMismatch)
    ));
    assert_eq!(controller.attempts(), 1);
    assert_eq!(controller.cumulative_delay().get(), 0);

    let accepted = controller.decide_retry(
        RetryEvent::Response(StatusCode::new(500).unwrap_or(StatusCode::OK)),
        initial_fingerprint.subject(),
        MonotonicDuration::new(0),
        MonotonicInstant::new(0),
    );
    assert!(matches!(accepted, Ok(RetryDecision::Retry(_))));
}

fn request(variant: PolicyVariant) -> Option<PreparedRequest<'static>> {
    request_with_headers(variant, RequestHeaders::EMPTY)
}

fn request_with_headers<'a>(
    variant: PolicyVariant,
    headers: RequestHeaders<'a>,
) -> Option<PreparedRequest<'a>> {
    let endpoint = endpoint()?;
    let provider = ProviderId::new("example").ok()?;
    let service = ServiceId::new("compute").ok()?;
    let endpoint_policy = if matches!(variant, PolicyVariant::EndpointPolicy) {
        EndpointPolicy::acknowledged_custom(AcknowledgedCustomEndpoint::new(
            endpoint,
            CustomEndpointAcknowledgement::trusted_operator_configuration(),
        ))
    } else {
        EndpointPolicy::fixed(endpoint)
    };
    let metadata = if matches!(variant, PolicyVariant::Metadata) {
        OperationMetadata::new(
            OperationImpact::Destructive,
            RequestSemantics::NonIdempotent,
            RetryEligibility::Never,
            CostIntent::MayIncurCost,
            RequestIdPolicy::Discard,
        )
        .ok()?
    } else {
        OperationMetadata::new(
            OperationImpact::ReadOnly,
            RequestSemantics::Safe,
            RetryEligibility::ExplicitPolicy,
            CostIntent::NoKnownCost,
            RequestIdPolicy::Discard,
        )
        .ok()?
    };
    let response_limit = if matches!(variant, PolicyVariant::ResponsePolicy) {
        63
    } else {
        64
    };
    let response = ResponsePolicy::new(
        &OK,
        ContentTypePolicy::Required(&JSON),
        ResponseBodyPolicy::Required,
        response_limit,
    )
    .ok()?;
    let provider_requirement = if matches!(variant, PolicyVariant::AuthenticationPolicy) {
        ScopeRequirement::Required(provider)
    } else {
        ScopeRequirement::Forbidden
    };
    let authentication = AuthenticationScopePolicy::new(
        provider_requirement,
        ScopeRequirement::Forbidden,
        ScopeRequirement::Forbidden,
        ScopeRequirement::Forbidden,
        ScopeRequirement::Forbidden,
        ScopeRequirement::Forbidden,
    );
    let raw_limit = if matches!(variant, PolicyVariant::RawResponsePolicy) {
        65
    } else {
        64
    };
    let raw = RawResponsePolicy::new(
        raw_limit,
        raw_limit,
        ResponseMediaPolicy::Required(&JSON),
        ResponseMediaPolicy::Required(&JSON),
        &[],
        0,
    )
    .ok()?;
    let request = TransportRequest::new(Method::Post, RequestTarget::new("/same-wire").ok()?)
        .with_headers(headers)
        .with_body(b"{}");
    let prepared = PreparedRequest::new(
        request,
        ProviderService::new(provider, service, endpoint_policy),
        metadata,
        response,
        authentication,
        raw,
    )
    .ok()?
    .with_operation_id(OperationId::new("same_operation").ok()?);
    Some(if matches!(variant, PolicyVariant::Replayability) {
        prepared
    } else {
        prepared.with_replayable_body()
    })
}