documentationUrl: https://spec.openlint.org/
rules:
  openapi-document-cache-control-parameter:
    description: 'Cache usage SHOULD be extensively detailed in the `description` property to avoid data leaks or the usage
      of stale data. This rule should ensure in some way that the api provider documented extensively the cache usage to avoid
      data leaks or usage of stale data. For now this ruleset tests: * the presence of following keywords in the `description`:
      `max-age`, `private`, `no-store`, `no-cache`. * that one and only one between Expires and Cache-Control is used. `Cache-Control`
      and `Expires` should not be used in conjuction, because `Cache-Control` overrides `Expires` when `max-age` is set. Instead
      if neither `Cache-Control` or `Expires` are set, clients MAY use euristic cache like described in RFC7234.'
    message: Cache usage SHOULD be documented when used.
    severity: info
    given: $..[parameters][?(@.in == "header" && @.name.match(/Cache-Control/i))]
    then:
    - field: description
      function: truthy
    - field: description
      function: pattern
      functionOptions:
        match: .*(max-age|private|no-store|no-cache).*
    formats:
    - oas3
    documentationUrl: https://apicommons.org/rules/#openapi-document-cache-control-parameter
  openapi-document-cache-response-header:
    description: 'Cache usage SHOULD be extensively detailed in the `description` property to avoid data leaks or the usage
      of stale data. This rule should ensure in some way that the api provider documented extensively the cache usage to avoid
      data leaks or usage of stale data. For now this ruleset tests: * the presence of following keywords in the `description`:
      `max-age`, `private`, `no-store`, `no-cache`. * that one and only one between Expires and Cache-Control is used. `Cache-Control`
      and `Expires` should not be used in conjuction, because `Cache-Control` overrides `Expires` when `max-age` is set. Instead
      if neither `Cache-Control` or `Expires` are set, clients MAY use euristic cache like described in RFC7234.'
    message: Cache usage in responses SHOULD be documented in Cache-Control and/or Expires. {{error}}
    severity: info
    given: $.[responses][?(@property[0] == "2" )][headers].[?(@property.match(/Cache-Control|Expires/i))]]
    then:
    - field: description
      function: truthy
    - field: description
      function: pattern
      functionOptions:
        match: .*(max-age|private|no-store|no-cache).*
    formats:
    - oas3
    documentationUrl: https://apicommons.org/rules/#openapi-document-cache-response-header
  openapi-operation-collection-support-filtering:
    description: Collection GET operations should support filtering via a filter query parameter (e.g. filter or filter[field]).
    message: Collection should support a filter query parameter.
    given: $.paths[*].get
    severity: info
    then:
      field: parameters
      function: schema
      functionOptions:
        schema:
          type: array
          contains:
            type: object
            required:
            - name
            - in
            properties:
              name:
                pattern: ^filter
              in:
                const: query
    documentationUrl: https://apicommons.org/rules/#openapi-operation-collection-support-filtering
  openapi-operation-collection-support-sorting:
    description: Collection GET operations should support sorting via a sort or order query parameter.
    message: Collection should support a sort/order query parameter.
    given: $.paths[*].get
    severity: info
    then:
      field: parameters
      function: schema
      functionOptions:
        schema:
          type: array
          contains:
            type: object
            required:
            - name
            - in
            properties:
              name:
                pattern: ^(sort|order)
              in:
                const: query
    documentationUrl: https://apicommons.org/rules/#openapi-operation-collection-support-sorting
  openapi-operation-collection-support-sparse-fieldsets:
    description: GET operations should support sparse fieldsets via a fields query parameter so clients can request only the
      fields they need.
    message: Operation should support a fields (sparse fieldset) query parameter.
    given: $.paths[*].get
    severity: info
    then:
      field: parameters
      function: schema
      functionOptions:
        schema:
          type: array
          contains:
            type: object
            required:
            - name
            - in
            properties:
              name:
                pattern: ^fields
              in:
                const: query
    documentationUrl: https://apicommons.org/rules/#openapi-operation-collection-support-sparse-fieldsets
  openapi-operation-define-429-response:
    description: APIs should define a 429 Too Many Requests response to document rate limiting behavior. Analysis shows 429
      appears in 671 operations, confirming rate limiting is a common API pattern.
    message: Operations MUST Have 429 Response
    severity: info
    given: $.paths.*[get,post,put,patch,delete].responses
    then:
      field: '429'
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-operation-define-429-response
  openapi-parameter-collection-limit-param-default:
    description: The limit / page-size query parameter should declare a default so the page size is predictable when the caller
      omits it.
    message: limit parameter should declare a default.
    given: $.paths[*].get.parameters[?(@ && @.in == 'query' && (@.name == 'limit' || @.name == 'per_page' || @.name == 'page_size'
      || @.name == 'pageSize'))].schema
    severity: info
    then:
      field: default
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-parameter-collection-limit-param-default
  openapi-parameter-collection-limit-param-maximum:
    description: The limit / page-size query parameter should declare a maximum so a caller cannot request an unbounded page
      (OWASP API4 — unrestricted resource consumption).
    message: limit parameter should declare a maximum.
    given: $.paths[*].get.parameters[?(@ && @.in == 'query' && (@.name == 'limit' || @.name == 'per_page' || @.name == 'page_size'
      || @.name == 'pageSize'))].schema
    severity: info
    then:
      field: maximum
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-parameter-collection-limit-param-maximum
  openapi-parameter-pagination-params-in-query:
    description: Pagination parameters like page, limit, offset, and cursor should be passed as query parameters, not in headers
      or path segments. Analysis confirms 100% of pagination parameters observed are query parameters.
    message: Pagination Parameters MUST Be Query Parameters
    severity: info
    given: $.paths[*].get.parameters[?(@.name == 'page' || @.name == 'limit' || @.name == 'offset' || @.name == 'cursor' ||
      @.name == 'per_page' || @.name == 'page_size')]
    then:
      field: in
      function: pattern
      functionOptions:
        match: query
    documentationUrl: https://apicommons.org/rules/#openapi-parameter-pagination-params-in-query
  openapi-request-post-collection-require-paging-object:
    formats:
    - oas3
    description: POST collection endpoints MUST have a request body schema that includes paging parameters.
    message: POST collection endpoints MUST have a request body schema that includes paging parameters.
    severity: info
    given: $.paths[?(!@property.match(/.*\/\{[^}]+\}$/))].post.requestBody.content.application/json.schema.properties.paging
    then:
      field: type
      function: pattern
      functionOptions:
        match: object
    documentationUrl: https://apicommons.org/rules/#openapi-request-post-collection-require-paging-object
  openapi-request-post-collection-require-paging-object-oas2:
    formats:
    - oas2
    description: POST collection endpoints MUST have a body-parameter schema that includes paging parameters.
    message: POST collection endpoints MUST have a body-parameter schema that includes paging parameters.
    severity: info
    given: $.paths[?(!@property.match(/.*\/\{[^}]+\}$/))].post.parameters[?(@.in=='body')].schema.properties.paging
    then:
      field: type
      function: pattern
      functionOptions:
        match: object
    documentationUrl: https://apicommons.org/rules/#openapi-request-post-collection-require-paging-object-oas2
  openapi-request-support-accept-encoding:
    description: Operations should accept an Accept-Encoding request header so clients can negotiate a compressed (e.g. gzip)
      response.
    message: Operation should accept an Accept-Encoding header.
    given: $.paths[*][get,post,put,patch,delete]
    severity: info
    then:
      field: parameters
      function: schema
      functionOptions:
        schema:
          type: array
          contains:
            type: object
            required:
            - name
            - in
            properties:
              name:
                const: Accept-Encoding
              in:
                const: header
    documentationUrl: https://apicommons.org/rules/#openapi-request-support-accept-encoding
  openapi-response-202-retry-after:
    description: 202 Accepted responses should document a Retry-After header suggesting how long clients should wait before
      polling the status resource.
    message: 202 Accepted responses should document a Retry-After header.
    given: $.paths[*][*].responses['202'].headers
    severity: info
    then:
      field: Retry-After
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-202-retry-after
  openapi-response-cache-header-no-conflict:
    description: 'Cache usage SHOULD be extensively detailed in the `description` property to avoid data leaks or the usage
      of stale data. This rule should ensure in some way that the api provider documented extensively the cache usage to avoid
      data leaks or usage of stale data. For now this ruleset tests: * the presence of following keywords in the `description`:
      `max-age`, `private`, `no-store`, `no-cache`. * that one and only one between Expires and Cache-Control is used. `Cache-Control`
      and `Expires` should not be used in conjuction, because `Cache-Control` overrides `Expires` when `max-age` is set. Instead
      if neither `Cache-Control` or `Expires` are set, clients MAY use euristic cache like described in RFC7234.'
    message: '{{error}}'
    severity: info
    given: $.[responses][?(@property[0] == "2" )][headers]
    then:
    - function: xor
      functionOptions:
        properties:
        - Expires
        - Cache-Control
    formats:
    - oas3
    documentationUrl: https://apicommons.org/rules/#openapi-response-cache-header-no-conflict
  openapi-response-collection-require-results-array:
    formats:
    - oas3
    description: Response bodies must have a root element called results and is an array of objects.
    message: Response bodies must have a root element called results and is an array of objects.
    severity: info
    given: $.paths[?(!@property.match(/.*\/\{[^}]+\}$/))].get.responses['200'].content.application/json.schema.properties.results
    then:
    - field: type
      function: pattern
      functionOptions:
        match: array
    - field: items.type
      function: pattern
      functionOptions:
        match: object
    documentationUrl: https://apicommons.org/rules/#openapi-response-collection-require-results-array
  openapi-response-collection-require-results-array-oas2:
    formats:
    - oas2
    description: Response bodies must have a root element called results and is an array of objects.
    message: Response bodies must have a root element called results and is an array of objects.
    severity: info
    given: $.paths[?(!@property.match(/.*\/\{[^}]+\}$/))].get.responses['200'].schema.properties.results
    then:
    - field: type
      function: pattern
      functionOptions:
        match: array
    - field: items.type
      function: pattern
      functionOptions:
        match: object
    documentationUrl: https://apicommons.org/rules/#openapi-response-collection-require-results-array-oas2
  openapi-response-collection-support-paging:
    formats:
    - oas3
    description: Response bodies from collection endpoints SHOULD offer paging capability.
    message: Response bodies from collection endpoints SHOULD offer paging capability.
    severity: info
    given: $.paths[?(!@property.match(/.*\/\{[^}]+\}.*$/))].get.responses['200'].content.application/json.schema.properties
    then:
    - field: paging
      function: truthy
    - field: paging
      function: pattern
      functionOptions:
        match: object
    - field: paging.type
      function: pattern
      functionOptions:
        match: object
    documentationUrl: https://apicommons.org/rules/#openapi-response-collection-support-paging
  openapi-response-collection-support-paging-oas2:
    formats:
    - oas2
    description: Response bodies from collection endpoints SHOULD offer paging capability.
    message: Response bodies from collection endpoints SHOULD offer paging capability.
    severity: info
    given: $.paths[?(!@property.match(/.*\/\{[^}]+\}.*$/))].get.responses['200'].schema.properties
    then:
    - field: paging
      function: truthy
    - field: paging
      function: pattern
      functionOptions:
        match: object
    - field: paging.type
      function: pattern
      functionOptions:
        match: object
    documentationUrl: https://apicommons.org/rules/#openapi-response-collection-support-paging-oas2
  openapi-response-define-429:
    description: Responses should contain common response - 429 (too many requests).
    message: '{{description}}. Missing {{property}}'
    severity: info
    given: $.paths..responses
    then:
      field: '429'
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-define-429
  openapi-response-get-cache-control:
    description: GET success responses should define a Cache-Control header so clients and intermediaries know how to cache
      the representation.
    message: GET success responses should define a `Cache-Control` header.
    given: $.paths[*].get.responses[?( @property >= 200 && @property < 300 && @property != 204 )].headers
    severity: info
    then:
      field: Cache-Control
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-get-cache-control
  openapi-response-get-etag:
    description: GET success responses should define an ETag header to enable validation-based caching and conditional requests.
    message: GET success responses should define a `ETag` header.
    given: $.paths[*].get.responses[?( @property >= 200 && @property < 300 && @property != 204 )].headers
    severity: info
    then:
      field: ETag
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-get-etag
  openapi-response-get-last-modified:
    description: GET success responses should define a Last-Modified header to enable date-based conditional requests.
    message: GET success responses should define a `Last-Modified` header.
    given: $.paths[*].get.responses[?( @property >= 200 && @property < 300 && @property != 204 )].headers
    severity: info
    then:
      field: Last-Modified
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-get-last-modified
  openapi-response-get-link-header:
    description: GET success responses should provide a Link header (RFC 8288) with rel next/prev/first/last for pagination
      and navigation — the header-based alternative to an in-body paging object.
    message: GET responses should provide a Link header (RFC 8288) for pagination/navigation.
    given: $.paths[*].get.responses[?( @property >= 200 && @property < 300 && @property != 204 )].headers
    severity: info
    then:
      field: Link
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-get-link-header
  openapi-response-get-vary:
    description: GET success responses should define a Vary header so caches key correctly on the request headers that affect
      the representation.
    message: GET success responses should define a `Vary` header.
    given: $.paths[*].get.responses[?( @property >= 200 && @property < 300 && @property != 204 )].headers
    severity: info
    then:
      field: Vary
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-get-vary
  openapi-response-include-ratelimit-header:
    description: Response must include ratelimit-x headers.
    message: '{{description}}; missing {{property}}'
    severity: info
    given: $..responses.*
    then:
    - field: headers.ratelimit-limit
      function: truthy
    - field: headers.ratelimit-remaining
      function: truthy
    - field: headers.ratelimit-reset
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-include-ratelimit-header
  openapi-response-ratelimit-header:
    description: Responses should define the structured RateLimit header (current IETF draft) conveying quota, remaining,
      and reset in one field — the modern successor to the RateLimit-Limit/Remaining/Reset triplet.
    message: Responses should define a `RateLimit` header.
    given: $..responses.*
    severity: info
    then:
      field: headers.RateLimit
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-ratelimit-header
  openapi-response-ratelimit-policy:
    description: Responses should define a RateLimit-Policy header documenting the quota policy and window (e.g. 100;w=60),
      so clients understand the limits in effect.
    message: Responses should define a `RateLimit-Policy` header.
    given: $..responses.*
    severity: info
    then:
      field: headers.RateLimit-Policy
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-ratelimit-policy
  openapi-response-success-require-ratelimit-header:
    description: 'Ratelimiting API preserves a service and limits attack scenario [see API4:2019 Lack of Resources & Rate
      Limiting](https://owasp.org/www-project-api-security). APIs should use the following headers at least on successful
      responses: - `X-RateLimit-Limit`: number of total requests in a give time window - `X-RateLimit-Remaining`: remaining
      requests in the current window - `X-RateLimit-Reset`: number of seconds before the window resets An example set of headers
      is the following ``` X-Ratelimit-Limit: 100 X-Ratelimit-Remaining: 40 X-Ratelimit-Reset: 12 ``` A standardization proposal
      for ratelimit headers is ongoning inside the IETF HTTPAPI Workgroup. See [the draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/).'
    message: Missing ratelimit headers. {{property}} {{error}} {{path}}
    severity: info
    given: $.[responses][?(@property[0] == "2" )][headers]
    then:
    - functionOptions:
        properties:
        - X-RateLimit-Limit
        - RateLimit-Limit
      function: xor
    - functionOptions:
        properties:
        - X-RateLimit-Remaining
        - RateLimit-Remaining
      function: xor
    - functionOptions:
        properties:
        - X-RateLimit-Reset
        - RateLimit-Reset
      function: xor
    formats:
    - oas3
    documentationUrl: https://apicommons.org/rules/#openapi-response-success-require-ratelimit-header
  openapi-response-throttled-require-retry-after:
    description: 'When a client is either: * throttled out with a 429 status code; * warned about a temporary server issue
      with a 503 status code; the server should explicitly communicate how long to wait before issuing further requests using
      the Retry-After header. Retry-After is defined in RFC7231.'
    message: 'Missing ratelimit header: {{property}} in {{path}}'
    severity: info
    given: $.[responses][?(@property == "429" || @property == "503"  )][headers]
    then:
      field: Retry-After
      function: truthy
    formats:
    - oas3
    documentationUrl: https://apicommons.org/rules/#openapi-response-throttled-require-retry-after
  openapi-response-write-etag:
    description: Write success responses (POST/PUT/PATCH) should define an ETag header so clients receive the new entity tag
      after a write and can make subsequent conditional requests.
    message: Write success responses should define a `ETag` header.
    given: $.paths[*][post,put,patch].responses[?( @property >= 200 && @property < 300 && @property != 204 )].headers
    severity: info
    then:
      field: ETag
      function: truthy
    documentationUrl: https://apicommons.org/rules/#openapi-response-write-etag
  openapi-schema-collection-require-pagination-params:
    description: Collection GET endpoints SHOULD support pagination using query parameters. Offset or cursor based pagination
      is required.
    message: Collection GET endpoints SHOULD support pagination using query parameters.
    severity: info
    given: $.paths[?(!@property.match(/.*\/\{[^}]+\}\/*.*/))].get
    then:
    - field: parameters
      function: schema
      functionOptions:
        schema:
          type: array
          items:
            type: object
          contains:
            type: object
            properties:
              name:
                const: limit
              in:
                const: query
          allOf:
          - anyOf:
            - contains:
                type: object
                properties:
                  name:
                    const: offset
                  in:
                    const: query
            - contains:
                type: object
                properties:
                  name:
                    const: cursor
                  in:
                    const: query
            - contains:
                type: object
                properties:
                  name:
                    const: page
                  in:
                    const: query
    documentationUrl: https://apicommons.org/rules/#openapi-schema-collection-require-pagination-params
  apis-json-schema-include-rate-limit-reference:
    description: This property ensures there is an API rate limits reference associated with API, ensuring the rate limits
      applied to an API are clearly communicated.
    message: Has an API Terms of Services
    severity: info
    given:
    - $.apis.*.properties.*
    - $.common.*
    then:
    - field: type
      function: pattern
      functionOptions:
        notMatch: \b(rate-limits|RateLimits|Rate Limits)\b
    documentationUrl: https://apicommons.org/rules/#apis-json-schema-include-rate-limit-reference
