【问题标题】:How to use $ref with json-schema and top level properties如何将 $ref 与 json-schema 和顶级属性一起使用
【发布时间】:2021-04-25 00:52:09
【问题描述】:

朋友们好 :) 我有一个如下所示的 JSON 架构:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Sync Repo Settings Config",
  "description": "Schema for defining the sync repo settings config",
  "additionalProperties": false,
  "type": "object",
  "$ref": "#/definitions/repoConfig",
  "definitions": {
    "repoConfig": {
      "type": "object",
      "properties": {
        "name": {
          "description": "A simple label for describing the ruleset.",
          "type": "string"
        },
        "selector": {
          "description": "For use in the org/.github repository. A GitHub repo search query that identifies the repositories which should be managed by the given rule.",
          "type": "boolean"
        },
        "squashMergeAllowed": {
          "description": "Whether or not squash-merging is enabled on this repository.",
          "type": "boolean"
        },
        "rebaseMergeAllowed": {
          "description": "Whether or not rebase-merging is enabled on this repository.",
          "type": "boolean"
        },
        "mergeCommitAllowed": {
          "description": "Whether or not PRs are merged with a merge commit on this repository.",
          "type": "boolean"
        },
        "deleteBranchOnMerge": {
          "description": "Either true to allow automatically deleting head branches when pull requests are merged, or false to prevent automatic deletion.",
          "type": "boolean"
        },
        "branchProtectionRules": {
          "description": "Branch protection rules",
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "pattern": {
                "description": "Identifies the protection rule pattern.",
                "type": "string"
              },
              "dismissesStaleReviews": {
                "description": "Will new commits pushed to matching branches dismiss pull request review approvals.",
                "type": "boolean"
              },
              "isAdminEnforced": {
                "description": "Can admins overwrite branch protection.",
                "type": "boolean"
              },
              "requiredApprovingReviewCount": {
                "description": "Number of approving reviews required to update matching branches.",
                "type": "number"
              },
              "requiredStatusCheckContexts": {
                "description": "List of required status check contexts that must pass for commits to be accepted to matching branches.",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "requiresCodeOwnerReviews": {
                "description": "Are reviews from code owners required to update matching branches.",
                "type": "boolean"
              },
              "requiresCommitSignatures": {
                "description": "Are commits required to be signed.",
                "type": "boolean"
              },
              "requiresStatusChecks": {
                "description": "Are status checks required to update matching branches.",
                "type": "boolean"
              },
              "requiresStrictStatusChecks": {
                "description": "Are branches required to be up to date before merging.",
                "type": "boolean"
              },
              "restrictsPushes": {
                "description": "Is pushing to matching branches restricted.",
                "type": "boolean"
              },
              "restrictsReviewDismissals": {
                "description": "Is dismissal of pull request reviews restricted.",
                "type": "boolean"
              }
            }
          }
        },
        "permissionRules": {
          "description": "List of explicit permissions to add (additive only)",
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "team": {
                "description": "Team slug to provide access.",
                "type": "string"
              },
              "permission": {
                "description": "Permission to provide the team.  Can be one of (pull|push|admin)",
                "type": "string",
                "enum": ["pull", "push", "admin"]
              }
            },
            "required": ["team", "permission"]
          }
        }
      }
    }
  }
}

我正在尝试创建一个可重复使用的 repoConfig 架构,它也可以在我的 json 文档的根目录中表示。我很挑剔,并关闭了additionalProperties 设置,只是为了让100% 一切都按预期工作。当我尝试验证此文档时:

{
   "rebaseMergeAllowed": false,
   "branchProtectionRules": [
      {
         "requiresCodeOwnerReviews": true,
         "requiredStatusCheckContexts": [
            "check1",
            "check2"
         ]
      }
   ],
   "permissionRules": [
      {
         "team": "team1",
         "permission": "push"
      }
   ]
}

我在验证期间从ajv npm 模块收到以下错误:

[
  {
    instancePath: '',
    schemaPath: '#/additionalProperties',
    keyword: 'additionalProperties',
    params: { additionalProperty: 'rebaseMergeAllowed' },
    message: 'must NOT have additional properties'
  }
]

如果我采用共享 repoConfig 对象中定义的 properties 集合并将它们直接内联到我的架构文档的根目录中,验证器将按预期工作。

【问题讨论】:

  • 是否愿意将答案标记为已接受?

标签: json jsonschema ajv


【解决方案1】:

虽然 Ether 的回答是正确的,但您实际上在这里有一个 XY problem

(我认为ajv实际上允许$refdefinitions在根级别。这样做的合法性是有争议和不清楚的。)

您的问题在于您对additionalProperties 的使用,因为它无法“透视”应用程序,例如$ref

使用“additionalProperties”进行验证仅适用于孩子 与“属性”中的任何名称都不匹配的实例名称的值, 并且不匹配“patternProperties”中的任何正则表达式。

https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.6

简单来说,propertiespatternProperties 在同一架构对象中additionalProperties

如果您需要继续使用 JSON Schema 的 Draft-07,则需要在同一级别重新定义 properties(您可以给它们赋值 true)。

如果您可以迁移到更新版本的 JSON Schema,您可以使用unevaluatedProperties,简单来说,可以“透视”应用程序关键字。它有点复杂,但它会按照您的预期行事。

【讨论】:

    【解决方案2】:

    在草案 7 和更早版本中,您不能将 $ref 与任何其他关键字结合使用。为了解决这个问题,您可以将 $ref 包装在 allOf 中:

    "allOf": [ { "$ref": "#/definitions/repoConfig" } ],
    ... rest of your schema...
    

    【讨论】:

    • 感谢您的建议!可悲的是,即使在这样做之后,我也会遇到同样的错误。我开始怀疑这是否是 ajv 中的错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-06
    • 1970-01-01
    • 2022-01-23
    • 2015-05-10
    • 2021-06-07
    相关资源
    最近更新 更多