systemprompt-api 0.9.2

Axum-based HTTP server and API gateway for systemprompt.io AI governance infrastructure. Exposes governed agents, MCP, A2A, and admin endpoints with rate limiting and RBAC.
Documentation
pub(super) fn is_low_entropy_challenge(challenge: &str) -> bool {
    let Some(first_char) = challenge.chars().next() else {
        return true;
    };

    if challenge.chars().all(|c| c == first_char) {
        return true;
    }

    if has_repeating_pattern(challenge) {
        return true;
    }

    if has_sequential_run(challenge) {
        return true;
    }

    if has_low_diversity(challenge) {
        return true;
    }

    if shannon_entropy(challenge) < 3.0 {
        return true;
    }

    false
}

fn shannon_entropy(data: &str) -> f64 {
    let len = data.len() as f64;
    if len == 0.0 {
        return 0.0;
    }

    let mut freq = std::collections::HashMap::new();
    for c in data.chars() {
        *freq.entry(c).or_insert(0u64) += 1;
    }

    freq.values().fold(0.0, |entropy, &count| {
        let p = count as f64 / len;
        p.mul_add(-p.log2(), entropy)
    })
}

fn has_repeating_pattern(challenge: &str) -> bool {
    for pattern_length in 2..=4 {
        if challenge.len() >= pattern_length * 3 {
            let pattern = &challenge[..pattern_length];
            let repetitions = challenge.len() / pattern_length;
            if repetitions >= 3 {
                let repeated = pattern.repeat(repetitions);
                if challenge.starts_with(&repeated) {
                    return true;
                }
            }
        }
    }
    false
}

fn has_sequential_run(challenge: &str) -> bool {
    use systemprompt_oauth::constants::validation::MIN_SEQUENTIAL_RUN;

    let chars: Vec<char> = challenge.chars().collect();
    if chars.len() < MIN_SEQUENTIAL_RUN {
        return false;
    }

    let mut ascending_count = 1;
    let mut descending_count = 1;

    for i in 1..chars.len() {
        if let (Some(prev), Some(curr)) = (chars[i - 1].to_digit(36), chars[i].to_digit(36)) {
            if curr == prev.wrapping_add(1) {
                ascending_count += 1;
                if ascending_count >= MIN_SEQUENTIAL_RUN {
                    return true;
                }
            } else {
                ascending_count = 1;
            }

            if prev == curr.wrapping_add(1) {
                descending_count += 1;
                if descending_count >= MIN_SEQUENTIAL_RUN {
                    return true;
                }
            } else {
                descending_count = 1;
            }
        }
    }
    false
}

fn has_low_diversity(challenge: &str) -> bool {
    use systemprompt_oauth::constants::validation::{DIVERSITY_THRESHOLD, MIN_UNIQUE_CHARS};

    let unique_chars: std::collections::HashSet<char> = challenge.chars().collect();
    let entropy_ratio = unique_chars.len() as f64 / challenge.len() as f64;

    if entropy_ratio < DIVERSITY_THRESHOLD {
        return true;
    }

    let min_unique_for_length = challenge.len() / 2;
    unique_chars.len() < min_unique_for_length.min(MIN_UNIQUE_CHARS)
}