plugin: implement fs host api
This commit is contained in:
parent
6711bcf300
commit
717c0999a5
|
|
@ -76,11 +76,13 @@ pub struct PluginGrantConfig {
|
||||||
pub permissions: Vec<PluginPermission>,
|
pub permissions: Vec<PluginPermission>,
|
||||||
/// Bounded outbound HTTPS allowlist entries for `host_api.https`.
|
/// Bounded outbound HTTPS allowlist entries for `host_api.https`.
|
||||||
pub https: Vec<PluginHttpsGrant>,
|
pub https: Vec<PluginHttpsGrant>,
|
||||||
|
/// Scoped filesystem allowlist entries for `host_api.fs`.
|
||||||
|
pub fs: Vec<PluginFsGrant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PluginGrantConfig {
|
impl PluginGrantConfig {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.permissions.is_empty() && self.https.is_empty()
|
self.permissions.is_empty() && self.https.is_empty() && self.fs.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binding_error(
|
pub fn binding_error(
|
||||||
|
|
@ -157,6 +159,48 @@ impl PluginHttpsGrant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
#[serde(default, deny_unknown_fields)]
|
||||||
|
pub struct PluginFsGrant {
|
||||||
|
/// Absolute host path that bounds every relative `host_api.fs` request.
|
||||||
|
pub root: String,
|
||||||
|
/// Explicit operation kinds allowed below `root`; write does not imply read/list.
|
||||||
|
pub operations: Vec<PluginFsOperation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginFsGrant {
|
||||||
|
pub fn label(&self) -> String {
|
||||||
|
let operations = if self.operations.is_empty() {
|
||||||
|
"<no-operations>".to_string()
|
||||||
|
} else {
|
||||||
|
self.operations
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(",")
|
||||||
|
};
|
||||||
|
format!("{} {}", self.root, operations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum PluginFsOperation {
|
||||||
|
Read,
|
||||||
|
List,
|
||||||
|
Write,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PluginFsOperation {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Read => f.write_str("read"),
|
||||||
|
Self::List => f.write_str("list"),
|
||||||
|
Self::Write => f.write_str("write"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PluginPermission {
|
impl PluginPermission {
|
||||||
pub fn label(&self) -> String {
|
pub fn label(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -2082,6 +2126,7 @@ input_schema = { type = "object", properties = { query = { type = "string" } },
|
||||||
digest: Some(digest.clone()),
|
digest: Some(digest.clone()),
|
||||||
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
};
|
};
|
||||||
let resolution = resolve_enabled_plugins(
|
let resolution = resolve_enabled_plugins(
|
||||||
&PluginConfig {
|
&PluginConfig {
|
||||||
|
|
@ -2108,6 +2153,7 @@ input_schema = { type = "object", properties = { query = { type = "string" } },
|
||||||
digest: Some(digest.clone()),
|
digest: Some(digest.clone()),
|
||||||
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
PluginGrantConfig {
|
PluginGrantConfig {
|
||||||
id: Some("project:example".to_string()),
|
id: Some("project:example".to_string()),
|
||||||
|
|
@ -2115,6 +2161,7 @@ input_schema = { type = "object", properties = { query = { type = "string" } },
|
||||||
digest: Some(digest.clone()),
|
digest: Some(digest.clone()),
|
||||||
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
PluginGrantConfig {
|
PluginGrantConfig {
|
||||||
id: Some("project:example".to_string()),
|
id: Some("project:example".to_string()),
|
||||||
|
|
@ -2122,6 +2169,7 @@ input_schema = { type = "object", properties = { query = { type = "string" } },
|
||||||
digest: Some("sha256:unrelated".to_string()),
|
digest: Some("sha256:unrelated".to_string()),
|
||||||
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
permissions: vec![PluginPermission::surface(PluginSurface::Hook)],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
] {
|
] {
|
||||||
let resolution = resolve_enabled_plugins(
|
let resolution = resolve_enabled_plugins(
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -190,6 +190,11 @@ fn render_item_human(item: &PluginInspectionItem) -> Result<String> {
|
||||||
" configured_https_grants: {}",
|
" configured_https_grants: {}",
|
||||||
join_or_none(&item.configured_https_grants)
|
join_or_none(&item.configured_https_grants)
|
||||||
)?;
|
)?;
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
" configured_fs_grants: {}",
|
||||||
|
join_or_none(&item.configured_fs_grants)
|
||||||
|
)?;
|
||||||
|
|
||||||
if let Some(runtime) = &item.static_runtime {
|
if let Some(runtime) = &item.static_runtime {
|
||||||
writeln!(
|
writeln!(
|
||||||
|
|
@ -360,6 +365,7 @@ fn snapshot_from_resolution(
|
||||||
builder.enabled_surfaces = surface_strings(enablement.surfaces.iter().copied());
|
builder.enabled_surfaces = surface_strings(enablement.surfaces.iter().copied());
|
||||||
builder.configured_grants = permission_strings(&enablement.grants.permissions);
|
builder.configured_grants = permission_strings(&enablement.grants.permissions);
|
||||||
builder.configured_https_grants = https_grant_strings(&enablement.grants.https);
|
builder.configured_https_grants = https_grant_strings(&enablement.grants.https);
|
||||||
|
builder.configured_fs_grants = fs_grant_strings(&enablement.grants.fs);
|
||||||
if let Ok(identity) = SourceQualifiedPluginId::parse(&enablement.id) {
|
if let Ok(identity) = SourceQualifiedPluginId::parse(&enablement.id) {
|
||||||
builder
|
builder
|
||||||
.source
|
.source
|
||||||
|
|
@ -452,6 +458,7 @@ fn fill_resolved(builder: &mut ItemBuilder, resolved: &ResolvedPlugin) {
|
||||||
builder.requested_permissions = permission_strings(&resolved.manifest.permissions);
|
builder.requested_permissions = permission_strings(&resolved.manifest.permissions);
|
||||||
builder.configured_grants = permission_strings(&resolved.grants.permissions);
|
builder.configured_grants = permission_strings(&resolved.grants.permissions);
|
||||||
builder.configured_https_grants = https_grant_strings(&resolved.grants.https);
|
builder.configured_https_grants = https_grant_strings(&resolved.grants.https);
|
||||||
|
builder.configured_fs_grants = fs_grant_strings(&resolved.grants.fs);
|
||||||
|
|
||||||
let record = ResolvedPluginRecord::from_resolved(resolved);
|
let record = ResolvedPluginRecord::from_resolved(resolved);
|
||||||
let static_runtime = inspect_resolved_plugin_static(&record);
|
let static_runtime = inspect_resolved_plugin_static(&record);
|
||||||
|
|
@ -554,6 +561,13 @@ fn https_grant_strings(grants: &[manifest::plugin::PluginHttpsGrant]) -> Vec<Str
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fs_grant_strings(grants: &[manifest::plugin::PluginFsGrant]) -> Vec<String> {
|
||||||
|
let mut values: Vec<_> = grants.iter().map(|grant| grant.label()).collect();
|
||||||
|
values.sort();
|
||||||
|
values.dedup();
|
||||||
|
values
|
||||||
|
}
|
||||||
|
|
||||||
fn permission_requested(manifest: &PluginPackageManifest, permission: &PluginPermission) -> bool {
|
fn permission_requested(manifest: &PluginPackageManifest, permission: &PluginPermission) -> bool {
|
||||||
manifest
|
manifest
|
||||||
.permissions
|
.permissions
|
||||||
|
|
@ -625,6 +639,7 @@ struct PluginInspectionItem {
|
||||||
requested_permissions: Vec<String>,
|
requested_permissions: Vec<String>,
|
||||||
configured_grants: Vec<String>,
|
configured_grants: Vec<String>,
|
||||||
configured_https_grants: Vec<String>,
|
configured_https_grants: Vec<String>,
|
||||||
|
configured_fs_grants: Vec<String>,
|
||||||
tools: Vec<ToolSummary>,
|
tools: Vec<ToolSummary>,
|
||||||
static_runtime: Option<PluginStaticInspection>,
|
static_runtime: Option<PluginStaticInspection>,
|
||||||
diagnostics: Vec<DiagnosticSummary>,
|
diagnostics: Vec<DiagnosticSummary>,
|
||||||
|
|
@ -693,6 +708,7 @@ struct ItemBuilder {
|
||||||
requested_permissions: Vec<String>,
|
requested_permissions: Vec<String>,
|
||||||
configured_grants: Vec<String>,
|
configured_grants: Vec<String>,
|
||||||
configured_https_grants: Vec<String>,
|
configured_https_grants: Vec<String>,
|
||||||
|
configured_fs_grants: Vec<String>,
|
||||||
tools: Vec<ToolSummary>,
|
tools: Vec<ToolSummary>,
|
||||||
static_runtime: Option<PluginStaticInspection>,
|
static_runtime: Option<PluginStaticInspection>,
|
||||||
diagnostics: Vec<DiagnosticSummary>,
|
diagnostics: Vec<DiagnosticSummary>,
|
||||||
|
|
@ -719,6 +735,7 @@ impl ItemBuilder {
|
||||||
requested_permissions: Vec::new(),
|
requested_permissions: Vec::new(),
|
||||||
configured_grants: Vec::new(),
|
configured_grants: Vec::new(),
|
||||||
configured_https_grants: Vec::new(),
|
configured_https_grants: Vec::new(),
|
||||||
|
configured_fs_grants: Vec::new(),
|
||||||
tools: Vec::new(),
|
tools: Vec::new(),
|
||||||
static_runtime: None,
|
static_runtime: None,
|
||||||
diagnostics: Vec::new(),
|
diagnostics: Vec::new(),
|
||||||
|
|
@ -790,6 +807,7 @@ impl ItemBuilder {
|
||||||
requested_permissions: self.requested_permissions,
|
requested_permissions: self.requested_permissions,
|
||||||
configured_grants: self.configured_grants,
|
configured_grants: self.configured_grants,
|
||||||
configured_https_grants: self.configured_https_grants,
|
configured_https_grants: self.configured_https_grants,
|
||||||
|
configured_fs_grants: self.configured_fs_grants,
|
||||||
tools: self.tools,
|
tools: self.tools,
|
||||||
static_runtime: self.static_runtime,
|
static_runtime: self.static_runtime,
|
||||||
diagnostics: self.diagnostics,
|
diagnostics: self.diagnostics,
|
||||||
|
|
@ -883,6 +901,7 @@ mod tests {
|
||||||
PluginPermission::tool("Echo"),
|
PluginPermission::tool("Echo"),
|
||||||
],
|
],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
config: None,
|
config: None,
|
||||||
});
|
});
|
||||||
|
|
@ -900,6 +919,7 @@ mod tests {
|
||||||
PluginPermission::tool("Echo"),
|
PluginPermission::tool("Echo"),
|
||||||
],
|
],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
config: None,
|
config: None,
|
||||||
});
|
});
|
||||||
|
|
@ -1017,6 +1037,7 @@ mod tests {
|
||||||
PluginPermission::tool("Echo"),
|
PluginPermission::tool("Echo"),
|
||||||
],
|
],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
config: None,
|
config: None,
|
||||||
});
|
});
|
||||||
|
|
@ -1280,6 +1301,7 @@ mod tests {
|
||||||
PluginPermission::tool("Echo"),
|
PluginPermission::tool("Echo"),
|
||||||
],
|
],
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
config: None,
|
config: None,
|
||||||
}],
|
}],
|
||||||
|
|
@ -1310,6 +1332,7 @@ mod tests {
|
||||||
digest: Some(digest),
|
digest: Some(digest),
|
||||||
permissions,
|
permissions,
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
config: None,
|
config: None,
|
||||||
}
|
}
|
||||||
|
|
@ -1337,6 +1360,7 @@ mod tests {
|
||||||
digest: None,
|
digest: None,
|
||||||
permissions,
|
permissions,
|
||||||
https: Vec::new(),
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
},
|
},
|
||||||
config: None,
|
config: None,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user