Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ All notable changes to OriginWeave are documented in this file. The format follo
- Credential-free TLS evidence containing canonical origin, TCP peers, reference identity, TLS version, cipher-suite identifier, selected ALPN or explicit absence, leaf certificate and SPKI hashes, server-presented certificate hashes and bounds, trust-bundle identity and hash, validity interval, fixed verification time, revocation configuration, and measured handshake duration.
- Credential-free sensitive-handle lifecycle evidence binds issuance, exclusive expiry, bounded uses, observed resolution count, and revocation to the exact credential-free `OpaqueHandleOnly` sensitive-access receipt, preserving tenant, actor, task, field set, purpose, destination, classification, policy version, and decision time without storing opaque handle tokens or protected values.
- Credential-free connection and redirect evidence containing canonical addresses, destination classes, target digests, hop numbers, and approved-address counts.
- Credential-free verified TCP evidence containing the logical origin, requested socket, observed peer, destination class, successful attempt number, and per-attempt timeout.
- Standard `Display` and `std::error::Error` contracts for destination, redirect, digest, direct-network, TLS, and resource-budget failures, including preserved destination-policy, rustls, and operating-system sources where applicable.
- Standard `Display` and `std::error::Error` contracts for core extension identifiers, destination, redirect, digest, direct-network, TLS, and resource-budget failures, including preserved destination-policy, rustls, and operating-system sources where applicable.
- Real loopback TCP integration proof plus deterministic timeout, refusal, retry, peer-inspection, peer-mismatch, canonicalization, IPv6 metadata, and single-use replay tests.
- Real loopback rustls integration covering trusted DNS SAN, Common-Name fallback rejection, wrong-name and untrusted-root rejection, fixed-time expiry and not-yet-valid failures, exact IPv4 and IPv6 SANs, TLS 1.2/TLS 1.3, required and optional ALPN, and transport-origin binding.
- Cumulative interactive-first RAM, VRAM, batch, local-model, admission, pause, and compositor-pressure mitigation plans, including active-consumer reduction at exact hard limits.
Expand Down
12 changes: 12 additions & 0 deletions crates/originweave-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,18 @@ pub enum ExtensionIdError {
InvalidExtensionId,
}

impl fmt::Display for ExtensionIdError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidExtensionId => formatter.write_str(
"extension identifier must be exactly 32 lowercase characters from a through p",
),
}
}
}

impl std::error::Error for ExtensionIdError {}

/// An OriginWeave Agent capability that a browser extension may request explicitly.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ExtensionAgentCapability {
Expand Down
21 changes: 21 additions & 0 deletions crates/originweave-core/tests/extension_error_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::error::Error;

use originweave_core::{ExtensionId, ExtensionIdError};

fn assert_standard_error<T: Error>() {}

#[test]
fn extension_id_error_exposes_a_stable_standard_error_contract() {
assert_standard_error::<ExtensionIdError>();

let result = ExtensionId::parse("invalid");
assert_eq!(result, Err(ExtensionIdError::InvalidExtensionId));

let rendered = result.as_ref().err().map(ToString::to_string);
assert_eq!(
rendered.as_deref(),
Some("extension identifier must be exactly 32 lowercase characters from a through p")
);
let source = result.as_ref().err().and_then(|error| error.source());
assert!(source.is_none());
}
Loading