Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error message is not accurate with oneOf #1048

Open
avishayt opened this issue Jan 5, 2025 · 2 comments
Open

Error message is not accurate with oneOf #1048

avishayt opened this issue Jan 5, 2025 · 2 comments

Comments

@avishayt
Copy link

avishayt commented Jan 5, 2025

Hello,
I have the following API definition (full yaml here):

    ConfigProviderSpec:
      oneOf:
        - $ref: "#/components/schemas/GitConfigProviderSpec"
        - $ref: "#/components/schemas/KubernetesSecretProviderSpec"
        - $ref: "#/components/schemas/InlineConfigProviderSpec"
        - $ref: "#/components/schemas/HttpConfigProviderSpec"
    GitConfigProviderSpec:
      type: object
      properties:
        name:
          type: string
          description: The name of the config provider.
        gitRef:
          type: object
          description: The reference to a Git configuration server.
          properties:
            repository:
              type: string
              description: The name of the Repository resource.
            targetRevision:
              type: string
              description: The revision to use from the Repository.
            path:
              type: string
              description: The path to the config in the Repository.
            mountPath:
              type: string
              description: Path in the device's file system at which the repository's path should be mounted.
              default: "/"
          required:
            - repository
            - targetRevision
            - path
      required:
      - name
      - gitRef
    KubernetesSecretProviderSpec:
      type: object
      properties:
        name:
          type: string
          description: The name of the config provider.
        secretRef:
          type: object
          description: The reference to a Kubernetes secret.
          properties:
            name:
              type: string
              description: The name of the secret.
            namespace:
              type: string
              description: The namespace of the secret.
            mountPath:
              type: string
              description: Path in the device's file system at which the secret should be mounted.
          required:
            - name
            - namespace
            - mountPath
      required:
      - name
      - secretRef
    InlineConfigProviderSpec:
      type: object
      properties:
        name:
          type: string
          description: The name of the config provider.
        inline:
          type: array
          description: A list of files to create on the device.
          items:
            $ref: '#/components/schemas/FileSpec'
      required:
      - name
      - inline
    FileSpec:
      type: object
      properties:
        path:
          type: string
          description: The absolute path to the file on the device. Note that any existing file will be overwritten.
        content:
          type: string
          description: The plain text (UTF-8) or base64-encoded content of the file.
        contentEncoding:
          type: string
          description: How the contents are encoded. Must be either "plain" or "base64". Defaults to "plain".
          enum:
          - plain
          - base64
        mode:
          type: integer
          description: The file's permission mode. You may specify the more familiar octal with a leading zero (e.g., 0644) or as a decimal without a leading zero (e.g., 420). Setuid/setgid/sticky bits are supported. If not specified, the permission mode for files defaults to 0644.
        user:
          type: string
          description: The file's owner, specified either as a name or numeric ID. Defaults to "root".
        group:
          type: string
          description: The file's group, specified either as a name or numeric ID. Defaults to "root".
      required:
      - path
      - content
    HttpConfigProviderSpec:
      type: object
      properties:
        name:
          type: string
          description: The name of the config provider.
        httpRef:
          type: object
          description: The reference to an HTTP configuration server.
          properties:
            repository:
              type: string
              description: The name of the repository resource to use as the sync source.
            suffix:
              type: string
              description: 'Part of the URL that comes after the base URL. It can include query parameters such as: "/path/to/endpoint?query=param".'
            filePath:
              type: string
              description: Path in the device's file system to which the content returned by the HTTP sever should be written.
          required:
          - repository
          - filePath
      required:
      - name
      - httpRef

I am trying to pass the following invalid configuration:
{"apiVersion":"v1alpha1","kind":"Device","metadata":{"labels":{"fleet":"fleet-b"},"name":"fab9839018890a88b898b980f8f809f8e8ac333761977d987a777a777a987c"},"spec":{"config":[{"inline":[{"mode":511,"path":"/etc/motd"}],"name":"motd"}]}}

This configuration uses InlineConfigProviderSpec for oneOf in this case. It is invalid because FileSpec requires a "content" property, which is missing here.

This is correctly identified as an invalid configuration, but the error message missed the reason - it complains that it's missing "gitRef", "secretRef", "content", and "httpRef" - while only "content" is relevant:

