[plugins] Route preview traffic to plugin service

This commit is contained in:
Steven Lee
2026-06-23 07:28:54 +00:00
parent 6e0c8b4517
commit 7db1786573
10 changed files with 304 additions and 10 deletions
+1
View File
@@ -21,5 +21,6 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
[dev-dependencies]
pretty_assertions = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt"] }
+1
View File
@@ -6,6 +6,7 @@ use codex_utils_absolute_path::AbsolutePathBuf;
pub mod mcp_connector;
pub mod mention_syntax;
pub mod plugin_namespace;
pub mod plugin_service_routing;
pub use plugin_namespace::DISCOVERABLE_PLUGIN_MANIFEST_PATHS;
pub use plugin_namespace::find_plugin_manifest_path;
@@ -0,0 +1,74 @@
use std::ffi::OsStr;
/// Process signal set by an eligible host to opt plugin-service requests into preview routing.
pub const CODEX_PLUGIN_SERVICE_PREVIEW_ENV_VAR: &str = "CODEX_PLUGIN_SERVICE_PREVIEW";
const PLUGIN_SERVICE_PREVIEW_ENABLED_VALUE: &str = "1";
const PLUGIN_SERVICE_PREVIEW_COOKIE_NAME: &[u8] = b"oai-chat-plugin-service-preview";
/// Routing cookie added to eligible plugin-service requests.
pub const PLUGIN_SERVICE_PREVIEW_COOKIE: &str = "oai-chat-plugin-service-preview=true";
/// Returns whether the host opted this process into plugin-service preview routing.
///
/// The host owns employee eligibility. This signal is defense-in-depth routing, not an
/// authorization boundary; authentication and authorization remain the responsibility of the
/// existing request path and plugin-service.
pub fn plugin_service_preview_enabled() -> bool {
plugin_service_preview_enabled_from_value(
std::env::var_os(CODEX_PLUGIN_SERVICE_PREVIEW_ENV_VAR).as_deref(),
)
}
/// Rewrites plugin-service cookies so callers cannot override the process routing signal.
///
/// Unrelated cookies are preserved. Any caller-provided preview cookie is removed before the
/// canonical routing cookie is added when preview routing is enabled.
pub fn plugin_service_routing_cookie(
existing_cookie_headers: &[&[u8]],
preview_enabled: bool,
) -> Option<Vec<u8>> {
let mut cookies = existing_cookie_headers
.iter()
.flat_map(|header| header.split(|byte| *byte == b';'))
.map(trim_cookie_whitespace)
.filter(|segment| !segment.is_empty())
.filter(|segment| {
let name = segment
.iter()
.position(|byte| *byte == b'=')
.map_or(*segment, |separator| &segment[..separator]);
trim_cookie_whitespace(name) != PLUGIN_SERVICE_PREVIEW_COOKIE_NAME
})
.map(<[u8]>::to_vec)
.collect::<Vec<_>>();
if preview_enabled {
cookies.push(PLUGIN_SERVICE_PREVIEW_COOKIE.as_bytes().to_vec());
}
(!cookies.is_empty()).then(|| cookies.join(&b"; "[..]))
}
fn plugin_service_preview_enabled_from_value(value: Option<&OsStr>) -> bool {
value == Some(OsStr::new(PLUGIN_SERVICE_PREVIEW_ENABLED_VALUE))
}
fn trim_cookie_whitespace(mut value: &[u8]) -> &[u8] {
while value
.first()
.is_some_and(|byte| matches!(byte, b' ' | b'\t'))
{
value = &value[1..];
}
while value
.last()
.is_some_and(|byte| matches!(byte, b' ' | b'\t'))
{
value = &value[..value.len() - 1];
}
value
}
#[cfg(test)]
#[path = "plugin_service_routing_tests.rs"]
mod tests;
@@ -0,0 +1,44 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn preview_signal_requires_exact_enabled_value() {
for value in [
None,
Some(""),
Some("0"),
Some("true"),
Some(" 1"),
Some("1 "),
] {
assert!(!plugin_service_preview_enabled_from_value(
value.map(OsStr::new)
));
}
assert!(plugin_service_preview_enabled_from_value(Some(OsStr::new(
"1"
))));
}
#[test]
fn routing_cookie_is_disabled_by_default_and_cannot_be_enabled_by_caller() {
assert_eq!(plugin_service_routing_cookie(&[], false), None);
assert_eq!(
plugin_service_routing_cookie(&[b"oai-chat-plugin-service-preview=true".as_slice()], false,),
None,
);
}
#[test]
fn routing_cookie_preserves_unrelated_cookies_and_replaces_caller_value() {
assert_eq!(
plugin_service_routing_cookie(
&[
b"session=abc; oai-chat-plugin-service-preview=false".as_slice(),
b"theme=dark; oai-chat-plugin-service-preview=true".as_slice(),
],
true,
),
Some(b"session=abc; theme=dark; oai-chat-plugin-service-preview=true".to_vec()),
);
}