Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dsc_lib/locales/en-us.toml
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,9 @@ schemaNotAvailable = "No Schema found and `validate` is not supported"
securityContext = "Security context"
utf8Conversion = "UTF-8 conversion"
unknown = "Unknown"
unrecognizedSchemaUri = "Unrecognized $schema URI"
validation = "Validation"
validSchemaUrisAre = "Valid schema URIs are"
setting = "Setting"

[progress]
Expand Down
55 changes: 54 additions & 1 deletion dsc_lib/src/configure/config_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::collections::HashMap;

use crate::schemas::DscRepoSchema;
use crate::{dscerror::DscError, schemas::DscRepoSchema};

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -165,6 +165,16 @@ impl DscRepoSchema for Configuration {
..Default::default()
}
}

fn validate_schema_uri(&self) -> Result<(), DscError> {
match Self::is_recognized_schema_uri(&self.schema) {
true => Ok(()),
false => Err(DscError::UnrecognizedSchemaUri(
self.schema.clone(),
Self::recognized_schema_uris(),
))
}
}
}

impl Configuration {
Expand Down Expand Up @@ -199,3 +209,46 @@ impl Default for Resource {
Self::new()
}
}

#[allow(unused_imports)]
mod test {
use serde_json::json;

use crate::{configure::config_doc::Configuration, dscerror::DscError, dscresources::resource_manifest::{import_manifest, ResourceManifest}, schemas::DscRepoSchema};

#[test]
fn test_validate_schema_uri_with_invalid_uri() {
let invalid_uri = "https://invalid.schema.uri".to_string();

let manifest = Configuration{
schema: invalid_uri.clone(),
..Default::default()
};

let ref result = manifest.validate_schema_uri();

assert!(result.as_ref().is_err());

match result.as_ref().unwrap_err() {
DscError::UnrecognizedSchemaUri(actual, recognized) => {
assert_eq!(actual, &invalid_uri);
assert_eq!(recognized, &Configuration::recognized_schema_uris())
},
_ => {
panic!("Expected validate_schema_uri() to error on unrecognized schema uri, but was {:?}", result.as_ref().unwrap_err())
}
}
}

#[test]
fn test_validate_schema_uri_with_valid_uri() {
let manifest = Configuration{
schema: Configuration::default_schema_id_uri(),
..Default::default()
};

let result = manifest.validate_schema_uri();

assert!(result.is_ok());
}
}
3 changes: 3 additions & 0 deletions dsc_lib/src/dscerror.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ pub enum DscError {
message: String,
},

#[error("{t}: {0}. {t2}: {1:?}", t = t!("dscerror.unrecognizedSchemaUri"), t2 = t!("dscerror.validSchemaUrisAre"))]
UnrecognizedSchemaUri(String, Vec<String>),

#[error("{t}: {0}", t = t!("dscerror.validation"))]
Validation(String),

Expand Down
57 changes: 57 additions & 0 deletions dsc_lib/src/dscresources/resource_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,16 @@ impl DscRepoSchema for ResourceManifest {
..Default::default()
}
}

fn validate_schema_uri(&self) -> Result<(), DscError> {
match Self::is_recognized_schema_uri(&self.schema_version) {
true => Ok(()),
false => Err(DscError::UnrecognizedSchemaUri(
self.schema_version.clone(),
Self::recognized_schema_uris(),
))
}
}
}

/// Import a resource manifest from a JSON value.
Expand Down Expand Up @@ -288,3 +298,50 @@ pub fn validate_semver(version: &str) -> Result<(), semver::Error> {
Version::parse(version)?;
Ok(())
}

#[allow(unused_imports)]
mod test {
use serde_json::json;

use crate::{dscerror::DscError, dscresources::resource_manifest::{import_manifest, ResourceManifest}, schemas::DscRepoSchema};

#[test]
fn test_validate_schema_uri_with_invalid_uri() {
let invalid_uri = "https://invalid.schema.uri".to_string();

let manifest = ResourceManifest{
schema_version: invalid_uri.clone(),
resource_type: "Microsoft.Dsc.Test/InvalidSchemaUri".to_string(),
version: "0.1.0".to_string(),
..Default::default()
};

let ref result = manifest.validate_schema_uri();

assert!(result.as_ref().is_err());

match result.as_ref().unwrap_err() {
DscError::UnrecognizedSchemaUri(actual, recognized) => {
assert_eq!(actual, &invalid_uri);
assert_eq!(recognized, &ResourceManifest::recognized_schema_uris())
},
_ => {
panic!("Expected validate_schema_uri() to error on unrecognized schema uri, but was {:?}", result.as_ref().unwrap_err())
}
}
}

#[test]
fn test_validate_schema_uri_with_valid_uri() {
let manifest = ResourceManifest{
schema_version: ResourceManifest::default_schema_id_uri(),
resource_type: "Microsoft.Dsc.Test/ValidSchemaUri".to_string(),
version: "0.1.0".to_string(),
..Default::default()
};

let result = manifest.validate_schema_uri();

assert!(result.is_ok());
}
}
22 changes: 22 additions & 0 deletions dsc_lib/src/schemas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use schemars::{schema::{Metadata, Schema}, JsonSchema};

use crate::dscerror::DscError;

/// Defines the URI prefix for the hosted schemas.
///
/// While the schemas are currently hosted in the GitHub repository, DSC provides the shortened
Expand Down Expand Up @@ -447,6 +449,26 @@ pub trait DscRepoSchema : JsonSchema {
Self::SCHEMA_SHOULD_BUNDLE
)
}

/// Indicates whether a given string is a recognized shema URI.
fn is_recognized_schema_uri(uri: &String) -> bool {
Self::recognized_schema_uris().contains(uri)
}

/// Validates the `$schema` keyword for deserializing instances.
///
/// This method simplifies the validation of a type that has the `$schema` keyword and expects
/// that instances of the type in data indicate which schema version DSC should use to validate
/// them.
///
/// This method includes a default implementation to avoid requiring the implementation for
/// types that don't define the `$schema` keyword in their serialized form.
///
/// Any DSC type that serializes with the `$schema` keyword **must** define this
/// method to actually validate the instance.
fn validate_schema_uri(&self) -> Result<(), DscError> {
Ok(())
}
}

#[allow(unused_imports)]
Expand Down