# harvested from https://github.com/zuplo/rate-my-openapi/blob/24819fbe7576e2811b3be2750312e2cea64bcf14/rulesets/.spectral.yaml on 2026-10-09 — a Spectral ruleset published in the provider's own GitHub repository (zuplo/rate-my-openapi); found by GitHub code search, fetched verbatim x-method: harvested x-stamped: 2026-10-09 x-source-url: https://github.com/zuplo/rate-my-openapi/blob/24819fbe7576e2811b3be2750312e2cea64bcf14/rulesets/.spectral.yaml extends: [[spectral:oas, all]] rules: # ----- This part is in sync with rule.vacuum.yaml # paths-kebab-case: false # operation-4xx-response: missing operation-success-response: warn operation-operationId-valid-in-url: warn operation-operationId: warn contact-properties: info info-contact: info info-license: info license-url: info tag-description: info operation-tags: hint openapi-tags: warn operation-singular-tag: false # The alphabetical rule seems to fail on Box openapi-tags-alphabetical: false # description-duplication: missing # Covered by oas3-api-servers # oas3-host-trailing-slash: missing no-$ref-siblings: false # ----- End of synced part # Copy of .spectral-supplement.yaml apimatic-security-defined: description: "Apimatic: It is recommended to define at least one authentication scheme globally using the securitySchemes property in the components section and use it globally to authenticate all the endpoints or use it for specific endpoints." message: "'security' must be defined and not empty" given: "$" severity: warn then: field: "security" function: schema functionOptions: schema: type: array items: type: object minItems: 1 apimatic-operationId-max-length: description: "Apimatic: Longer content can lead to issues in the code generation process. It's best to keep the length to a maximum of 50 characters, wherever possible." message: "{{property}} must be shorter than 50 characters" given: "$.paths..operationId" severity: info type: validation then: function: length functionOptions: max: 50 apimatic-parameter-name-max-length: description: "Apimatic: Longer content can lead to issues in the code generation process. It's best to keep the length to a maximum of 50 characters, wherever possible." message: "{{property}} must be shorter than 50 characters" given: "$.paths..parameters[*].name" severity: info type: validation then: function: length functionOptions: max: 50 apimatic-header-name-max-length: description: "Apimatic: Longer content can lead to issues in the code generation process. It's best to keep the length to a maximum of 50 characters, wherever possible." message: "{{property}} must be shorter than 50 characters" given: "$.paths..responses..headers[*]~" severity: info type: validation then: function: length functionOptions: max: 50 apimatic-component-name-max-length: description: "Apimatic: Longer content can lead to issues in the code generation process. It's best to keep the length to a maximum of 50 characters, wherever possible." message: "{{property}} must be shorter than 50 characters" given: "$.components.[schemas,requestBodies,responses,parameters,examples,headers,securitySchemes][*]~" severity: info type: validation then: function: length functionOptions: max: 50 apimatic-no-inline-response-schema: given: $.paths..responses..content..schema description: "Apimatic: In general, inline schemas are not encouraged in code generators and API portal generators since their names are inferred from the parent node in which they are defined inline." message: "Response schema: {{path}} should be moved to components/schemas and referenced" severity: info resolved: false then: field: "$ref" function: truthy apimatic-no-inline-parameter-schema: description: "Apimatic: In general, inline schemas are not encouraged in code generators and API portal generators since their names are inferred from the parent node in which they are defined inline." message: "Parameter schema: {{path}} should be moved to components/schemas and referenced" given: $.paths..parameters[*].schema severity: info resolved: false then: field: "$ref" function: truthy apimatic-no-inline-request-body-schema: description: "Apimatic: In general, inline schemas are not encouraged in code generators and API portal generators since their names are inferred from the parent node in which they are defined inline." message: "Request Body schema: {{path}} should be moved to components/schemas and referenced" given: $.paths..requestBody.content..schema severity: info resolved: false then: field: "$ref" function: truthy owasp:api1:2019-no-numeric-ids: description: "OWASP API1:2019 - Use random IDs that cannot be guessed. UUIDs are preferred." severity: warn given: '$.paths..parameters[*][?(@property === "name" && (@ === "id" || @.match(/(_id|Id|-id)$/)))]^.schema' then: function: schema functionOptions: schema: type: "object" not: properties: type: const: "integer" properties: format: const: "uuid" owasp:api2:2019-no-http-basic: message: "Security scheme uses HTTP Basic. Use a more secure authentication method, like OAuth 2.0." description: "Basic authentication credentials transported over network are more susceptible to interception than other forms of authentication, and as they are not encrypted it means passwords and tokens are more easily leaked." severity: warn given: "$.components.securitySchemes[*]" then: field: "scheme" function: pattern functionOptions: notMatch: "basic" owasp:api3:2019-define-error-responses-401: message: "Operation is missing {{property}}." description: "OWASP API Security recommends defining schemas for all responses, even errors. The 401 describes what happens when a request is unauthorized, so its important to define this not just for documentation, but to empower contract testing to make sure the proper JSON structure is being returned instead of leaking implementation details in backtraces." severity: warn given: "$.paths..responses" then: - field: "401" function: truthy - field: "401.content" function: truthy owasp:api3:2019-define-error-responses-500: message: "Operation is missing {{property}}." description: "OWASP API Security recommends defining schemas for all responses, even errors. The 500 describes what happens when a request fails with an internal server error, so its important to define this not just for documentation, but to empower contract testing to make sure the proper JSON structure is being returned instead of leaking implementation details in backtraces." severity: warn given: "$.paths..responses" then: - field: "500" function: truthy - field: "500.content" function: truthy owasp:api4:2019-rate-limit: message: "All 2XX and 4XX responses should define rate limiting headers." description: "Define proper rate limiting to avoid attackers overloading the API. There are many ways to implement rate-limiting, but most of them involve using HTTP headers, and there are two popular ways to do that:\n\nIETF Draft HTTP RateLimit Headers:. https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/\n\nCustomer headers like X-Rate-Limit-Limit (Twitter: https://developer.twitter.com/en/docs/twitter-api/rate-limits) or X-RateLimit-Limit (GitHub: https://docs.github.com/en/rest/overview/resources-in-the-rest-api)" severity: info formats: [oas3] given: "$.paths[*]..responses[?(@property.match(/^(2|4)/))]" then: field: "headers" function: schema functionOptions: schema: type: "object" oneOf: - required: ["RateLimit-Limit", "RateLimit-Reset"] - required: ["X-RateLimit-Limit"] - required: ["X-Rate-Limit-Limit"] owasp:api4:2019-rate-limit-retry-after: message: "A 429 response should define a Retry-After header." description: "Define proper rate limiting to avoid attackers overloading the API. Part of that involves setting a Retry-After header so well meaning consumers are not polling and potentially exacerbating problems." severity: info formats: [oas3] given: "$..responses[429].headers" then: field: "Retry-After" function: defined owasp:api4:2019-rate-limit-responses-429: message: "Operation is missing rate limiting response in {{property}}." description: "OWASP API Security recommends defining schemas for all responses, even errors. A HTTP 429 response signals the API client is making too many requests, and will supply information about when to retry so that the client can back off calmly without everything breaking. Defining this response is important not just for documentation, but to empower contract testing to make sure the proper JSON structure is being returned instead of leaking implementation details in backtraces. It also ensures your API/framework/gateway actually has rate limiting set up." severity: info given: "$.paths..responses" then: - field: "429" function: truthy - field: "429.content" function: truthy owasp:api7:2019-security-hosts-https-oas3: message: "Server URLs MUST begin https://, and no other protocol is permitted." description: "All server interactions MUST use the https protocol, meaning server URLs should begin `https://`.\n\nLearn more about the importance of TLS (over SSL) here: https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html" severity: warn formats: [oas3] given: "$.servers..url" then: function: pattern functionOptions: match: "/^https:/" redocly-operation-summary: message: Operation should have a summary description: "Operation summaries are used to generate API docs. Redocly uses the summary as the header for the operation, as well as the sidebar navigation text. See https://redocly.com/docs/cli/rules/operation-summary/" severity: warn given: "$.paths.*[?( @property === 'get' || @property === 'put' || @property === 'post' || @property === 'delete' || @property === 'options' || @property === 'head' || @property === 'patch' || @property === 'trace' )]" then: - field: "summary" function: truthy redocly-components-invalid-map-name: message: All component names MUST consist of the following characters `A..Z a..z 0..9 . _ -` description: "All components MUST use keys that match the regular expression: ^[a-zA-Z0-9.-_]+$ See https://redocly.com/docs/cli/rules/spec-components-invalid-map-name/" severity: error given: - "$.components.schemas[*]~" - "$.components.parameters[*]~" - "$.components.securitySchemes[*]~" - "$.components.requestBodies[*]~" - "$.components.responses[*]~" - "$.components.headers[*]~" - "$.components.examples[*]~" - "$.components.links[*]~" - "$.components.callbacks[*]~" then: function: pattern functionOptions: match: ^[a-zA-Z0-9._-]+$ redocly-no-server-variables-empty-enum: message: "Server variables defined, but no enum of options provided" description: "If you use server variables, there are generally two kinds: tenant-driven and environment-driven. In the case of environment-driven variables, you may want to predefine all of the possible values. See https://redocly.com/docs/cli/rules/no-server-variables-empty-enum/" severity: warn given: "$.servers[*].variables[*]" then: field: "enum" function: defined redocly-no-undefined-server-variable: message: "Variable was declared in server URL but not documented" description: "Document all declared server variables to make it easier to consume the API. See https://redocly.com/docs/cli/rules/no-undefined-server-variable/" severity: warn given: "$.servers[?(@.url.match(/({)/))]" then: field: "variables" function: defined speakeasy-parameter-name-nonempty: message: "Parameter has an empty name" description: "All parameters must have a non-empty name. See https://www.speakeasyapi.dev/docs/openapi/validation" severity: warn given: "$.paths..parameters..name" then: function: length functionOptions: min: 1 # TODO: Integrate and benchmark custom JS rules # speakeasy-duplicate-tag: # message: "Duplicate tags detected" # description: "Tag names must be unique. See https://www.speakeasyapi.dev/docs/openapi/validation" # severity: warn # given: "$.tags" # then: # function: "checkUniqueTags" # speakeasy-validate-requests: # message: "Request body content type is not a valid mime type" # description: "Request body content type must be a valid mime type. See https://www.speakeasyapi.dev/docs/openapi/validation" # severity: warn # given: "$.paths..requestBody.content" # then: # function: "validateContentMimeType" # speakeasy-validate-responses: # message: "Response content type is not a valid mime type" # description: "Responses content type must be a valid mime type. See https://www.speakeasyapi.dev/docs/openapi/validation" # severity: warn # given: "$.paths..responses..content" # then: # function: "validateContentMimeType"