Files
windmill/backend/windmill-worker/src/schema.rs
wendrul 6634c82e20 feat: backend arg schema validation (#5455)
* Make schema validation struct

Schema Validation rules that are constructed from the schema or from the
MainArgSig(TODO).

* Make other validator builder

* Fail dependency job like with lockfile failing for schema validator

* Add last types + tests

* Remove unused dependency

* fix typos

* Migration ID was colliding with another, changed it manually

* Add Oneof + other fixes

* fix: cache for querying scripts correclty handles ScriptMetadata

* Add cache for schema validation from main arg sig

* Prepare sqlx

* Remove default features

* Feature flags

* Fix down migration table name

* cleanup: put validation logic inside a function

* Refactor to cache the should_validate boolean

Changed the schemavalidators cache to take in an
Option<SchemaValidator>, effectively storing the `should_validate_schema` information.

Also pass the schema when avaialble to construct the schema validator

* Add other job kinds to u8 cache key just in case

* Only cache if not preview
2025-03-19 19:41:10 +01:00

95 lines
2.9 KiB
Rust

use std::collections::HashMap;
use windmill_common::schema::{SchemaValidationRule, SchemaValidator};
use windmill_parser::{MainArgSignature, Typ};
fn make_rules_for_arg_typ(typ: &Typ) -> Vec<SchemaValidationRule> {
let mut rules = vec![];
match typ {
Typ::Str(enum_variants) => {
rules.push(SchemaValidationRule::IsString);
if let Some(enum_variants) = enum_variants {
rules.push(SchemaValidationRule::StrictEnum(
enum_variants
.iter()
.map(|v| serde_json::Value::String(v.to_string()))
.collect(),
));
}
}
Typ::Int => {
rules.push(SchemaValidationRule::IsInteger);
}
Typ::Float => {
rules.push(SchemaValidationRule::IsNumber);
}
Typ::Bool => {
rules.push(SchemaValidationRule::IsBool);
}
Typ::List(typ) => {
rules.push(SchemaValidationRule::IsArray(make_rules_for_arg_typ(typ)));
}
Typ::Bytes => {
rules.push(SchemaValidationRule::IsString);
rules.push(SchemaValidationRule::IsBytes);
}
Typ::Datetime => {
rules.push(SchemaValidationRule::IsString);
rules.push(SchemaValidationRule::IsDatetime);
}
Typ::Email => {
rules.push(SchemaValidationRule::IsString);
rules.push(SchemaValidationRule::IsEmail);
}
Typ::Sql => {
rules.push(SchemaValidationRule::IsString);
}
Typ::Object(props) => {
let mut obj_rules = vec![];
for prop in props {
obj_rules.push((prop.key.to_string(), make_rules_for_arg_typ(&prop.typ)));
}
rules.push(SchemaValidationRule::IsObject(obj_rules))
}
Typ::OneOf(variants) => {
let mut rules_map = HashMap::new();
for variant in variants {
let mut obj_rules = vec![];
for prop in &variant.properties {
obj_rules.push((prop.key.to_string(), make_rules_for_arg_typ(&prop.typ)));
}
rules_map.insert(variant.label.to_string(), vec![SchemaValidationRule::IsObject(obj_rules)]);
}
rules.push(SchemaValidationRule::IsOneOf(rules_map))
}
Typ::Resource(_) => (),
Typ::DynSelect(_) => (),
Typ::Unknown => (),
}
rules
}
pub fn schema_validator_from_main_arg_sig(sig: &MainArgSignature) -> SchemaValidator {
let mut rules = vec![];
let mut required = vec![];
for arg in &sig.args {
if !arg.has_default {
required.push(arg.name.to_string());
}
rules.push((arg.name.to_string(), make_rules_for_arg_typ(&arg.typ)));
}
SchemaValidator { required, rules }
}