fix: reject unknown profile archive selectors
This commit is contained in:
@@ -1339,13 +1339,18 @@ impl WorkspaceWorkerRuntime for EmbeddedWorkerRuntime {
|
||||
.profile
|
||||
.clone()
|
||||
.unwrap_or_else(|| embedded_profile_selector(&request.intent));
|
||||
let config_bundle = match self
|
||||
.runtime
|
||||
.store_config_bundle(default_embedded_config_bundle(&profile))
|
||||
{
|
||||
let config_bundle = match default_embedded_config_bundle(&profile).and_then(|bundle| {
|
||||
self.runtime
|
||||
.store_config_bundle(bundle)
|
||||
.map_err(|err| err.to_string())
|
||||
}) {
|
||||
Ok(availability) => availability.reference,
|
||||
Err(error) => {
|
||||
diagnostics.push(embedded_runtime_diagnostic(&error));
|
||||
diagnostics.push(diagnostic(
|
||||
"embedded_profile_source_archive_invalid",
|
||||
DiagnosticSeverity::Error,
|
||||
error,
|
||||
));
|
||||
return WorkerSpawnResult {
|
||||
state: WorkerOperationState::Rejected,
|
||||
worker: None,
|
||||
@@ -2020,7 +2025,18 @@ impl WorkspaceWorkerRuntime for RemoteWorkerRuntime {
|
||||
.profile
|
||||
.clone()
|
||||
.unwrap_or_else(|| embedded_profile_selector(&request.intent));
|
||||
let sync = self.sync_config_bundle(default_embedded_config_bundle(&profile));
|
||||
let sync = match default_embedded_config_bundle(&profile) {
|
||||
Ok(bundle) => self.sync_config_bundle(bundle),
|
||||
Err(error) => ConfigBundleSyncResult {
|
||||
state: WorkerOperationState::Rejected,
|
||||
availability: None,
|
||||
diagnostics: vec![diagnostic(
|
||||
"remote_profile_source_archive_invalid",
|
||||
DiagnosticSeverity::Error,
|
||||
error,
|
||||
)],
|
||||
},
|
||||
};
|
||||
let Some(config_bundle) = sync.availability.map(|availability| availability.reference)
|
||||
else {
|
||||
return WorkerSpawnResult {
|
||||
@@ -2349,14 +2365,14 @@ fn embedded_worker_execution_status_label(
|
||||
}
|
||||
}
|
||||
|
||||
fn default_embedded_config_bundle(profile: &ProfileSelector) -> ConfigBundle {
|
||||
fn default_embedded_config_bundle(profile: &ProfileSelector) -> Result<ConfigBundle, String> {
|
||||
let id = format!(
|
||||
"workspace-runtime-{}",
|
||||
embedded_profile_label(profile)
|
||||
.unwrap_or_else(|| "default".to_string())
|
||||
.replace([':', '/', ' '], "-")
|
||||
);
|
||||
ConfigBundle {
|
||||
Ok(ConfigBundle {
|
||||
metadata: ConfigBundleMetadata {
|
||||
id,
|
||||
digest: String::new(),
|
||||
@@ -2373,13 +2389,16 @@ fn default_embedded_config_bundle(profile: &ProfileSelector) -> ConfigBundle {
|
||||
label: embedded_profile_label(profile),
|
||||
}],
|
||||
declarations: Vec::new(),
|
||||
profile_source_archive: Some(default_profile_source_archive(profile)),
|
||||
profile_source_archive: Some(default_profile_source_archive(profile)?),
|
||||
}
|
||||
.with_computed_digest()
|
||||
.with_computed_digest())
|
||||
}
|
||||
|
||||
fn default_profile_source_archive(profile: &ProfileSelector) -> ProfileSourceArchive {
|
||||
fn default_profile_source_archive(
|
||||
profile: &ProfileSelector,
|
||||
) -> Result<ProfileSourceArchive, String> {
|
||||
let selected = embedded_profile_label(profile).unwrap_or_else(|| "default".to_string());
|
||||
let selected_path = embedded_profile_path(profile)?;
|
||||
let mut entrypoints = BTreeMap::new();
|
||||
entrypoints.insert("default".to_string(), "profiles/default.dcdl".to_string());
|
||||
entrypoints.insert(
|
||||
@@ -2389,7 +2408,7 @@ fn default_profile_source_archive(profile: &ProfileSelector) -> ProfileSourceArc
|
||||
for slug in ["companion", "intake", "orchestrator", "coder", "reviewer"] {
|
||||
entrypoints.insert(format!("builtin:{slug}"), format!("profiles/{slug}.dcdl"));
|
||||
}
|
||||
entrypoints.insert(selected, embedded_profile_path(profile));
|
||||
entrypoints.insert(selected, selected_path);
|
||||
|
||||
let mut sources = BTreeMap::new();
|
||||
sources.insert(
|
||||
@@ -2423,22 +2442,22 @@ fn default_profile_source_archive(profile: &ProfileSelector) -> ProfileSourceArc
|
||||
imports: BTreeMap::new(),
|
||||
sources,
|
||||
})
|
||||
.expect("builtin Decodal profile source archive is valid")
|
||||
.map_err(|err| err.to_string())
|
||||
}
|
||||
|
||||
fn embedded_profile_path(profile: &ProfileSelector) -> String {
|
||||
fn embedded_profile_path(profile: &ProfileSelector) -> Result<String, String> {
|
||||
match profile {
|
||||
ProfileSelector::RuntimeDefault => "profiles/default.dcdl".to_string(),
|
||||
ProfileSelector::Builtin(name) | ProfileSelector::Named(name) => {
|
||||
match name.strip_prefix("builtin:").unwrap_or(name) {
|
||||
"companion" => "profiles/companion.dcdl".to_string(),
|
||||
"intake" => "profiles/intake.dcdl".to_string(),
|
||||
"orchestrator" => "profiles/orchestrator.dcdl".to_string(),
|
||||
"coder" => "profiles/coder.dcdl".to_string(),
|
||||
"reviewer" => "profiles/reviewer.dcdl".to_string(),
|
||||
_ => "profiles/default.dcdl".to_string(),
|
||||
}
|
||||
}
|
||||
ProfileSelector::RuntimeDefault => Ok("profiles/default.dcdl".to_string()),
|
||||
ProfileSelector::Builtin(name) => match name.strip_prefix("builtin:").unwrap_or(name) {
|
||||
"default" => Ok("profiles/default.dcdl".to_string()),
|
||||
"companion" => Ok("profiles/companion.dcdl".to_string()),
|
||||
"intake" => Ok("profiles/intake.dcdl".to_string()),
|
||||
"orchestrator" => Ok("profiles/orchestrator.dcdl".to_string()),
|
||||
"coder" => Ok("profiles/coder.dcdl".to_string()),
|
||||
"reviewer" => Ok("profiles/reviewer.dcdl".to_string()),
|
||||
other => Err(format!("unknown builtin profile selector: builtin:{other}")),
|
||||
},
|
||||
ProfileSelector::Named(name) => Err(format!("unknown named profile selector: {name}")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2945,6 +2964,49 @@ mod tests {
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
#[test]
|
||||
fn embedded_builtin_decodal_profiles_resolve_through_archive() {
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
for selector in [
|
||||
ProfileSelector::RuntimeDefault,
|
||||
ProfileSelector::Builtin("builtin:companion".to_string()),
|
||||
ProfileSelector::Builtin("builtin:intake".to_string()),
|
||||
ProfileSelector::Builtin("builtin:orchestrator".to_string()),
|
||||
ProfileSelector::Builtin("builtin:coder".to_string()),
|
||||
ProfileSelector::Builtin("builtin:reviewer".to_string()),
|
||||
] {
|
||||
let bundle = default_embedded_config_bundle(&selector).unwrap();
|
||||
let archive = bundle
|
||||
.profile_source_archive
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.verify()
|
||||
.unwrap();
|
||||
let selector_key = match &selector {
|
||||
ProfileSelector::RuntimeDefault => "default".to_string(),
|
||||
ProfileSelector::Builtin(name) => name.clone(),
|
||||
ProfileSelector::Named(name) => name.clone(),
|
||||
};
|
||||
let manifest = archive
|
||||
.resolve_profile(&selector_key, root.path(), "embedded-test-worker")
|
||||
.unwrap();
|
||||
assert_eq!(manifest.worker.name, "embedded-test-worker");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn embedded_archive_rejects_unknown_selectors() {
|
||||
assert!(
|
||||
default_embedded_config_bundle(&ProfileSelector::Builtin(
|
||||
"builtin:missing".to_string()
|
||||
))
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
default_embedded_config_bundle(&ProfileSelector::Named("custom".to_string())).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
fn test_config_bundle() -> ConfigBundle {
|
||||
ConfigBundle {
|
||||
metadata: worker_runtime::config_bundle::ConfigBundleMetadata {
|
||||
|
||||
Reference in New Issue
Block a user