Skip to main content

lenso_plugin_bundle/
selection.rs

1use lenso_app_plan::{ExecutionClassId, authoring::PluginDescriptor};
2
3use crate::{BundleError, PluginArtifactV2, PluginManifest, invalid_bundle};
4
5/// One exact runtime protocol admitted by the Host.
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct RuntimeAdmission {
8    pub execution_class: ExecutionClassId,
9    pub runtime_profile: String,
10}
11
12/// Host policy used to resolve one implementation before Plan construction.
13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct ImplementationPolicy {
15    pub host_target: String,
16    pub runtimes: Vec<RuntimeAdmission>,
17}
18
19/// One final implementation selected from a Plugin Release.
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct ResolvedPluginImplementation {
22    pub implementation_id: String,
23    pub descriptor: PluginDescriptor,
24    pub artifact: PluginArtifactV2,
25}
26
27/// Selects one implementation deterministically. Selection never implies runtime fallback.
28pub fn resolve_implementation(
29    manifest: &PluginManifest,
30    policy: &ImplementationPolicy,
31) -> Result<ResolvedPluginImplementation, BundleError> {
32    match manifest {
33        PluginManifest::V2(value) => {
34            let descriptor =
35                serde_json::from_value::<PluginDescriptor>(value.entry.descriptor.clone())
36                    .map_err(|error| BundleError::InvalidManifest(error.to_string()))?;
37            if !policy.runtimes.iter().any(|admission| {
38                admission.execution_class == *descriptor.execution_class()
39                    && admission.runtime_profile == descriptor.runtime_profile()
40            }) || !target_matches(&value.artifact, &policy.host_target)
41            {
42                return invalid_bundle("V2 Bundle has no implementation admitted by Host policy");
43            }
44            Ok(ResolvedPluginImplementation {
45                implementation_id: "default".to_owned(),
46                descriptor,
47                artifact: value.artifact.clone(),
48            })
49        }
50        PluginManifest::V3(value) => resolve_profiled_implementation(
51            &value.contract,
52            value.implementations.iter().map(|candidate| {
53                (
54                    &candidate.id,
55                    &candidate.host_targets,
56                    &candidate.artifact,
57                    &candidate.runtime,
58                )
59            }),
60            policy,
61            "V3",
62        ),
63        PluginManifest::V4(value) => resolve_profiled_implementation(
64            &value.contract,
65            value.implementations.iter().map(|candidate| {
66                (
67                    &candidate.id,
68                    &candidate.host_targets,
69                    &candidate.artifact,
70                    &candidate.runtime,
71                )
72            }),
73            policy,
74            "V4",
75        ),
76    }
77}
78
79fn resolve_profiled_implementation<'a>(
80    contract: &lenso_app_plan::authoring::PluginContract,
81    candidates: impl Iterator<
82        Item = (
83            &'a String,
84            &'a Vec<String>,
85            &'a PluginArtifactV2,
86            &'a lenso_app_plan::authoring::PluginImplementation,
87        ),
88    >,
89    policy: &ImplementationPolicy,
90    schema: &str,
91) -> Result<ResolvedPluginImplementation, BundleError> {
92    let candidates = candidates.collect::<Vec<_>>();
93    for admission in &policy.runtimes {
94        let matches = candidates
95            .iter()
96            .filter(|(_, targets, _, runtime)| {
97                runtime.execution_class() == &admission.execution_class
98                    && runtime.runtime_profile() == admission.runtime_profile
99                    && targets
100                        .iter()
101                        .any(|target| target == "*" || target == &policy.host_target)
102            })
103            .collect::<Vec<_>>();
104        match matches.as_slice() {
105            [] => {}
106            [(id, _, artifact, runtime)] => {
107                return Ok(ResolvedPluginImplementation {
108                    implementation_id: (*id).clone(),
109                    descriptor: contract.resolve(runtime),
110                    artifact: (*artifact).clone(),
111                });
112            }
113            _ => {
114                return invalid_bundle(format!(
115                    "Host policy ambiguously matches {} implementations of `({}, {})`",
116                    matches.len(),
117                    admission.execution_class.as_str(),
118                    admission.runtime_profile
119                ));
120            }
121        }
122    }
123    invalid_bundle(format!(
124        "{schema} Bundle has no implementation admitted by Host policy"
125    ))
126}
127
128fn target_matches(artifact: &PluginArtifactV2, host_target: &str) -> bool {
129    artifact.media_type == "application/wasm" || artifact.target == host_target
130}