plugin: filter static enabled surfaces
This commit is contained in:
parent
79ca0f7f81
commit
627c8f36ff
|
|
@ -303,7 +303,8 @@ pub fn inspect_resolved_plugin_static(record: &ResolvedPluginRecord) -> PluginSt
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let duplicate_tool_names = duplicate_tool_names(record);
|
let duplicate_tool_names = duplicate_tool_names(record);
|
||||||
let tools = record
|
let tools = if surface_enabled(record, PluginSurface::Tool) {
|
||||||
|
record
|
||||||
.manifest
|
.manifest
|
||||||
.tools
|
.tools
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -326,13 +327,17 @@ pub fn inspect_resolved_plugin_static(record: &ResolvedPluginRecord) -> PluginSt
|
||||||
diagnostic,
|
diagnostic,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
let instance_world = record.manifest.runtime.as_ref().is_some_and(|runtime| {
|
let instance_world = record.manifest.runtime.as_ref().is_some_and(|runtime| {
|
||||||
runtime.kind == PLUGIN_RUNTIME_COMPONENT_KIND
|
runtime.kind == PLUGIN_RUNTIME_COMPONENT_KIND
|
||||||
&& runtime.world.as_deref() == Some(PLUGIN_COMPONENT_INSTANCE_WORLD)
|
&& runtime.world.as_deref() == Some(PLUGIN_COMPONENT_INSTANCE_WORLD)
|
||||||
});
|
});
|
||||||
let services = record
|
let services = if surface_enabled(record, PluginSurface::Service) {
|
||||||
|
record
|
||||||
.manifest
|
.manifest
|
||||||
.services
|
.services
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -342,7 +347,8 @@ pub fn inspect_resolved_plugin_static(record: &ResolvedPluginRecord) -> PluginSt
|
||||||
let granted = grant_allows(record, &permission);
|
let granted = grant_allows(record, &permission);
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
if !instance_world {
|
if !instance_world {
|
||||||
diagnostics.push("service requires instance-capable component world".to_string());
|
diagnostics
|
||||||
|
.push("service requires instance-capable component world".to_string());
|
||||||
}
|
}
|
||||||
if let Err(error) = authorize_plugin_service(record, &service.name) {
|
if let Err(error) = authorize_plugin_service(record, &service.name) {
|
||||||
diagnostics.push(error.bounded_message());
|
diagnostics.push(error.bounded_message());
|
||||||
|
|
@ -357,8 +363,12 @@ pub fn inspect_resolved_plugin_static(record: &ResolvedPluginRecord) -> PluginSt
|
||||||
diagnostic,
|
diagnostic,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
let ingresses = record
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
let ingresses = if surface_enabled(record, PluginSurface::Ingress) {
|
||||||
|
record
|
||||||
.manifest
|
.manifest
|
||||||
.ingresses
|
.ingresses
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -368,7 +378,8 @@ pub fn inspect_resolved_plugin_static(record: &ResolvedPluginRecord) -> PluginSt
|
||||||
let granted = grant_allows(record, &permission);
|
let granted = grant_allows(record, &permission);
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
if !instance_world {
|
if !instance_world {
|
||||||
diagnostics.push("ingress requires instance-capable component world".to_string());
|
diagnostics
|
||||||
|
.push("ingress requires instance-capable component world".to_string());
|
||||||
}
|
}
|
||||||
if let Err(error) = authorize_plugin_ingress(record, &ingress.name) {
|
if let Err(error) = authorize_plugin_ingress(record, &ingress.name) {
|
||||||
diagnostics.push(error.bounded_message());
|
diagnostics.push(error.bounded_message());
|
||||||
|
|
@ -383,7 +394,10 @@ pub fn inspect_resolved_plugin_static(record: &ResolvedPluginRecord) -> PluginSt
|
||||||
diagnostic,
|
diagnostic,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
PluginStaticInspection {
|
PluginStaticInspection {
|
||||||
runtime,
|
runtime,
|
||||||
|
|
|
||||||
|
|
@ -1090,6 +1090,18 @@ fn fill_resolved(builder: &mut ItemBuilder, resolved: &ResolvedPlugin) {
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|tool| tool.diagnostic.as_ref()),
|
.filter_map(|tool| tool.diagnostic.as_ref()),
|
||||||
)
|
)
|
||||||
|
.chain(
|
||||||
|
static_runtime
|
||||||
|
.services
|
||||||
|
.iter()
|
||||||
|
.filter_map(|service| service.diagnostic.as_ref()),
|
||||||
|
)
|
||||||
|
.chain(
|
||||||
|
static_runtime
|
||||||
|
.ingresses
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ingress| ingress.diagnostic.as_ref()),
|
||||||
|
)
|
||||||
{
|
{
|
||||||
builder.diagnostics.push(DiagnosticSummary {
|
builder.diagnostics.push(DiagnosticSummary {
|
||||||
kind: "static_eligibility".to_string(),
|
kind: "static_eligibility".to_string(),
|
||||||
|
|
@ -1491,6 +1503,58 @@ mod tests {
|
||||||
assert!(show.contains("configured_grants: surfaces.tool, tool.Echo"));
|
assert!(show.contains("configured_grants: surfaces.tool, tool.Echo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn service_only_enablement_ignores_unselected_tool_static_grants() {
|
||||||
|
let dir = tempdir().unwrap();
|
||||||
|
let workspace = dir.path();
|
||||||
|
let digest = write_mixed_tool_service_package(workspace, "mixed");
|
||||||
|
let mut config = PluginConfig::default();
|
||||||
|
config.enabled.push(PluginEnablementConfig {
|
||||||
|
id: "project:mixed".to_string(),
|
||||||
|
digest: Some(digest.clone()),
|
||||||
|
version: Some(PluginExactVersion("0.1.0".to_string())),
|
||||||
|
surfaces: vec![PluginSurface::Service],
|
||||||
|
grants: PluginGrantConfig {
|
||||||
|
id: Some("project:mixed".to_string()),
|
||||||
|
version: Some(PluginExactVersion("0.1.0".to_string())),
|
||||||
|
digest: Some(digest),
|
||||||
|
permissions: vec![
|
||||||
|
PluginPermission::surface(PluginSurface::Service),
|
||||||
|
PluginPermission::service("svc"),
|
||||||
|
],
|
||||||
|
https: Vec::new(),
|
||||||
|
fs: Vec::new(),
|
||||||
|
},
|
||||||
|
config: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let snapshot = inspect_snapshot(workspace, &config);
|
||||||
|
let item = select_item(&snapshot, "project:mixed").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(item.status, "active");
|
||||||
|
assert!(item.static_eligible);
|
||||||
|
assert_eq!(item.enabled_surfaces, vec!["service"]);
|
||||||
|
assert!(
|
||||||
|
item.tools.is_empty(),
|
||||||
|
"unselected Tool must not be reported"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
item.diagnostics
|
||||||
|
.iter()
|
||||||
|
.all(|diagnostic| !diagnostic.message.contains("tool.Echo")),
|
||||||
|
"unselected Tool grant diagnostics must not affect service-only enablement: {:#?}",
|
||||||
|
item.diagnostics
|
||||||
|
);
|
||||||
|
|
||||||
|
let show_json = serde_json::to_value(item).unwrap();
|
||||||
|
assert_eq!(show_json["status"], "active");
|
||||||
|
assert_eq!(
|
||||||
|
show_json["enabled_surfaces"],
|
||||||
|
serde_json::json!(["service"])
|
||||||
|
);
|
||||||
|
assert_eq!(show_json["tools"], serde_json::json!([]));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn human_list_uses_required_status_vocabulary() {
|
fn human_list_uses_required_status_vocabulary() {
|
||||||
let dir = tempdir().unwrap();
|
let dir = tempdir().unwrap();
|
||||||
|
|
@ -2098,6 +2162,61 @@ mod tests {
|
||||||
assert!(error.len() < 160);
|
assert!(error.len() < 160);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_mixed_tool_service_package(workspace: &Path, id: &str) -> String {
|
||||||
|
let package_dir = workspace.join(".yoi/plugins");
|
||||||
|
fs::create_dir_all(&package_dir).unwrap();
|
||||||
|
let package = package_dir.join(format!("{id}.yoi-plugin"));
|
||||||
|
let manifest = format!(
|
||||||
|
r#"schema_version = 1
|
||||||
|
id = "{id}"
|
||||||
|
name = "{id}"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "mixed surface package"
|
||||||
|
surfaces = ["tool", "service"]
|
||||||
|
permissions = [
|
||||||
|
{{ kind = "surface", surface = "tool" }},
|
||||||
|
{{ kind = "tool", name = "Echo" }},
|
||||||
|
{{ kind = "surface", surface = "service" }},
|
||||||
|
{{ kind = "service", name = "svc" }},
|
||||||
|
]
|
||||||
|
|
||||||
|
[runtime]
|
||||||
|
kind = "wasm-component"
|
||||||
|
world = "yoi:plugin/instance@1.0.0"
|
||||||
|
component = "plugin.component.wasm"
|
||||||
|
|
||||||
|
[[tools]]
|
||||||
|
name = "Echo"
|
||||||
|
description = "unselected tool"
|
||||||
|
input_schema = {{ type = "object" }}
|
||||||
|
|
||||||
|
[[services]]
|
||||||
|
name = "svc"
|
||||||
|
description = "selected service"
|
||||||
|
lifecycle = "host-managed"
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
write_stored_zip(
|
||||||
|
&package,
|
||||||
|
&[
|
||||||
|
("plugin.toml", manifest.as_bytes()),
|
||||||
|
("plugin.component.wasm", b"placeholder component bytes"),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let discovery = discover_plugins(&PluginDiscoveryOptions {
|
||||||
|
workspace_root: workspace.to_path_buf(),
|
||||||
|
user_data_home: None,
|
||||||
|
limits: PluginDiscoveryLimits::default(),
|
||||||
|
});
|
||||||
|
discovery
|
||||||
|
.packages
|
||||||
|
.iter()
|
||||||
|
.find(|package| package.identity.local_id == id)
|
||||||
|
.unwrap()
|
||||||
|
.digest
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn inspect_snapshot(workspace: &Path, config: &PluginConfig) -> PluginInspectionSnapshot {
|
fn inspect_snapshot(workspace: &Path, config: &PluginConfig) -> PluginInspectionSnapshot {
|
||||||
let discovery = discover_plugins(&PluginDiscoveryOptions {
|
let discovery = discover_plugins(&PluginDiscoveryOptions {
|
||||||
workspace_root: workspace.to_path_buf(),
|
workspace_root: workspace.to_path_buf(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user