pb33f / openapi-changes

The world's sexiest OpenAPI breaking changes detector. Discover what changed between two OpenAPI specs, or a single spec over time. Supports OpenAPI 3.1, 3.0 and Swagger
https://pb33f.io/openapi-changes/
Other
180 stars 16 forks source link

Deadlock Issue with Goroutines in openapi-changes Tool When Comparing OpenAPI Specifications #113

Closed clement-is closed 6 months ago

clement-is commented 7 months ago

Hello,

First of all, thank you for your project. 🀠 I've encountered an issue with the openapi-changes tool when trying to compare two OpenAPI specifications. Specifically, when I run the comparison with npx, I encounter a problem related to goroutines, which leads to a deadlock error. This issue also manifests in my GitLab CI pipeline, presenting the same error in the logs.


@@@@@@@   @@@@@@@   @@@@@@   @@@@@@   @@@@@@@@
@@@@@@@@  @@@@@@@@  @@@@@@@  @@@@@@@  @@@@@@@@
@@!  @@@  @@!  @@@      @@@      @@@  @@!
!@!  @!@  !@   @!@      @!@      @!@  !@!
@!@@!@!   @!@!@!@   @!@!!@   @!@!!@   @!!!:!
!!@!!!    !!!@!!!!  !!@!@!   !!@!@!   !!!!!:
!!:       !!:  !!!      !!:      !!:  !!:
:!:       :!:  !:!      :!:      :!:  :!:
 ::        :: ::::  :: ::::  :: ::::   ::
 :        :: : ::    : : :    : : :    :

openapi-changes version: 0.0.55 | compiled: Mon, 26 Feb 2024 21:16:51 UTC

β–€  Building original model for commit b5a4cb
  SPEC   extracted 2 commits from history                                                                                                            
└─┬Paths
  β”œβ”€β”€[-] path (19:3)❌ 
  β”œβ”€β”€[-] path (48:3)❌ 
  β”œβ”€β”€[+] path (19:3)
  └──[+] path (48:3)

Date: 03/06/24 | Commit: New: tmp/openapi.yaml, Original: oas/cats.yaml
Document Element | Total Changes | Breaking Changes
paths            | 4             | 2

❌  2 Breaking changes out of 4
 INFO  Removals: 2
 INFO  Additions: 2
 INFO  Breaking Removals: 2
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
github.com/pb33f/openapi-changes/cmd.GetSummaryCommand.func1(0x40002f0608, {0x40002a05e0, 0x2, 0x887a84?})
        D:/a/openapi-changes/openapi-changes/cmd/summary.go:229 +0x744
github.com/spf13/cobra.(*Command).execute(0x40002f0608, {0x40002a0580, 0x2, 0x2})
        C:/Users/runneradmin/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:983 +0x840
github.com/spf13/cobra.(*Command).ExecuteC(0x128d4c0)
        C:/Users/runneradmin/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1115 +0x344
github.com/spf13/cobra.(*Command).Execute(...)
        C:/Users/runneradmin/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1039
github.com/pb33f/openapi-changes/cmd.Execute({0xc2682c?, 0x19?}, {0xc30c40?, 0x8962a8?}, {0x400029e640?, 0x40000021c0?})
        D:/a/openapi-changes/openapi-changes/cmd/root.go:51 +0xa0
main.main()
        D:/a/openapi-changes/openapi-changes/openapi-changes.go:29 +0x184

goroutine 17 [select]:
github.com/pb33f/openapi-changes/cmd.GetSummaryCommand.func1.1(0x40002fc060, 0x40002fc0c0)
        D:/a/openapi-changes/openapi-changes/cmd/summary.go:85 +0x390
created by github.com/pb33f/openapi-changes/cmd.GetSummaryCommand.func1 in goroutine 1
        D:/a/openapi-changes/openapi-changes/cmd/summary.go:212 +0x6cc

🧐 Steps to Reproduce: Use the following Dockerfile to set up the environment and replicate the issue locally:

