From 9f987aedb1d6370d9e23b6afefd8be89f1e97bc2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:18:16 +0900 Subject: [PATCH 1/9] test(core): require atomic browser protocol use validation --- .../tests/browser_protocol_use_validation.rs | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 crates/originweave-core/tests/browser_protocol_use_validation.rs diff --git a/crates/originweave-core/tests/browser_protocol_use_validation.rs b/crates/originweave-core/tests/browser_protocol_use_validation.rs new file mode 100644 index 000000000..536b2f2b3 --- /dev/null +++ b/crates/originweave-core/tests/browser_protocol_use_validation.rs @@ -0,0 +1,112 @@ +use std::error::Error; + +use originweave_core::{ + BrowserProtocolAdapterDescriptor, BrowserProtocolCapability, BrowserProtocolKind, + BrowserProtocolUseValidationError, BrowserProtocolVersionRequirementError, + OriginWeaveProtocolVersion, +}; + +const ORIGINWEAVE_PROTOCOL_VERSION: OriginWeaveProtocolVersion = + OriginWeaveProtocolVersion::new(0, 1); +const ADAPTER_VERSION: &str = "originweave-bidi-v1"; +const PROTOCOL_REVISION: &str = "webdriver-bidi-wd-2026-06-01"; +const BROWSER_REVISION: &str = "chromium-r1639810"; + +fn descriptor() -> Result> { + Ok(BrowserProtocolAdapterDescriptor::new( + BrowserProtocolKind::WebDriverBiDi, + ORIGINWEAVE_PROTOCOL_VERSION, + ADAPTER_VERSION, + PROTOCOL_REVISION, + BROWSER_REVISION, + &[ + BrowserProtocolCapability::Navigation, + BrowserProtocolCapability::TypedInput, + ], + )?) +} + +#[test] +fn validated_use_binds_all_required_adapter_metadata() -> Result<(), Box> { + let descriptor = descriptor()?; + let validated = descriptor.validate_use( + ORIGINWEAVE_PROTOCOL_VERSION, + PROTOCOL_REVISION, + BROWSER_REVISION, + BrowserProtocolCapability::Navigation, + )?; + + assert_eq!(validated.kind(), BrowserProtocolKind::WebDriverBiDi); + assert_eq!( + validated.originweave_protocol_version(), + ORIGINWEAVE_PROTOCOL_VERSION + ); + assert_eq!(validated.adapter_version(), ADAPTER_VERSION); + assert_eq!(validated.protocol_revision(), PROTOCOL_REVISION); + assert_eq!(validated.browser_revision(), BROWSER_REVISION); + assert_eq!( + validated.capability(), + BrowserProtocolCapability::Navigation + ); + Ok(()) +} + +#[test] +fn protocol_generation_mismatch_precedes_runtime_and_capability_checks() -> Result<(), Box> { + let descriptor = descriptor()?; + let wrong_generation = OriginWeaveProtocolVersion::new(0, 2); + + assert_eq!( + descriptor.validate_use( + wrong_generation, + "runtime revision with spaces", + "browser/revision", + BrowserProtocolCapability::NetworkObservation, + ), + Err(BrowserProtocolUseValidationError::ProtocolVersion( + BrowserProtocolVersionRequirementError::ProtocolVersionMismatch { + required: wrong_generation, + actual: ORIGINWEAVE_PROTOCOL_VERSION, + } + )) + ); + Ok(()) +} + +#[test] +fn runtime_revision_validation_precedes_capability_check() -> Result<(), Box> { + let descriptor = descriptor()?; + + assert_eq!( + descriptor.validate_use( + ORIGINWEAVE_PROTOCOL_VERSION, + "webdriver-bidi-wd-2026-07-01", + BROWSER_REVISION, + BrowserProtocolCapability::NetworkObservation, + ), + Err(BrowserProtocolUseValidationError::RuntimeRevision( + originweave_core::BrowserProtocolRuntimeRequirementError::ProtocolRevisionMismatch, + )) + ); + Ok(()) +} + +#[test] +fn undeclared_capability_cannot_produce_validated_use() -> Result<(), Box> { + let descriptor = descriptor()?; + + assert_eq!( + descriptor.validate_use( + ORIGINWEAVE_PROTOCOL_VERSION, + PROTOCOL_REVISION, + BROWSER_REVISION, + BrowserProtocolCapability::NetworkObservation, + ), + Err(BrowserProtocolUseValidationError::Capability( + originweave_core::BrowserProtocolCapabilityRequirementError::UnsupportedCapability( + BrowserProtocolCapability::NetworkObservation, + ), + )) + ); + Ok(()) +} From e5a55985ef9009d8044c2c68c92e58a64660786f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:20:51 +0900 Subject: [PATCH 2/9] style(core): apply canonical browser protocol validation formatting --- .../originweave-core/tests/browser_protocol_use_validation.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/originweave-core/tests/browser_protocol_use_validation.rs b/crates/originweave-core/tests/browser_protocol_use_validation.rs index 536b2f2b3..ba559a5af 100644 --- a/crates/originweave-core/tests/browser_protocol_use_validation.rs +++ b/crates/originweave-core/tests/browser_protocol_use_validation.rs @@ -52,7 +52,8 @@ fn validated_use_binds_all_required_adapter_metadata() -> Result<(), Box Result<(), Box> { +fn protocol_generation_mismatch_precedes_runtime_and_capability_checks() +-> Result<(), Box> { let descriptor = descriptor()?; let wrong_generation = OriginWeaveProtocolVersion::new(0, 2); From 8d8e9b9bc38072113ff82516a89ce9b276383155 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:23:57 +0900 Subject: [PATCH 3/9] feat(core): validate browser protocol use prerequisites atomically --- .../originweave-core/src/browser_protocol.rs | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/crates/originweave-core/src/browser_protocol.rs b/crates/originweave-core/src/browser_protocol.rs index a23e6c3e1..369666ece 100644 --- a/crates/originweave-core/src/browser_protocol.rs +++ b/crates/originweave-core/src/browser_protocol.rs @@ -289,6 +289,87 @@ impl BrowserProtocolAdapterDescriptor { Err(BrowserProtocolCapabilityRequirementError::UnsupportedCapability(capability)) } } + + /// Validate all adapter metadata prerequisites for one immediate browser operation. + /// + /// Validation is intentionally ordered and fail closed: the exact + /// OriginWeave Protocol generation is checked first, then the supplied + /// runtime protocol/browser revisions, then the required adapter + /// capability. Success returns a non-cloneable value that a later trusted + /// transport can consume as proof that these metadata prerequisites were + /// checked together. It is not browser or Agent authority and does not + /// authenticate the caller supplying runtime revision evidence. + pub fn validate_use( + &self, + required_originweave_protocol_version: OriginWeaveProtocolVersion, + runtime_protocol_revision: &str, + runtime_browser_revision: &str, + required_capability: BrowserProtocolCapability, + ) -> Result { + self.require_originweave_protocol_version(required_originweave_protocol_version) + .map_err(BrowserProtocolUseValidationError::ProtocolVersion)?; + self.require_runtime_revisions(runtime_protocol_revision, runtime_browser_revision) + .map_err(BrowserProtocolUseValidationError::RuntimeRevision)?; + self.require_capability(required_capability) + .map_err(BrowserProtocolUseValidationError::Capability)?; + + Ok(ValidatedBrowserProtocolUse { + descriptor: self.clone(), + capability: required_capability, + }) + } +} + +/// Snapshot proving that one descriptor passed all browser-protocol metadata checks for one use. +/// +/// Only [`BrowserProtocolAdapterDescriptor::validate_use`] can construct this +/// value. It intentionally does not implement `Clone`: a future trusted browser +/// transport can consume the value by ownership at the operation boundary +/// rather than treating it as reusable ambient authority. The value still does +/// not authenticate an adapter or attest that supplied runtime metadata came +/// from the running browser process. +#[derive(Debug, PartialEq, Eq)] +pub struct ValidatedBrowserProtocolUse { + descriptor: BrowserProtocolAdapterDescriptor, + capability: BrowserProtocolCapability, +} + +impl ValidatedBrowserProtocolUse { + /// Return the validated browser protocol family. + #[must_use] + pub const fn kind(&self) -> BrowserProtocolKind { + self.descriptor.kind + } + + /// Return the validated OriginWeave Protocol generation. + #[must_use] + pub const fn originweave_protocol_version(&self) -> OriginWeaveProtocolVersion { + self.descriptor.originweave_protocol_version + } + + /// Return the validated bounded adapter-version metadata token. + #[must_use] + pub fn adapter_version(&self) -> &str { + &self.descriptor.adapter_version + } + + /// Return the validated bounded upstream protocol-revision metadata token. + #[must_use] + pub fn protocol_revision(&self) -> &str { + &self.descriptor.protocol_revision + } + + /// Return the validated bounded browser-revision metadata token. + #[must_use] + pub fn browser_revision(&self) -> &str { + &self.descriptor.browser_revision + } + + /// Return the exact adapter capability validated for this use. + #[must_use] + pub const fn capability(&self) -> BrowserProtocolCapability { + self.capability + } } const fn capability_rank(capability: BrowserProtocolCapability) -> u8 { @@ -398,6 +479,37 @@ impl fmt::Display for BrowserProtocolCapabilityRequirementError { impl std::error::Error for BrowserProtocolCapabilityRequirementError {} +/// Failure to validate all browser-protocol metadata prerequisites for one use. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BrowserProtocolUseValidationError { + /// The descriptor targets the wrong OriginWeave Protocol generation. + ProtocolVersion(BrowserProtocolVersionRequirementError), + /// The supplied runtime protocol or browser revision is invalid or has drifted. + RuntimeRevision(BrowserProtocolRuntimeRequirementError), + /// The descriptor does not explicitly declare the required capability. + Capability(BrowserProtocolCapabilityRequirementError), +} + +impl fmt::Display for BrowserProtocolUseValidationError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::ProtocolVersion(error) => error.fmt(formatter), + Self::RuntimeRevision(error) => error.fmt(formatter), + Self::Capability(error) => error.fmt(formatter), + } + } +} + +impl std::error::Error for BrowserProtocolUseValidationError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::ProtocolVersion(error) => Some(error), + Self::RuntimeRevision(error) => Some(error), + Self::Capability(error) => Some(error), + } + } +} + /// Failure to construct canonical browser protocol adapter metadata. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BrowserProtocolDescriptorError { From d39cbf5d31da8578a495d6795bb4983405403d3a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:24:24 +0900 Subject: [PATCH 4/9] feat(core): export browser protocol use validation types --- crates/originweave-core/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/originweave-core/src/lib.rs b/crates/originweave-core/src/lib.rs index 6a8c7b6bd..bf8f2fa5e 100644 --- a/crates/originweave-core/src/lib.rs +++ b/crates/originweave-core/src/lib.rs @@ -17,9 +17,9 @@ mod contracts; pub use browser_protocol::{ BrowserProtocolAdapterDescriptor, BrowserProtocolCapability, BrowserProtocolCapabilityRequirementError, BrowserProtocolDescriptorError, BrowserProtocolKind, - BrowserProtocolRuntimeRequirementError, BrowserProtocolVersionRequirementError, - MAX_BROWSER_PROTOCOL_METADATA_BYTES, OriginWeaveProtocolVersion, - OriginWeaveProtocolVersionParseError, + BrowserProtocolRuntimeRequirementError, BrowserProtocolUseValidationError, + BrowserProtocolVersionRequirementError, MAX_BROWSER_PROTOCOL_METADATA_BYTES, + OriginWeaveProtocolVersion, OriginWeaveProtocolVersionParseError, ValidatedBrowserProtocolUse, }; pub use browser_registry::{ BrowserAuthorityRegistry, BrowserRegistryError, MAX_EXTERNAL_BROWSER_IDENTIFIER_BYTES, From 72c4c3359b745357ec23942efabf13cebaa0f36f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:25:32 +0900 Subject: [PATCH 5/9] test(core): cover browser protocol validation error evidence --- .../tests/browser_protocol_use_validation.rs | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/crates/originweave-core/tests/browser_protocol_use_validation.rs b/crates/originweave-core/tests/browser_protocol_use_validation.rs index ba559a5af..cf7c8ad0b 100644 --- a/crates/originweave-core/tests/browser_protocol_use_validation.rs +++ b/crates/originweave-core/tests/browser_protocol_use_validation.rs @@ -1,9 +1,10 @@ use std::error::Error; use originweave_core::{ - BrowserProtocolAdapterDescriptor, BrowserProtocolCapability, BrowserProtocolKind, - BrowserProtocolUseValidationError, BrowserProtocolVersionRequirementError, - OriginWeaveProtocolVersion, + BrowserProtocolAdapterDescriptor, BrowserProtocolCapability, + BrowserProtocolCapabilityRequirementError, BrowserProtocolKind, + BrowserProtocolRuntimeRequirementError, BrowserProtocolUseValidationError, + BrowserProtocolVersionRequirementError, OriginWeaveProtocolVersion, }; const ORIGINWEAVE_PROTOCOL_VERSION: OriginWeaveProtocolVersion = @@ -86,7 +87,7 @@ fn runtime_revision_validation_precedes_capability_check() -> Result<(), Box Result<(), Box Date: Wed, 12 Aug 2026 15:37:05 +0900 Subject: [PATCH 6/9] test(core): require runtime browser protocol kind binding --- .../tests/browser_protocol_use_validation.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/originweave-core/tests/browser_protocol_use_validation.rs b/crates/originweave-core/tests/browser_protocol_use_validation.rs index cf7c8ad0b..1bba239de 100644 --- a/crates/originweave-core/tests/browser_protocol_use_validation.rs +++ b/crates/originweave-core/tests/browser_protocol_use_validation.rs @@ -150,3 +150,24 @@ fn validation_errors_preserve_stable_typed_sources() { ); } } + +#[test] +fn runtime_protocol_kind_mismatch_precedes_revision_and_capability_checks() +-> Result<(), Box> { + let descriptor = descriptor()?; + + assert_eq!( + descriptor.validate_use( + ORIGINWEAVE_PROTOCOL_VERSION, + BrowserProtocolKind::ChromeDevToolsProtocol, + "runtime revision with spaces", + "browser/revision", + BrowserProtocolCapability::NetworkObservation, + ), + Err(BrowserProtocolUseValidationError::ProtocolKindMismatch { + descriptor_kind: BrowserProtocolKind::WebDriverBiDi, + runtime_kind: BrowserProtocolKind::ChromeDevToolsProtocol, + }) + ); + Ok(()) +} From de107ca6fa0de44d911fbfb52f7dc8f9a9fb8bca Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:41:47 +0900 Subject: [PATCH 7/9] test(core): bind all validated uses to runtime protocol kind --- .../tests/browser_protocol_use_validation.rs | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/crates/originweave-core/tests/browser_protocol_use_validation.rs b/crates/originweave-core/tests/browser_protocol_use_validation.rs index 1bba239de..8994253ec 100644 --- a/crates/originweave-core/tests/browser_protocol_use_validation.rs +++ b/crates/originweave-core/tests/browser_protocol_use_validation.rs @@ -32,6 +32,7 @@ fn validated_use_binds_all_required_adapter_metadata() -> Result<(), Box Result<(), Box> { + let descriptor = descriptor()?; + + let error = descriptor.validate_use( + ORIGINWEAVE_PROTOCOL_VERSION, + BrowserProtocolKind::ChromeDevToolsProtocol, + "runtime revision with spaces", + "browser/revision", + BrowserProtocolCapability::NetworkObservation, + ); + + assert_eq!( + error, + Err(BrowserProtocolUseValidationError::ProtocolKindMismatch { + descriptor_kind: BrowserProtocolKind::WebDriverBiDi, + runtime_kind: BrowserProtocolKind::ChromeDevToolsProtocol, + }) + ); + let error = error.err().ok_or("expected protocol kind mismatch")?; + assert_eq!( + error.to_string(), + "runtime browser protocol kind does not match the pinned adapter kind" + ); + assert!(error.source().is_none()); + Ok(()) +} + #[test] fn runtime_revision_validation_precedes_capability_check() -> Result<(), Box> { let descriptor = descriptor()?; @@ -82,6 +113,7 @@ fn runtime_revision_validation_precedes_capability_check() -> Result<(), Box Result<(), Box Result<(), Box> { - let descriptor = descriptor()?; - - assert_eq!( - descriptor.validate_use( - ORIGINWEAVE_PROTOCOL_VERSION, - BrowserProtocolKind::ChromeDevToolsProtocol, - "runtime revision with spaces", - "browser/revision", - BrowserProtocolCapability::NetworkObservation, - ), - Err(BrowserProtocolUseValidationError::ProtocolKindMismatch { - descriptor_kind: BrowserProtocolKind::WebDriverBiDi, - runtime_kind: BrowserProtocolKind::ChromeDevToolsProtocol, - }) - ); - Ok(()) -} From 3294f2779e9e27f6bf17834841b9e64c178619aa Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:43:00 +0900 Subject: [PATCH 8/9] feat(core): bind validated use to runtime protocol kind --- .../originweave-core/src/browser_protocol.rs | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/crates/originweave-core/src/browser_protocol.rs b/crates/originweave-core/src/browser_protocol.rs index 369666ece..d4650ac30 100644 --- a/crates/originweave-core/src/browser_protocol.rs +++ b/crates/originweave-core/src/browser_protocol.rs @@ -293,21 +293,29 @@ impl BrowserProtocolAdapterDescriptor { /// Validate all adapter metadata prerequisites for one immediate browser operation. /// /// Validation is intentionally ordered and fail closed: the exact - /// OriginWeave Protocol generation is checked first, then the supplied - /// runtime protocol/browser revisions, then the required adapter - /// capability. Success returns a non-cloneable value that a later trusted - /// transport can consume as proof that these metadata prerequisites were - /// checked together. It is not browser or Agent authority and does not - /// authenticate the caller supplying runtime revision evidence. + /// OriginWeave Protocol generation is checked first, then the caller-supplied + /// runtime protocol family, then the supplied runtime protocol/browser + /// revisions, and finally the required adapter capability. Success returns + /// a non-cloneable value that a later trusted transport can consume as proof + /// that these metadata prerequisites were checked together. It is not + /// browser or Agent authority and does not authenticate or attest the caller + /// supplying runtime metadata. pub fn validate_use( &self, required_originweave_protocol_version: OriginWeaveProtocolVersion, + runtime_kind: BrowserProtocolKind, runtime_protocol_revision: &str, runtime_browser_revision: &str, required_capability: BrowserProtocolCapability, ) -> Result { self.require_originweave_protocol_version(required_originweave_protocol_version) .map_err(BrowserProtocolUseValidationError::ProtocolVersion)?; + if self.kind != runtime_kind { + return Err(BrowserProtocolUseValidationError::ProtocolKindMismatch { + descriptor_kind: self.kind, + runtime_kind, + }); + } self.require_runtime_revisions(runtime_protocol_revision, runtime_browser_revision) .map_err(BrowserProtocolUseValidationError::RuntimeRevision)?; self.require_capability(required_capability) @@ -484,6 +492,13 @@ impl std::error::Error for BrowserProtocolCapabilityRequirementError {} pub enum BrowserProtocolUseValidationError { /// The descriptor targets the wrong OriginWeave Protocol generation. ProtocolVersion(BrowserProtocolVersionRequirementError), + /// The runtime transport reports a different protocol family than the descriptor. + ProtocolKindMismatch { + /// Browser protocol family pinned by the adapter descriptor. + descriptor_kind: BrowserProtocolKind, + /// Browser protocol family reported by the runtime transport. + runtime_kind: BrowserProtocolKind, + }, /// The supplied runtime protocol or browser revision is invalid or has drifted. RuntimeRevision(BrowserProtocolRuntimeRequirementError), /// The descriptor does not explicitly declare the required capability. @@ -494,6 +509,8 @@ impl fmt::Display for BrowserProtocolUseValidationError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::ProtocolVersion(error) => error.fmt(formatter), + Self::ProtocolKindMismatch { .. } => formatter + .write_str("runtime browser protocol kind does not match the pinned adapter kind"), Self::RuntimeRevision(error) => error.fmt(formatter), Self::Capability(error) => error.fmt(formatter), } @@ -504,6 +521,7 @@ impl std::error::Error for BrowserProtocolUseValidationError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::ProtocolVersion(error) => Some(error), + Self::ProtocolKindMismatch { .. } => None, Self::RuntimeRevision(error) => Some(error), Self::Capability(error) => Some(error), } From 9aed5ae21aca022f58253566c87e67be648675bd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 15:46:08 +0900 Subject: [PATCH 9/9] docs(changelog): record browser protocol use validation --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d197d67e..2241b0dea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to OriginWeave are documented in this file. The format follo - Rust workspace for independently reusable core, policy, destination, network, TLS, resource, and evidence modules. - Versioned browser-protocol adapter metadata that distinguishes WebDriver BiDi from pinned CDP, binds bounded adapter/browser revision tokens to an explicit duplicate-free capability set, normalizes capability-set identity independently of caller ordering, and exposes typed fail-closed capability requirements without granting browser, action, network, or secret authority by protocol kind alone. - Canonical OriginWeave protocol-version parsing for exact `originweave/.` syntax, with typed fail-closed rejection of malformed, ambiguous, overflowed, or noncanonical serialized generations; parsing does not negotiate compatibility or grant adapter authority. +- Atomic browser-protocol use validation that requires the exact OriginWeave protocol generation, caller-supplied runtime protocol family, exact pinned runtime protocol/browser revisions, and an explicitly declared capability in deterministic fail-closed order before producing non-cloneable validation evidence; this metadata proof does not authenticate the adapter or grant browser/Agent authority. - Canonical HTTPS and loopback-origin boundary with case-normalized schemes and hosts, default-port normalization, IPv4/IPv6 handling, browser-special numeric-host rejection, and explicit malformed-input errors. - Typed browser actions, capabilities, risk classes, execution modes, robots decisions, secret-delivery contracts, immutable canonical action-intent digests, and intent-bound approval scopes. - Deterministic fail-closed policy evaluation for untrusted instructions, origin grants, crawler restrictions, execution-mode and purpose consistency, approvals, and brokered secrets.