vacuum icon indicating copy to clipboard operation
vacuum copied to clipboard

False positive validation using .spectral ruleset

Open tina-junold opened this issue 1 year ago • 2 comments

Given is the following openapi.yml

openapi: 3.0.3
info:
  title: Chat Gateway
  description: A HTTP Gateway to the grpc chat service.
  version: draft
  license:
    name: UNLICENSED
    url: https://www.company.com
  contact:
    name: Company Inc.
    email: [email protected]
    url: https://www.company.com

servers:
  - url: https://localhost:5000
    description: Local Development Server

tags:
  - name: authenticate
    description: Authentication request
  - name: chat
    description: Chat service related requests

paths:
  /login:
    post:
      operationId: login
      description: Login to the chat server
      summary: To use the chat server, you have to login.
      security: []
      tags:
        - authenticate
      requestBody:
        description: The login request body.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
            example:
              name: client.1
      responses:
        '200':
          description: Successful login
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
              example:
                clientID: 4b84bbfc-e6ee-4e8b-a391-695b07b18416
                token: 20ca572a-6797-4c9e-b119-680d780f6738
        '400':
          $ref: '#/components/responses/400'
        '500':
          $ref: '#/components/responses/500'
  /clients:
    get:
      operationId: clients
      description: Get a list of current clients
      summary: This returns a list of current connected clients.
      security:
        - bearerAuth: []
      tags:
        - chat
      responses:
        '200':
          description: Successful client list request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientsResponse'
              example:
                clients:
                  - name: client.1
                    clientID: 4b84bbfc-e6ee-4e8b-a391-695b07b18416
        '400':
          $ref: '#/components/responses/400'
        '500':
          $ref: '#/components/responses/500'
  /messages:
    get:
      operationId: messages
      description: Get a list of received messages
      summary: This returns all received but not read messages.
      security:
        - bearerAuth: [ ]
      tags:
        - chat
      responses:
        '200':
          description: Successful message list request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessagesResponse'
              example:
                messages:
                  - message: "Hello from client.1"
                    clientID: 4b84bbfc-e6ee-4e8b-a391-695b07b18416
        '400':
          $ref: '#/components/responses/400'
        '500':
          $ref: '#/components/responses/500'
  /send:
    post:
      operationId: send
      description: Send a message
      summary: This allows to send a message through the chat server to all connected clients.
      security:
        - bearerAuth: []
      tags:
        - chat
      requestBody:
        description: The message request body.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendRequest'
            example:
              message: "Hello @chat"
      responses:
        '204':
          description: Successful send message
        '400':
          $ref: '#/components/responses/400'
        '500':
          $ref: '#/components/responses/500'