FROM node:20.11
WORKDIR /app
COPY . . 
CMD ["bash", "-c", "npx @pb33f/openapi-changes summary openapi.yaml tmp/openapi.yaml"]
# (docker build --no-cache -t oas-changes . && docker run -it --attach STDOUT --attach STDERR oas-changes)

Additional Information:

This deadlock issue prevents successful comparison of OpenAPI specifications and affects the integration in CI pipelines. Any insights or fixes for this problem would be greatly appreciated.

Thank you!

daveshanley commented 7 months ago

Oh dear, this is a bug for sure. I can track it down without the specs, but it would be most helpful if you could provide me with a reproducible left and right spec?

clement-is commented 7 months ago

For sure, thank you for your prompt reply ! πŸ’¨

πŸ‘ˆ Left spec:

openapi: 3.1.0
info:
  version: 1.0.0
  title: Cat example
  description: Cat API
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
  contact:
    name: Toto
    url: https://www.toto.com
    email: toto@toto.com
servers:
  - url: toto:8080
externalDocs:
  description: API Documentation
  url: https://openweathermap.org/api
paths:
  /kubernetes/facts:
    get:
      operationId: ReadFacts
      description: get all the facts
      summary: This endpoint is protected
      security:
        - BearerAuth:
            - dog_scope:read
      responses:
        '200':
          $ref: '#/components/responses/CatFactsResponse'
        '400':
          $ref: '#/components/responses/BadRequestResponse'
        default:
          $ref: '#/components/responses/ErrorResponse'
    post:
      operationId: CreateFact
      description: create a fact
      summary: This endpoint is protected
      security:
        - BearerAuth:
            - dog_scope:create
      responses:
        '200':
          $ref: '#/components/responses/CatFactsResponse'
        '400':
          $ref: '#/components/responses/BadRequestResponse'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /toto/health:
    get:
      operationId: GetHealth
      description: check the health of the service
      summary: This endpoint is open
      responses:
        '200':
          description: Get the health check
          content:
            application/json:
              schema:
                properties:
                  status:
                    type: string
                    enum:
                      - HEALTHY
                      - UNHEALTHY
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |-
        With this authentication scheme, you must specify the following headers in your API request:<br />
          * `Authorization: Bearer XXXX`, where `XXXX` is your token provided by dedicated /token endpoint.
    OpenID:
      type: openIdConnect
      openIdConnectUrl: https://example.com/.well-known/openid-configuration
  schemas:
    CatFacts:
      type: object
      properties:
        message:
          type: string
        status:
          type: string
    ErrorDocumentationUrl:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: ErrorDocumentationUrl
      type: string
      additionalProperties: false
      description: Documentation URL for the domain error
      format: uri
      enum:
        - https://docs.toto.cloud/docs/domains/cloud/errors#unauthenticated_access
        - https://docs.toto.cloud/docs/domains/cloud/errors#forbidden_access
        - https://docs.toto.cloud/docs/domains/cloud/errors#invalid_parameter
        - https://docs.toto.cloud/docs/domains/cloud/errors#resource_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#duplicate_resource
        - https://docs.toto.cloud/docs/domains/cloud/errors#internal_server_error
        - https://docs.toto.cloud/docs/domains/cloud/errors#ambiguous_granular_permission_elements
        - https://docs.toto.cloud/docs/domains/cloud/errors#ambiguous_permission_elements
        - https://docs.toto.cloud/docs/domains/cloud/errors#ambiguous_role_elements
        - https://docs.toto.cloud/docs/domains/cloud/errors#duplicate_role
        - https://docs.toto.cloud/docs/domains/cloud/errors#forbidden
        - https://docs.toto.cloud/docs/domains/cloud/errors#identity_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#inactive_token
        - https://docs.toto.cloud/docs/domains/cloud/errors#missing_roles
        - https://docs.toto.cloud/docs/domains/cloud/errors#namespace_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#not_in_tenant_roles
        - https://docs.toto.cloud/docs/domains/cloud/errors#permission_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#role_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#unexpected_token_usage
    Url:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: Url
      type: string
      format: uri
      example: https://domain.org/path/
    Error:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: Error
      type: object
      additionalProperties: false
      description: For HTTP errors, we implement the https://datatracker.ietf.org/doc/html/rfc9457
      required:
        - type
        - title
      properties:
        type:
          $ref: '#/components/schemas/ErrorDocumentationUrl'
        title:
          description: Human-readable summary of the problem type.
          type: string
        detail:
          description: Human-readable explanation specific to this occurrence of the problem.
          type: string
        instance:
          description: Url to fetch more information about this problem type.
          $ref: '#/components/schemas/Url'
      examples:
        - type: https://docs.toto.cloud/docs/domains/cloud/errors#unauthenticated_access
          title: You do not have enough credit.
          detail: Your current balance is 30, but that costs 50.
          instance: /account/12345/msgs/abc
          balance: 30
          accounts:
            - /account/12345
            - /account/67890
    Violation:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: Violation
      type: object
      properties:
        field:
          description: The field impacted by the violation.
          type: string
        description:
          description: A description of why the field is violated.
          type: string
      required:
        - field
        - description
    BadRequestError:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: BadRequestError
      type: object
      additionalProperties: false
      description: For HTTP 400 bad request errors, we implement the https://datatracker.ietf.org/doc/html/rfc9457
      allOf:
        - $ref: '#/components/schemas/Error'
        - type: object
          properties:
            violations:
              description: Array of violations to provide a per-field detail.
              type: array
              items:
                $ref: '#/components/schemas/Violation'
      $def:
        Violation:
          $schema: https://json-schema.org/draft/2020-12/schema
          title: Violation
          type: object
          properties:
            field:
              description: The field impacted by the violation.
              type: string
            description:
              description: A description of why the field is violated.
              type: string
          required:
            - field
            - description
  responses:
    ErrorResponse:
      description: Error Response
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Error'
    BadRequestResponse:
      description: Bad Request Response
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/BadRequestError'
    CatFactsResponse:
      description: An object listing cats facts
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CatFacts'

