lenso_app_authoring/host_authoring/
policy.rs1use anyhow::{Context, bail};
2use lenso_app_plan::authoring::PluginDescriptor;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Clone, Debug, Deserialize, Serialize)]
8#[serde(deny_unknown_fields)]
9pub struct AdmittedRelease {
10 pub descriptor: PluginDescriptor,
11 pub manifest_digest: String,
12}
13
14#[derive(Clone, Debug, Deserialize, Serialize)]
16#[serde(deny_unknown_fields)]
17pub struct SlotAdmission {
18 pub slot: String,
19 pub max_instances: usize,
20 pub releases: Vec<AdmittedRelease>,
21 pub configuration_schema: Option<Value>,
22}
23
24pub(super) fn compile_ceiling(schema: &Value) -> anyhow::Result<jsonschema::Validator> {
26 check_schema(schema, 0, &mut 0)?;
27 jsonschema::draft202012::options()
28 .build(schema)
29 .map_err(|_| anyhow::anyhow!("invalid Host configuration ceiling schema"))
30}
31
32fn check_schema(schema: &Value, depth: usize, count: &mut usize) -> anyhow::Result<()> {
33 *count += 1;
34 if depth > 64 || *count > 4096 {
35 bail!("Host configuration schema exceeds depth/node limits");
36 }
37 if schema.is_boolean() {
38 return Ok(());
39 }
40 let object = schema
41 .as_object()
42 .context("Host configuration schema must be an object or boolean")?;
43 for (key, value) in object {
44 match key.as_str() {
45 "properties" => {
46 for child in value
47 .as_object()
48 .context("schema properties must be an object")?
49 .values()
50 {
51 check_schema(child, depth + 1, count)?;
52 }
53 }
54 "items" | "additionalProperties" | "not" | "if" | "then" | "else" => {
55 check_schema(value, depth + 1, count)?;
56 }
57 "allOf" | "anyOf" | "oneOf" => {
58 for child in value
59 .as_array()
60 .context("schema combinator must be an array")?
61 {
62 check_schema(child, depth + 1, count)?;
63 }
64 }
65 "type" | "const" | "enum" | "required" | "minimum" | "maximum" | "minItems"
66 | "maxItems" | "uniqueItems" | "minLength" | "maxLength" | "title" | "description"
67 | "$comment" => {}
68 _ => bail!("unsupported Host configuration schema keyword `{key}`"),
69 }
70 }
71 Ok(())
72}