components:
  securitySchemes:
    bearerAuth:
      description: Authentication via token. Use the /login request to obtain the token.
      type: http
      scheme: bearer

  schemas:
    ErrorCode:
      description: The error code.
      type: integer
      example: 123
    ErrorMessage:
      description: The error message. Use only for internal evaluation.
      type: string
      example: validation error
    ErrorRelate:
      description: Describes a field or parameter this error belongs to. Can be null.
      type: string
      nullable: true
      example: custom.field
    ErrorDetail:
      type: object
      description: contains some detailed error information.
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          $ref: '#/components/schemas/ErrorMessage'
        relate:
          $ref: '#/components/schemas/ErrorRelate'
      required:
        - code
        - message
        - relate
      example:
        code: 123
        message: validation error
        relate: custom.field
    ErrorDetails:
      description: A list with error details.
      type: array
      items:
        $ref: '#/components/schemas/ErrorDetail'
      example:
        - code: 123
          message: validation error
          relate: custom.field
    ErrorResponseDetails:
      type: object
      description: A detailed error response.
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          $ref: '#/components/schemas/ErrorMessage'
        error-details:
          $ref: '#/components/schemas/ErrorDetails'
      required:
        - code
        - message
        - error-details
      example:
        code: 123
        message: validation error
        error-details:
          - code: 456
            message: specific validation error
            relate: custom.field
    ErrorResponseMinimal:
      description: A minimal error response.
      type: object
      properties:
        message:
          $ref: '#/components/schemas/ErrorMessage'
      required:
        - message
      example:
        message: an error occurred

    Token:
      description: An auth token
      type: string
      format: uuid
      example: 20ca572a-6797-4c9e-b119-680d780f6738
      x-oapi-codegen-extra-tags:
        validate: required

    ClientName:
      description: A client name
      type: string
      example: client.1
      x-oapi-codegen-extra-tags:
        validate: required

    ClientID:
      description: A client id
      type: string
      format: uuid
      example: 4b84bbfc-e6ee-4e8b-a391-695b07b18416
      x-oapi-codegen-extra-tags:
        validate: required

    Client:
      description: A client
      properties:
        name:
          $ref: '#/components/schemas/ClientName'
        clientID:
          $ref: '#/components/schemas/ClientID'
      required:
        - name
        - clientID

    Message:
      description: A message
      properties:
        message:
          description: The message
          type: string
          example: "Hello World"
          x-oapi-codegen-extra-tags:
            validate: required
        clientID:
          $ref: '#/components/schemas/ClientID'
      required:
        - message
        - clientID

    LoginRequest:
      description: The login request
      properties:
        name:
          $ref: '#/components/schemas/ClientName'
      required:
        - name

    LoginResponse:
      description: The login response
      properties:
        clientID:
          $ref: "#/components/schemas/ClientID"
        token:
          $ref: "#/components/schemas/Token"
      required:
        - clientID
        - token

    ClientsResponse:
      description: The clients response
      properties:
        clients:
          description: The clients
          type: array
          items:
            $ref: '#/components/schemas/Client'
          example:
            - name: client.1
              clientID: 4b84bbfc-e6ee-4e8b-a391-695b07b18416
            - name: client.2
              clientID: 2fb0def5-1c64-42a2-9c98-58c0fa6a3313
          x-oapi-codegen-extra-tags:
            validate: required
      required:
        - clients

    MessagesResponse:
      description: The messages response
      properties:
        messages:
          description: The messages
          type: array
          items:
            $ref: '#/components/schemas/Message'
          example:
            - message:  "Hello from client.1"
              clientID: 4b84bbfc-e6ee-4e8b-a391-695b07b18416
            - message: "Hello back from client.2"
              clientID: 2fb0def5-1c64-42a2-9c98-58c0fa6a3313
          x-oapi-codegen-extra-tags:
            validate: required
      required:
        - messages

    SendRequest:
      description: The send request
      properties:
        message:
          type: string
          example: "Hello @chat"
          x-oapi-codegen-extra-tags:
            validate: required
      required:
        - message

  responses:
    '400':
      description: An error response.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponseDetails'
          examples:
            errorResponse:
              $ref: '#/components/examples/ErrorResponse'
    '500':
      description: A bad request response.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponseMinimal'
          examples:
            basicErrorResponse:
              $ref: '#/components/examples/BasicErrorResponse'

  examples:
    ErrorResponse:
      description: An error response example.
      value:
        code: 123
        message: validation error
        error-details:
          - code: 456
            message: specific validation error
            relate: custom.field
    BasicErrorResponse:
      description: A basic error response example.
      value:
        message: an error occurred

and the .spectral.yml ruleset:

---
extends:
  - [spectral:oas, all]

If i lint this, i got the message:

------------------------------------------------
Location        | Severity | Message                                                                             | Rule                  | Category   | Path
openapi.yml:0:0 | warning  | 'postResponseSuccess' function has invalid options supplied. Example valid optio... | post-response-success | Operations | $.paths.*.post.responses

This is imho a bug since POST /send contains a valid 204 response.

tina-junold avatar Dec 16 '24 11:12 tina-junold

i tried to reproduce your issue and found that

  • if you are leveraging the Doctor online the issue does not appear you have 100% score 🎉
  • if you use the command line vacuum generate-ruleset all my-ruleset and then use it , it is also not triggering the issue

the issue is triggerd only when you use the ruleset you mentionned extends: [[spectral:oas, all]]

so there is kind of special case when using this model vs the others even if the rules is 100% the same

notice that the Location 0:0 is suspicious as usually vacuum maintains a precise location for such error, a deep dive is required🐟

LasneF avatar Dec 16 '24 17:12 LasneF

I believe this is a duplicate of (or a symptom of) #624.

AtomicTroop avatar Feb 24 '25 14:02 AtomicTroop

Hi,

The fix for this was committed: April 25, 2025 (commit 3234b54) Released: v0.16.6 (April 27, 2025) Fixed in: model/utils.go lines 71-73

daveshanley avatar Nov 07 '25 15:11 daveshanley