0
votes

I'm trying to define a json schema that requires some fields if a control field is true. I just made the following schema (I tried more than 1 solution from google, so there is some differences between the if statements...):

{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "if": {
    "not": {
      "properties": {
        "ldap_enable": {
          "enum": [ false ]
        }
      }
    }
  },
  "then": {
    "required": ["ldap_binddn", 
                 "ldap_bindpassword",
                 "ldap_server",
                 "ldap_searchdn",
                 "ldap_searchfilter",
                 "ldap_mappings",
                 "ldap_needtls" 
                ]
  },
  "if": {
    "properties" : {
      "telegram_alert": {
        "enum": [ 
        true 
       ]
      }
    }
   },
  "then": {
    "required": ["telegram_chat", 
                 "telegram_token"
                ]
  },
  "if": {
    "properties" : {
      "email_alert": {
        "enum": [ 
        true 
       ]
      }
    }
   },
  "then": {
    "required": ["email_sender", 
                 "email_host",
                 "email_port"
                ]
  },
  "required": [
    "mysql",
    "port",
    "tmp_path",
    "cookie_hash",
    "cookie_encryption",
    "web_host",
    "concurrency_mode",
    "max_parallel_tasks",
    "email_alert",
    "telegram_alert",
    "ldap_enable"
  ],
  "properties": {
    "mysql": {
      "$id": "#/properties/mysql",
      "type": "object",
      "title": "The Mysql Schema",
      "required": [
        "host",
        "user",
        "pass",
        "name"
      ],
      "properties": {
        "host": {
          "$id": "#/properties/mysql/properties/host",
          "type": "string",
          "title": "DB Address",
          "default": "db",
          "pattern": "^(.*)$"
        },
        "user": {
          "$id": "#/properties/mysql/properties/user",
          "type": "string",
          "title": "Username for DB",
          "default": "semaphore",
          "pattern": "^(.*)$"
        },
        "pass": {
          "$id": "#/properties/mysql/properties/pass",
          "type": "string",
          "title": "User Password",
          "default": "semaphore",
          "pattern": "^(.*)$"
        },
        "name": {
          "$id": "#/properties/mysql/properties/name",
          "type": "string",
          "title": "Schema Name on DB",
          "default": "semaphore",
          "pattern": "^(.*)$"
        }
      }
    },
    "port": {
      "$id": "#/properties/port",
      "type": "string",
      "title": "The port where app will listen.",
      "default": "3000"
    },
    "tmp_path": {
      "$id": "#/properties/tmp_path",
      "type": "string",
      "title": "The path where the playbooks will be temporary placed.",
      "default": "/tmp",
      "pattern": "^(.*)$"
    },
    "cookie_hash": {
      "$id": "#/properties/cookie_hash",
      "type": "string",
      "title": "Cookie Hash for Site",
      "pattern": "^(.*)$"
    },
    "cookie_encryption": {
      "$id": "#/properties/cookie_encryption",
      "type": "string",
      "title": "The Cookie_encryption",
      "pattern": "^(.*)$"
    },
    "email_sender": {
      "$id": "#/properties/email_sender",
      "type": "string",
      "default": "semaphore@localhost",
      "pattern": "^(.*)$"
    },
    "email_host": {
      "$id": "#/properties/email_host",
      "type": "string",
      "title": "The Email_host Schema",
      "pattern": "^(.*)$"
    },
    "email_port": {
      "$id": "#/properties/email_port",
      "type": "string",
      "title": "The Email_port Schema",
      "pattern": "^(.*)$"
    },
    "web_host": {
      "$id": "#/properties/web_host",
      "type": "string",
      "title": "The Web_host Schema",
      "default": "http://localhost:3000",
      "pattern": "^(.*)$"
    },
    "ldap_binddn": {
      "$id": "#/properties/ldap_binddn",
      "type": "string",
      "title": "Ldap Bind User.",
      "examples": [
        "cn=bla,dc=com"
      ],
      "pattern": "^(.*)$"
    },
    "ldap_bindpassword": {
      "$id": "#/properties/ldap_bindpassword",
      "type": "string",
      "title": "Ldap Bind Password",
      "pattern": "^(.*)$"
    },
    "ldap_server": {
      "$id": "#/properties/ldap_server",
      "type": "string",
      "title": "Ldap Server",
      "default": "ldap",
      "pattern": "^(.*)$"
    },
    "ldap_searchdn": {
      "$id": "#/properties/ldap_searchdn",
      "type": "string",
      "title": "The Ldap_searchdn Schema",
      "examples": [
        "ou=user,dc=example"
      ],
      "pattern": "^(.*)$"
    },
    "ldap_searchfilter": {
      "$id": "#/properties/ldap_searchfilter",
      "type": "string",
      "title": "The Ldap_searchfilter Schema",
      "examples": [
        "(uid=%s)"
      ],
      "pattern": "^(.*)$"
    },
    "ldap_mappings": {
      "$id": "#/properties/ldap_mappings",
      "type": "object",
      "title": "The Ldap_mappings Schema",
      "required": [
        "dn",
        "mail",
        "uid",
        "cn"
      ],
      "properties": {
        "dn": {
          "$id": "#/properties/ldap_mappings/properties/dn",
          "type": "string",
          "title": "The Dn Schema",
          "default": "dn",
          "examples": [
            "dn"
          ],
          "pattern": "^(.*)$"
        },
        "mail": {
          "$id": "#/properties/ldap_mappings/properties/mail",
          "type": "string",
          "title": "The Mail Schema",
          "default": "mail",
          "examples": [
            "mail"
          ],
          "pattern": "^(.*)$"
        },
        "uid": {
          "$id": "#/properties/ldap_mappings/properties/uid",
          "type": "string",
          "title": "The Uid Schema",
          "default": "uid",
          "examples": [
            "uid"
          ],
          "pattern": "^(.*)$"
        },
        "cn": {
          "$id": "#/properties/ldap_mappings/properties/cn",
          "type": "string",
          "title": "The Cn Schema",
          "default": "cn",
          "examples": [
            "cn"
          ],
          "pattern": "^(.*)$"
        }
      }
    },
    "telegram_chat": {
      "$id": "#/properties/telegram_chat",
      "type": "string",
      "title": "The Telegram_chat Schema",
      "examples": [
        "asdfasdf"
      ],
      "pattern": "^(.*)$"
    },
    "telegram_token": {
      "$id": "#/properties/telegram_token",
      "type": "string",
      "title": "The Telegram_token Schema",
      "examples": [
        "asdfasdf"
      ],
      "pattern": "^(.*)$"
    },
    "concurrency_mode": {
      "$id": "#/properties/concurrency_mode",
      "type": "string",
      "title": "The Concurrency_mode Schema",
      "default": "",
      "examples": [
        ""
      ],
      "pattern": "^(.*)$"
    },
    "max_parallel_tasks": {
      "$id": "#/properties/max_parallel_tasks",
      "type": "integer",
      "title": "The Max_parallel_tasks Schema",
      "default": 0
    },
    "email_alert": {
      "$id": "#/properties/email_alert",
      "type": "boolean",
      "title": "The Email_alert Schema",
      "default": false,
      "examples": [
        true
      ]
    },
    "telegram_alert": {
      "$id": "#/properties/telegram_alert",
      "type": "boolean",
      "title": "The Telegram_alert Schema",
      "default": false,
      "examples": [
        true
      ]
    },
    "ldap_enable": {
      "$id": "#/properties/ldap_enable",
      "type": "boolean",
      "title": "The Ldap_enable Schema",
      "default": false,
      "examples": [
        true
      ]
    },
    "ldap_needtls": {
      "$id": "#/properties/ldap_needtls",
      "type": "boolean",
      "title": "The Ldap_needtls Schema",
      "default": false,
      "examples": [
        true
      ]
    }
  }
}