API Error: Error at "/spec/config/0/gitRef": property "gitRef" is missing
Schema:
  {
    "properties": {
      "gitRef": {
        "description": "The reference to a Git configuration server.",
        "properties": {
          "mountPath": {
            "default": "/",
            "description": "Path in the device's file system at which the repository's path should be mounted.",
            "type": "string"
          },
          "path": {
            "description": "The path to the config in the Repository.",
            "type": "string"
          },
          "repository": {
            "description": "The name of the Repository resource.",
            "type": "string"
          },
          "targetRevision": {
            "description": "The revision to use from the Repository.",
            "type": "string"
          }
        },
        "required": [
          "repository",
          "targetRevision",
          "path"
        ],
        "type": "object"
      },
      "name": {
        "description": "The name of the config provider.",
        "type": "string"
      }
    },
    "required": [
      "name",
      "gitRef"
    ],
    "type": "object"
  }

Value:
  {
    "inline": [
      {
        "mode": 511,
        "path": "/etc/motd"
      }
    ],
    "name": "motd"
  }
 | Error at "/spec/config/0/secretRef": property "secretRef" is missing
Schema:
  {
    "properties": {
      "name": {
        "description": "The name of the config provider.",
        "type": "string"
      },
      "secretRef": {
        "description": "The reference to a Kubernetes secret.",
        "properties": {
          "mountPath": {
            "description": "Path in the device's file system at which the secret should be mounted.",
            "type": "string"
          },
          "name": {
            "description": "The name of the secret.",
            "type": "string"
          },
          "namespace": {
            "description": "The namespace of the secret.",
            "type": "string"
          }
        },
        "required": [
          "name",
          "namespace",
          "mountPath"
        ],
        "type": "object"
      }
    },
    "required": [
      "name",
      "secretRef"
    ],
    "type": "object"
  }

Value:
  {
    "inline": [
      {
        "mode": 511,
        "path": "/etc/motd"
      }
    ],
    "name": "motd"
  }
 | Error at "/spec/config/0/inline/0/content": property "content" is missing
Schema:
  {
    "properties": {
      "content": {
        "description": "The plain text (UTF-8) or base64-encoded content of the file.",
        "type": "string"
      },
      "contentEncoding": {
        "description": "How the contents are encoded. Must be either \"plain\" or \"base64\". Defaults to \"plain\".",
        "enum": [
          "plain",
          "base64"
        ],
        "type": "string"
      },
      "group": {
        "description": "The file's group, specified either as a name or numeric ID. Defaults to \"root\".",
        "type": "string"
      },
      "mode": {
        "description": "The file's permission mode. You may specify the more familiar octal with a leading zero (e.g., 0644) or as a decimal without a leading zero (e.g., 420). Setuid/setgid/sticky bits are supported. If not specified, the permission mode for files defaults to 0644.",
        "type": "integer"
      },
      "path": {
        "description": "The absolute path to the file on the device. Note that any existing file will be overwritten.",
        "type": "string"
      },
      "user": {
        "description": "The file's owner, specified either as a name or numeric ID. Defaults to \"root\".",
        "type": "string"
      }
    },
    "required": [
      "path",
      "content"
    ],
    "type": "object"
  }

Value:
  {
    "mode": 511,
    "path": "/etc/motd"
  }
 | Error at "/spec/config/0/httpRef": property "httpRef" is missing
Schema:
  {
    "properties": {
      "httpRef": {
        "description": "The reference to an HTTP configuration server.",
        "properties": {
          "filePath": {
            "description": "Path in the device's file system to which the content returned by the HTTP sever should be written.",
            "type": "string"
          },
          "repository": {
            "description": "The name of the repository resource to use as the sync source.",
            "type": "string"
          },
          "suffix": {
            "description": "Part of the URL that comes after the base URL. It can include query parameters such as: \"/path/to/endpoint?query=param\".",
            "type": "string"
          }
        },
        "required": [
          "repository",
          "filePath"
        ],
        "type": "object"
      },
      "name": {
        "description": "The name of the config provider.",
        "type": "string"
      }
    },
    "required": [
      "name",
      "httpRef"
    ],
    "type": "object"
  }

Value:
  {
    "inline": [
      {
        "mode": 511,
        "path": "/etc/motd"
      }
    ],
    "name": "motd"
  }

Thank you for your awesome library and for your help.

@avishayt
Copy link
Author

avishayt commented Jan 5, 2025

Tested with v0.127.0

@avishayt
Copy link
Author

I managed to work around it using a custom error handler, but am wondering if you consider this a bug that should be fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant