parlov-core 0.7.0

Shared types, error types, and oracle class definitions for parlov.
Documentation

parlov-core

Shared types for HTTP oracle detection. Zero I/O, zero async — just data structures.

types

use parlov_core::{
    ResponseSurface, ProbeDefinition, ProbeExchange, DifferentialSet,
    OracleResult, Technique, Vector, NormativeStrength, Signal, SignalKind,
    StrategyOutcome, EndpointVerdict, ContributingFinding,
    ObservabilityStatus, BlockSummary, RequestAuthState,
    ResponseClass, Applicability, SignalSurface,
};

ResponseSurface — one captured HTTP interaction:

pub struct ResponseSurface {
    pub status: StatusCode,
    pub headers: HeaderMap,
    pub body: Bytes,
    pub timing_ns: u64,
}

ProbeDefinition — one HTTP request to execute:

pub struct ProbeDefinition {
    pub url: String,
    pub method: Method,
    pub headers: HeaderMap,      // auth context lives here
    pub body: Option<Bytes>,
}

ProbeExchange — paired request and response:

pub struct ProbeExchange {
    pub request: ProbeDefinition,
    pub response: ResponseSurface,
}

DifferentialSet — paired exchanges with technique context (replaces ProbeSet):

pub struct DifferentialSet {
    pub baseline: Vec<ProbeExchange>,
    pub probe: Vec<ProbeExchange>,
    pub technique: Technique,
}

Technique — strategy metadata. Drives both probe construction and analyzer routing:

pub struct Technique {
    pub id: &'static str,
    pub name: &'static str,
    pub oracle_class: OracleClass,
    pub vector: Vector,                              // StatusCodeDiff, CacheProbing, ErrorMessageGranularity, RedirectDiff
    pub strength: NormativeStrength,                 // Must, MustNot, Should, May
    pub normalization_weight: Option<f32>,           // weight on SameStatus path; None ⇒ NoSignal
    pub inverted_signal_weight: Option<f32>,         // weight on inverted differential (rate-limit burst/headers)
    pub method_relevant: bool,                       // true only if 405 is the oracle (very rare)
    pub parser_relevant: bool,                       // true when parser/validator response IS the oracle
    pub applicability: fn(&ResponseSurface, &ResponseSurface) -> Applicability, // marker-presence grading
    pub contradiction_surface: SignalSurface,        // surface SameStatus is evaluated against
}

Signal and SignalKind — typed observations from differential analysis:

pub struct Signal {
    pub kind: SignalKind,
    pub description: String,
}

OracleResult — the analysis output:

pub struct OracleResult {
    pub class: OracleClass,                          // Existence, Authentication, Timing, ...
    pub verdict: OracleVerdict,                      // Confirmed / Likely / NotPresent
    pub severity: Option<Severity>,                  // High / Medium / Low
    pub confidence: u8,                              // 0-100 weighted score
    pub impact_class: Option<ImpactClass>,           // Low / Medium / High leak impact
    pub reasons: Vec<ScoringReason>,                 // audit trail for scoring decisions
    pub label: Option<String>,                       // "Authorization-based differential"
    pub leaks: Option<String>,                       // "Resource existence confirmed to low-privilege callers"
    pub rfc_basis: Option<String>,                   // "RFC 9110 §15.5.4"
    pub signals: Vec<Signal>,                        // typed observations from analysis
    pub technique_id: Option<String>,                // originating strategy id
    pub vector: Option<Vector>,                      // detection method
    pub normative_strength: Option<NormativeStrength>, // RFC mandate level
}

ImpactClass — leak severity classification:

pub enum ImpactClass { Low, Medium, High }

ScoringReason — audit trail entry for a scoring decision:

pub struct ScoringReason {
    pub dimension: ScoringDimension,  // Confidence or Severity
    pub description: String,
}

All types derive Serialize and Deserialize with custom serde helpers for StatusCode, Method, and HeaderMap (the http crate types lack native serde support).

finding_id() — deterministic SHA-256 finding ID from technique, target, and status pair for cross-run deduplication.

use it

Build a differential set from captured HTTP exchanges:

use parlov_core::{
    ProbeExchange, ProbeDefinition, ResponseSurface,
    DifferentialSet, Technique, Vector, NormativeStrength,
};
use bytes::Bytes;
use http::{HeaderMap, Method, StatusCode};

let exchange = ProbeExchange {
    request: ProbeDefinition {
        url: "https://api.example.com/users/123".into(),
        method: Method::GET,
        headers: HeaderMap::new(),
        body: None,
    },
    response: ResponseSurface {
        status: StatusCode::FORBIDDEN,
        headers: HeaderMap::new(),
        body: Bytes::new(),
        timing_ns: 12_500_000,
    },
};

errors

use parlov_core::Error;

Four variants via thiserror: Http(String), Cli(String), Analysis(String), Serialization(serde_json::Error).

license

MIT OR Apache-2.0