mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Decouple plugin manifest path resolution (#29620)
## Why
Plugin manifests use the same schema whether the package lives on the
host or in an executor. Only the path representation differs: host
callers need native `Path` inputs and `AbsolutePathBuf` outputs, while
executor callers need `PathUri` throughout.
Maintaining separate parsing or resolver implementations would duplicate
the manifest rules and allow them to drift. This PR instead makes
URI-native resolution the single parsing path and keeps host conversion
at the boundary.
## What changed
- Make `parse_plugin_manifest_uri` the shared manifest parser and
resolve every path-bearing field as `PathUri`.
- Keep the existing host entrypoint as a thin adapter: convert its
native root and manifest path to `PathUri`, run the shared parser, then
map resources back to `AbsolutePathBuf`.
- Expose `PluginManifest::try_map_resources` so callers can convert the
generic resource type without duplicating manifest construction.
- Resolve relative manifest paths using the root URI's convention:
backslashes are separators for Windows roots and ordinary filename
characters for POSIX roots.
- Apply lexical containment after URI resolution, rejecting absolute
paths and parent traversal outside the plugin root.
- Make encoded backslashes fail containment only for Windows URIs;
encoded `/` remains unsafe for every convention.
- Use a host-native synthetic root for marketplace fallback manifests so
the host adapter also works on Windows.
```text
host Path --------> PathUri --\
+--> one manifest parser --> PluginManifest<PathUri>
executor PathUri -------------/
host result: PluginManifest<PathUri> --> PluginManifest<AbsolutePathBuf>
```
Existing host manifest behavior is preserved; #28918 is the first
executor consumer.
## Verification
- `just test -p codex-utils-path-uri`
- `just test -p codex-plugin`
- `just test -p codex-core-plugins`
## Stack
1. #29614 — add lexical `PathUri` containment.
2. **This PR** — share URI-native manifest path resolution.
3. #28918 — keep selected plugin roots and resources URI-native.
4. #29626 — load executor skills without host path conversion.
5. #29628 — resolve executor MCP working directories without host path
conversion.
This commit is contained in:
5 files changed
+149
-62
No files matched your search
@@ -265,10 +265,18 @@ impl PathUri {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(path_segments) = containment_path_segments(&self.0) else {
|
||||
let Some(path_segments) = containment_path_segments(
|
||||
&self.0,
|
||||
self.infer_path_convention()
|
||||
.unwrap_or(PathConvention::Posix),
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
let Some(base_segments) = containment_path_segments(&base.0) else {
|
||||
let Some(base_segments) = containment_path_segments(
|
||||
&base.0,
|
||||
base.infer_path_convention()
|
||||
.unwrap_or(PathConvention::Posix),
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
path_segments.starts_with(&base_segments)
|
||||
@@ -569,7 +577,7 @@ fn is_windows_drive_uri_segment(segment: &str) -> bool {
|
||||
matches!(segment.as_bytes(), [drive, b':'] if drive.is_ascii_alphabetic())
|
||||
}
|
||||
|
||||
fn containment_path_segments(url: &Url) -> Option<Vec<&str>> {
|
||||
fn containment_path_segments(url: &Url, convention: PathConvention) -> Option<Vec<&str>> {
|
||||
let segments = url
|
||||
.path_segments()?
|
||||
.filter(|segment| !segment.is_empty())
|
||||
@@ -577,7 +585,7 @@ fn containment_path_segments(url: &Url) -> Option<Vec<&str>> {
|
||||
(!segments.iter().any(|segment| {
|
||||
urlencoding::decode_binary(segment.as_bytes())
|
||||
.iter()
|
||||
.any(|byte| matches!(*byte, b'/' | b'\\'))
|
||||
.any(|byte| *byte == b'/' || (convention == PathConvention::Windows && *byte == b'\\'))
|
||||
}))
|
||||
.then_some(segments)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user