Then I just checked the following json against the schema:

{
    "mysql": {
        "host": "db",
        "user": "semaphore",
        "pass": "semaphore",
        "name": "semaphore"
    },
    "port": "",
    "tmp_path": "/bla",
    "cookie_hash": "93n2lvoStnqjskpqea5P+04hPo1CEoEj9fJ68BARtYA=",
    "cookie_encryption": "602ZDI0qYlScN+FH6ivx75ERWfS+0E4aHV5WaYGHI4s=",
    "email_sender": "semaphore@localhost",
    "email_host": "server",
    "email_port": "25",
    "web_host": "http://whoknows",
    "telegram_chat": "asdfasdf",
    "telegram_token": "asdfasdf",
    "concurrency_mode": "",
    "max_parallel_tasks": 0,
    "email_alert": true,
    "telegram_alert": true,
    "ldap_enable": true,
    "ldap_needtls": true
 }

I just expected a validation error here, the ldap_* fields should be required because ldap_enable is true, but instead "https://www.jsonschemavalidator.net/" site and python jsonschema lib returns that the json is valid.

1

1 Answers

2
votes

You have keyword duplication (if, then) at root level of your schema. If multiple conditions are needed you can group them with oneOf, allOf, anyOf arrays depending on your requirements.

Please check this schema:

{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "allOf": [
    {
      "if": {
        "properties": {
          "ldap_enable": {
            "enum": [
              true
            ]
          }
        }
      },
      "then": {
        "required": [
          "ldap_binddn",
          "ldap_bindpassword",
          "ldap_server",
          "ldap_searchdn",
          "ldap_searchfilter",
          "ldap_mappings",
          "ldap_needtls"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "telegram_alert": {
            "enum": [
              true
            ]
          }
        }
      },
      "then": {
        "required": [
          "telegram_chat",
          "telegram_token"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "email_alert": {
            "enum": [
              true
            ]
          }
        }
      },
      "then": {
        "required": [
          "email_sender",
          "email_host",
          "email_port"
        ]
      }
    }
  ],
  "required": [
    "mysql",
    "port",
    "tmp_path",
    "cookie_hash",
    "cookie_encryption",
    "web_host",
    "concurrency_mode",
    "max_parallel_tasks",
    "email_alert",
    "telegram_alert",
    "ldap_enable"
  ],
  "properties": {
    "mysql": {
      "$id": "#/properties/mysql",
      "type": "object",
      "title": "The Mysql Schema",
      "required": [
        "host",
        "user",
        "pass",
        "name"
      ],
      "properties": {
        "host": {
          "$id": "#/properties/mysql/properties/host",
          "type": "string",
          "title": "DB Address",
          "default": "db",
          "pattern": "^(.*)$"
        },
        "user": {
          "$id": "#/properties/mysql/properties/user",
          "type": "string",
          "title": "Username for DB",
          "default": "semaphore",
          "pattern": "^(.*)$"
        },
        "pass": {
          "$id": "#/properties/mysql/properties/pass",
          "type": "string",
          "title": "User Password",
          "default": "semaphore",
          "pattern": "^(.*)$"
        },
        "name": {
          "$id": "#/properties/mysql/properties/name",
          "type": "string",
          "title": "Schema Name on DB",
          "default": "semaphore",
          "pattern": "^(.*)$"
        }
      }
    },
    "port": {
      "$id": "#/properties/port",
      "type": "string",
      "title": "The port where app will listen.",
      "default": "3000"
    },
    "tmp_path": {
      "$id": "#/properties/tmp_path",
      "type": "string",
      "title": "The path where the playbooks will be temporary placed.",
      "default": "/tmp",
      "pattern": "^(.*)$"
    },
    "cookie_hash": {
      "$id": "#/properties/cookie_hash",
      "type": "string",
      "title": "Cookie Hash for Site",
      "pattern": "^(.*)$"
    },
    "cookie_encryption": {
      "$id": "#/properties/cookie_encryption",
      "type": "string",
      "title": "The Cookie_encryption",
      "pattern": "^(.*)$"
    },
    "email_sender": {
      "$id": "#/properties/email_sender",
      "type": "string",
      "default": "semaphore@localhost",
      "pattern": "^(.*)$"
    },
    "email_host": {
      "$id": "#/properties/email_host",
      "type": "string",
      "title": "The Email_host Schema",
      "pattern": "^(.*)$"
    },
    "email_port": {
      "$id": "#/properties/email_port",
      "type": "string",
      "title": "The Email_port Schema",
      "pattern": "^(.*)$"
    },
    "web_host": {
      "$id": "#/properties/web_host",
      "type": "string",
      "title": "The Web_host Schema",
      "default": "http://localhost:3000",
      "pattern": "^(.*)$"
    },
    "ldap_binddn": {
      "$id": "#/properties/ldap_binddn",
      "type": "string",
      "title": "Ldap Bind User.",
      "examples": [
        "cn=bla,dc=com"
      ],
      "pattern": "^(.*)$"
    },
    "ldap_bindpassword": {
      "$id": "#/properties/ldap_bindpassword",
      "type": "string",
      "title": "Ldap Bind Password",
      "pattern": "^(.*)$"
    },
    "ldap_server": {
      "$id": "#/properties/ldap_server",
      "type": "string",
      "title": "Ldap Server",
      "default": "ldap",
      "pattern": "^(.*)$"
    },
    "ldap_searchdn": {
      "$id": "#/properties/ldap_searchdn",
      "type": "string",
      "title": "The Ldap_searchdn Schema",
      "examples": [
        "ou=user,dc=example"
      ],
      "pattern": "^(.*)$"
    },
    "ldap_searchfilter": {
      "$id": "#/properties/ldap_searchfilter",
      "type": "string",
      "title": "The Ldap_searchfilter Schema",
      "examples": [
        "(uid=%s)"
      ],
      "pattern": "^(.*)$"
    },
    "ldap_mappings": {
      "$id": "#/properties/ldap_mappings",
      "type": "object",
      "title": "The Ldap_mappings Schema",
      "required": [
        "dn",
        "mail",
        "uid",
        "cn"
      ],
      "properties": {
        "dn": {
          "$id": "#/properties/ldap_mappings/properties/dn",
          "type": "string",
          "title": "The Dn Schema",
          "default": "dn",
          "examples": [
            "dn"
          ],
          "pattern": "^(.*)$"
        },
        "mail": {
          "$id": "#/properties/ldap_mappings/properties/mail",
          "type": "string",
          "title": "The Mail Schema",
          "default": "mail",
          "examples": [
            "mail"
          ],
          "pattern": "^(.*)$"
        },
        "uid": {
          "$id": "#/properties/ldap_mappings/properties/uid",
          "type": "string",
          "title": "The Uid Schema",
          "default": "uid",
          "examples": [
            "uid"
          ],
          "pattern": "^(.*)$"
        },
        "cn": {
          "$id": "#/properties/ldap_mappings/properties/cn",
          "type": "string",
          "title": "The Cn Schema",
          "default": "cn",
          "examples": [
            "cn"
          ],
          "pattern": "^(.*)$"
        }
      }
    },
    "telegram_chat": {
      "$id": "#/properties/telegram_chat",
      "type": "string",
      "title": "The Telegram_chat Schema",
      "examples": [
        "asdfasdf"
      ],
      "pattern": "^(.*)$"
    },
    "telegram_token": {
      "$id": "#/properties/telegram_token",
      "type": "string",
      "title": "The Telegram_token Schema",
      "examples": [
        "asdfasdf"
      ],
      "pattern": "^(.*)$"
    },
    "concurrency_mode": {
      "$id": "#/properties/concurrency_mode",
      "type": "string",
      "title": "The Concurrency_mode Schema",
      "default": "",
      "examples": [
        ""
      ],
      "pattern": "^(.*)$"
    },
    "max_parallel_tasks": {
      "$id": "#/properties/max_parallel_tasks",
      "type": "integer",
      "title": "The Max_parallel_tasks Schema",
      "default": 0
    },
    "email_alert": {
      "$id": "#/properties/email_alert",
      "type": "boolean",
      "title": "The Email_alert Schema",
      "default": false,
      "examples": [
        true
      ]
    },
    "telegram_alert": {
      "$id": "#/properties/telegram_alert",
      "type": "boolean",
      "title": "The Telegram_alert Schema",
      "default": false,
      "examples": [
        true
      ]
    },
    "ldap_enable": {
      "$id": "#/properties/ldap_enable",
      "type": "boolean",
      "title": "The Ldap_enable Schema",
      "default": false,
      "examples": [
        true
      ]
    },
    "ldap_needtls": {
      "$id": "#/properties/ldap_needtls",
      "type": "boolean",
      "title": "The Ldap_needtls Schema",
      "default": false,
      "examples": [
        true
      ]
    }
  }
}