diff --git a/crates/wadm-types/src/validation.rs b/crates/wadm-types/src/validation.rs index 81790ae8..12e3d343 100644 --- a/crates/wadm-types/src/validation.rs +++ b/crates/wadm-types/src/validation.rs @@ -8,6 +8,7 @@ use std::sync::OnceLock; use anyhow::{Context as _, Result}; use regex::Regex; use serde::{Deserialize, Serialize}; +use serde_json::Value; use crate::{LinkProperty, Manifest, TraitProperty, LATEST_VERSION}; @@ -327,6 +328,7 @@ pub async fn validate_manifest(manifest: &Manifest) -> Result Vec { failures } +fn check_source_config_on_components(manifest: &Manifest) -> Vec { + let forbidden_config_key = "source_config"; + let mut failures = Vec::new(); + let components = manifest.component_lookup(); + let component_traits = components + .into_iter() + .filter_map(|(name, component)| match &component.traits { + Some(traits) => Some((name, traits)), + None => None, + }); + for (name, traits) in component_traits { + for trait_ in traits { + if let TraitProperty::Custom(custom) = trait_.properties.clone() { + if let Some(_) = custom.get(forbidden_config_key) { + failures.push(ValidationFailure::new( + ValidationFailureLevel::Error, + format!( + "component [{name}] has source_config in one of its traits properties", + ), + )) + } + } + } + } + failures +} + #[cfg(test)] mod tests { use super::is_valid_manifest_name; diff --git a/tests/fixtures/manifests/with-source-config-on-component.wadm.yaml b/tests/fixtures/manifests/with-source-config-on-component.wadm.yaml new file mode 100644 index 00000000..ab76abe5 --- /dev/null +++ b/tests/fixtures/manifests/with-source-config-on-component.wadm.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: sample_application_with_source_config_on_component + annotations: + version: v0.0.1 + description: Sample manifest that does not pass since it has a source_config on a component +spec: + components: + - name: http-component + type: component + properties: + image: ghcr.io/wasmcloud/component-http-hello-world:0.1.0 + traits: + - type: spreadscaler + properties: + instances: 1 + # This is not allowed since 1.0.0 should error during validation + source_config: + - name: any_value + properties: + SOME_OTHER_KEY: any_other_value \ No newline at end of file diff --git a/tests/validation.rs b/tests/validation.rs index d7d960dc..dde0b00d 100644 --- a/tests/validation.rs +++ b/tests/validation.rs @@ -1,6 +1,6 @@ use anyhow::{Context as _, Result}; -use wadm_types::validation::{validate_manifest_file, ValidationFailureLevel, ValidationOutput}; +use wadm_types::validation::{validate_manifest_file, ValidationFailure, ValidationFailureLevel, ValidationOutput}; /// Ensure that valid YAML manifests are valid #[tokio::test] @@ -120,3 +120,27 @@ async fn validate_policy() -> Result<()> { assert!(failures.valid(), "manifest is valid"); Ok(()) } + +#[tokio::test] +async fn validate_source_config_on_component_errors() -> Result<()> { + let (_manifest, failures) = validate_manifest_file( + "./tests/fixtures/manifests/with-source-config-on-component.wadm.yaml", + ) + .await + .context("failed to validate manifest")?; + assert!(!failures.is_empty(), "failures present, all errors"); + let failures = failures.iter().collect::>(); + assert_eq!(failures.len(), 1, "expected one failure"); + let ValidationFailure { level, msg, .. } = failures.get(0).expect("expected one failure"); + assert_eq!( + *level, + ValidationFailureLevel::Error, + "expected error level" + ); + assert_eq!( + msg, + "component [http-component] has source_config in one of its traits properties", + "expected error message, but was incorrect", + ); + Ok(()) +}