chio-http-core 0.1.2

Protocol-agnostic HTTP security types for the Chio kernel
Documentation
use std::collections::BTreeSet;

use chio_http_core::{HttpEgressContract, HttpEgressError};

fn strict_contract() -> HttpEgressContract {
    HttpEgressContract {
        tenant_egress_namespace: "tenant-a.prod".to_string(),
        allowed_schemes: BTreeSet::from(["https".to_string()]),
        allowed_authority_set: BTreeSet::from([
            "api.example.com".to_string(),
            "api.example.com:8443".to_string(),
            "127.0.0.1".to_string(),
            "169.254.169.254".to_string(),
            "[fd00::1]".to_string(),
            "[::ffff:127.0.0.1]".to_string(),
        ]),
        deny_loopback: true,
        deny_link_local: true,
        deny_ipv6_ula: true,
        max_redirect_chain: 2,
        max_response_bytes: 4096,
    }
}

#[test]
fn allows_declared_public_authority() {
    let contract = strict_contract();
    let target = match contract.enforce_attempt("https://api.example.com/v1/tools", 1, Some(4096)) {
        Ok(target) => target,
        Err(error) => panic!("public declared authority should pass: {error}"),
    };

    assert_eq!(target.tenant_egress_namespace, "tenant-a.prod");
    assert_eq!(target.scheme, "https");
    assert_eq!(target.authority, "api.example.com");
}

#[test]
fn allows_default_port_authority_entry() {
    let mut contract = strict_contract();
    contract.allowed_authority_set = BTreeSet::from(["api.example.com:443".to_string()]);

    let target = match contract.enforce_attempt("https://api.example.com:443/v1/tools", 0, None) {
        Ok(target) => target,
        Err(error) => panic!("default-port authority should pass: {error}"),
    };

    assert_eq!(target.authority, "api.example.com");
}

#[test]
fn missing_contract_fails_closed() {
    let err = match HttpEgressContract::enforce_required(
        None,
        "https://api.example.com/v1/tools",
        0,
        None,
    ) {
        Ok(_) => panic!("missing contract must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(err, HttpEgressError::MissingContract));
}

#[test]
fn loopback_target_fails_closed_even_when_declared() {
    let contract = strict_contract();
    let err = match contract.enforce_url("https://127.0.0.1/admin", 0) {
        Ok(_) => panic!("loopback target must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(err, HttpEgressError::LoopbackDenied { .. }));
}

#[test]
fn ipv4_mapped_loopback_fails_closed() {
    let contract = strict_contract();
    let err = match contract.enforce_url("https://[::ffff:127.0.0.1]/admin", 0) {
        Ok(_) => panic!("IPv4-mapped loopback target must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(err, HttpEgressError::LoopbackDenied { .. }));
}

#[test]
fn link_local_target_fails_closed_even_when_declared() {
    let contract = strict_contract();
    let err = match contract.enforce_url("https://169.254.169.254/latest/meta-data", 0) {
        Ok(_) => panic!("link-local target must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(err, HttpEgressError::LinkLocalDenied { .. }));
}

#[test]
fn ipv6_ula_target_fails_closed_even_when_declared() {
    let contract = strict_contract();
    let err = match contract.enforce_url("https://[fd00::1]/internal", 0) {
        Ok(_) => panic!("IPv6 ULA target must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(err, HttpEgressError::Ipv6UlaDenied { .. }));
}

#[test]
fn redirect_chain_limit_fails_closed() {
    let contract = strict_contract();
    let err = match contract.enforce_url("https://api.example.com/v1/tools", 3) {
        Ok(_) => panic!("overlong redirect chain must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(
        err,
        HttpEgressError::RedirectLimitExceeded {
            observed: 3,
            max: 2
        }
    ));
}

#[test]
fn oversized_response_fails_closed() {
    let contract = strict_contract();
    let err = match contract.enforce_attempt("https://api.example.com/v1/tools", 0, Some(4097)) {
        Ok(_) => panic!("oversized response must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(
        err,
        HttpEgressError::ResponseTooLarge {
            observed: 4097,
            max: 4096
        }
    ));
}

#[test]
fn undeclared_authority_fails_closed() {
    let contract = strict_contract();
    let err = match contract.enforce_url("https://api.example.com.evil.test/v1/tools", 0) {
        Ok(_) => panic!("undeclared authority must fail closed"),
        Err(error) => error,
    };

    assert!(matches!(err, HttpEgressError::AuthorityDenied { .. }));
}