πŸ‘‰ Right spec:

openapi: 3.1.0
info:
  version: 1.0.0
  title: Cat example
  description: Cat API
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
  contact:
    name: Toto
    url: https://www.toto.com
    email: toto@toto.com
servers:
  - url: toto:8080
externalDocs:
  description: API Documentation
  url: https://openweathermap.org/api
paths:
  /kubernetes/facts:
    get:
      operationId: ReadFacts
      description: get all the facts
      summary: This endpoint is protected
      security:
        - BearerAuth:
            - dog_scope:read
      responses:
        '200':
          $ref: '#/components/responses/CatFactsResponse'
        '400':
          $ref: '#/components/responses/BadRequestResponse'
        default:
          $ref: '#/components/responses/ErrorResponse'
    post:
      operationId: CreateFact
      description: create a fact
      summary: This endpoint is protected
      security:
        - BearerAuth:
            - dog_scope:create
      responses:
        '200':
          $ref: '#/components/responses/CatFactsResponse'
        '400':
          $ref: '#/components/responses/BadRequestResponse'
        default:
          $ref: '#/components/responses/ErrorResponse'
  /kubernetes/health:
    get:
      operationId: GetHealth
      description: check the health of the service
      summary: This endpoint is open
      responses:
        '200':
          description: Get the health check
          content:
            application/json:
              schema:
                properties:
                  status:
                    type: string
                    enum:
                      - HEALTHY
                      - UNHEALTHY
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |-
        With this authentication scheme, you must specify the following headers in your API request:<br />
          * `Authorization: Bearer XXXX`, where `XXXX` is your token provided by dedicated /token endpoint.
    OpenID:
      type: openIdConnect
      openIdConnectUrl: https://example.com/.well-known/openid-configuration
  schemas:
    CatFacts:
      type: object
      properties:
        message:
          type: string
        status:
          type: string
    ErrorDocumentationUrl:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: ErrorDocumentationUrl
      type: string
      additionalProperties: false
      description: Documentation URL for the domain error
      format: uri
      enum:
        - https://docs.toto.cloud/docs/domains/cloud/errors#unauthenticated_access
        - https://docs.toto.cloud/docs/domains/cloud/errors#forbidden_access
        - https://docs.toto.cloud/docs/domains/cloud/errors#invalid_parameter
        - https://docs.toto.cloud/docs/domains/cloud/errors#resource_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#duplicate_resource
        - https://docs.toto.cloud/docs/domains/cloud/errors#internal_server_error
        - https://docs.toto.cloud/docs/domains/cloud/errors#ambiguous_granular_permission_elements
        - https://docs.toto.cloud/docs/domains/cloud/errors#ambiguous_permission_elements
        - https://docs.toto.cloud/docs/domains/cloud/errors#ambiguous_role_elements
        - https://docs.toto.cloud/docs/domains/cloud/errors#duplicate_role
        - https://docs.toto.cloud/docs/domains/cloud/errors#forbidden
        - https://docs.toto.cloud/docs/domains/cloud/errors#identity_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#inactive_token
        - https://docs.toto.cloud/docs/domains/cloud/errors#missing_roles
        - https://docs.toto.cloud/docs/domains/cloud/errors#namespace_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#not_in_tenant_roles
        - https://docs.toto.cloud/docs/domains/cloud/errors#permission_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#role_not_found
        - https://docs.toto.cloud/docs/domains/cloud/errors#unexpected_token_usage
    Url:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: Url
      type: string
      format: uri
      example: https://domain.org/path/
    Error:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: Error
      type: object
      additionalProperties: false
      description: For HTTP errors, we implement the https://datatracker.ietf.org/doc/html/rfc9457
      required:
        - type
        - title
      properties:
        type:
          $ref: '#/components/schemas/ErrorDocumentationUrl'
        title:
          description: Human-readable summary of the problem type.
          type: string
        detail:
          description: Human-readable explanation specific to this occurrence of the problem.
          type: string
        instance:
          description: Url to fetch more information about this problem type.
          $ref: '#/components/schemas/Url'
      examples:
        - type: https://docs.toto.cloud/docs/domains/cloud/errors#unauthenticated_access
          title: You do not have enough credit.
          detail: Your current balance is 30, but that costs 50.
          instance: /account/12345/msgs/abc
          balance: 30
          accounts:
            - /account/12345
            - /account/67890
    Violation:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: Violation
      type: object
      properties:
        field:
          description: The field impacted by the violation.
          type: string
        description:
          description: A description of why the field is violated.
          type: string
      required:
        - field
        - description
    BadRequestError:
      $schema: https://json-schema.org/draft/2020-12/schema
      title: BadRequestError
      type: object
      additionalProperties: false
      description: For HTTP 400 bad request errors, we implement the https://datatracker.ietf.org/doc/html/rfc9457
      allOf:
        - $ref: '#/components/schemas/Error'
        - type: object
          properties:
            violations:
              description: Array of violations to provide a per-field detail.
              type: array
              items:
                $ref: '#/components/schemas/Violation'
      $def:
        Violation:
          $schema: https://json-schema.org/draft/2020-12/schema
          title: Violation
          type: object
          properties:
            field:
              description: The field impacted by the violation.
              type: string
            description:
              description: A description of why the field is violated.
              type: string
          required:
            - field
            - description
  responses:
    ErrorResponse:
      description: Error Response
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Error'
    BadRequestResponse:
      description: Bad Request Response
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/BadRequestError'
    CatFactsResponse:
      description: An object listing cats facts
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CatFacts'

I only changed the endpoint path from: /toto/health to /kubernetes/health Note that when there's no breaking change, there's nothing to worry about. 🐱

krystian-jedrzejowski-zazoon commented 7 months ago

I also have same issue

LasneF commented 7 months ago

same here too

daveshanley commented 7 months ago

I'll bump this issue to the top of my queue as soon as I'm back from vacation.

I'm in the middle of the Caribbean Sea at the moment and I have no laptop.

daveshanley commented 6 months ago

This has been resolved in v0.0.56.