cortexkit-log 0.3.2

Fleet logging format, filtering, redaction, and retention for CortexKit modules
Documentation
use std::borrow::Cow;
use std::sync::LazyLock;

use regex::{Captures, Regex};

const REDACTED: &str = "[REDACTED]";

static BEARER: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"(?i)\b(Bearer)[ \t]+[A-Za-z0-9._~+/=-]+").expect("valid bearer regex")
});
static JWT: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"\beyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b").expect("valid JWT regex")
});
static CORTEXKIT_HANDLE: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"\bckh_[A-Za-z0-9_-]+\b").expect("valid CortexKit handle regex"));
static OPENAI_KEY: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"\bsk-[A-Za-z0-9_-]+\b").expect("valid OpenAI key regex"));
static GITHUB_TOKEN: LazyLock<Regex> =
    LazyLock::new(|| Regex::new(r"\bgh[po]_[A-Za-z0-9_-]+\b").expect("valid GitHub token regex"));

pub(crate) fn fleet_redact(line: &str) -> Cow<'_, str> {
    let authorization_redacted = redact_authorization(line);
    let bearer_redacted = BEARER.replace_all(&authorization_redacted, |captures: &Captures<'_>| {
        format!("{} {REDACTED}", &captures[1])
    });
    let jwt_redacted = JWT.replace_all(&bearer_redacted, REDACTED);
    let handle_redacted = CORTEXKIT_HANDLE.replace_all(&jwt_redacted, REDACTED);
    let openai_redacted = OPENAI_KEY.replace_all(&handle_redacted, REDACTED);
    let github_redacted = GITHUB_TOKEN.replace_all(&openai_redacted, REDACTED);

    if github_redacted == line {
        Cow::Borrowed(line)
    } else {
        Cow::Owned(github_redacted.into_owned())
    }
}

fn redact_authorization(input: &str) -> Cow<'_, str> {
    let lowercase = input.to_ascii_lowercase();
    let mut search_from = 0;
    let mut output = String::new();
    let mut copied_through = 0;

    while let Some(relative) = lowercase[search_from..].find("authorization:") {
        let marker = search_from + relative;
        let after_marker = marker + "authorization:".len();
        let mut value_start = after_marker;
        while input
            .as_bytes()
            .get(value_start)
            .is_some_and(u8::is_ascii_whitespace)
        {
            value_start += 1;
        }
        if value_start >= input.len() {
            break;
        }

        let value_end = authorization_value_end(input, value_start);
        let redaction_start = if input.as_bytes()[value_start] == b'"' {
            value_start + 1
        } else if input.as_bytes()[value_start] == b'\\'
            && input.as_bytes().get(value_start + 1) == Some(&b'"')
        {
            value_start + 2
        } else {
            value_start
        };
        output.push_str(&input[copied_through..redaction_start]);
        output.push_str(REDACTED);
        copied_through = value_end;
        search_from = value_end;
    }

    if copied_through == 0 {
        Cow::Borrowed(input)
    } else {
        output.push_str(&input[copied_through..]);
        Cow::Owned(output)
    }
}

fn authorization_value_end(input: &str, start: usize) -> usize {
    let bytes = input.as_bytes();
    if bytes[start] == b'"' {
        return quoted_end(bytes, start + 1, false);
    }
    if bytes[start] == b'\\' && bytes.get(start + 1) == Some(&b'"') {
        return quoted_end(bytes, start + 2, true);
    }

    let first_end = token_end(bytes, start);
    let scheme = &input[start..first_end];
    if !["basic", "bearer", "digest"].contains(&scheme.to_ascii_lowercase().as_str()) {
        return preserve_escaped_quote(bytes, start, first_end);
    }

    let mut credential_start = first_end;
    while bytes
        .get(credential_start)
        .is_some_and(u8::is_ascii_whitespace)
    {
        credential_start += 1;
    }
    let credential_end = token_end(bytes, credential_start);
    preserve_escaped_quote(bytes, credential_start, credential_end)
}

fn quoted_end(bytes: &[u8], mut index: usize, escaped_delimiter: bool) -> usize {
    while index < bytes.len() {
        if escaped_delimiter && bytes[index] == b'\\' && bytes.get(index + 1) == Some(&b'"') {
            return index;
        }
        if !escaped_delimiter && bytes[index] == b'"' {
            return index;
        }
        index += 1;
    }
    bytes.len()
}

fn token_end(bytes: &[u8], mut index: usize) -> usize {
    while bytes
        .get(index)
        .is_some_and(|byte| !byte.is_ascii_whitespace())
    {
        index += 1;
    }
    index
}

fn preserve_escaped_quote(bytes: &[u8], start: usize, end: usize) -> usize {
    if end >= start + 2 && bytes.get(end - 2..end) == Some(br#"\""#) {
        end - 2
    } else if end > start && bytes[end - 1] == b'"' {
        end - 1
    } else {
        end
    }
}