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

Initial CAMARA OAS linting ruleset #74

Merged
merged 16 commits into from
Feb 9, 2024
1 change: 1 addition & 0 deletions artifacts/Github_actions/.workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Configuration files for Github Actions
354 changes: 354 additions & 0 deletions documentation/Linting-rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,354 @@
# CAMARA API Linting Rules Documentation

## Introduction


## 1. Spectral core ruleset

Spectral has a built-in OpenAPI Specification ruleset that can be used to validate OpenAPI files.

With `extends: "spectral:oas"` ("oas" being shorthand for OpenAPI Specification) in the ruleset file to rules for OpenAPI v2 and v3.x, depending on the appropriate OpenAPI version being used (this is automatically detected through formats) are added to the final ruleset.

The full list of the rules in this ruleset are described in [OpenAPI Rules](https://docs.stoplight.io/docs/spectral/4dec24461f3af-open-api-rules).


`extends: [[spectral:oas, off]]` - this avoids running any rules from the extended ruleset as they are disabled. Each rule then can be [enabled individually](https://docs.stoplight.io/docs/spectral/0a73453054745-recommended-or-all#enabling-rules).

### Rule severity

The `severity` keyword is optional in rule definition and can be `error`, `warn`, `info`, `hint`, or `off`.
The default value is `warn`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should discuss what is the expected outcome for each severity. For example should warn result in a change and re-lint, or can it be ignored?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Maybe we can differentiate along the following lines:

  • warnings can be ignored when introducing linting first time
    • OR (alternative) warnings can be ignored if correcting them would introduce a breaking change
  • warnings shall not be introduced with a change (e.g. within a merge, that's the point where linting is done)

But that's to clarify in a next version. Will you open an issue for that @Kevsy ?


### OpenAPI v2 & v3
Rules applying to both OpenAPI v2.0, v3.0, and most likely v3.1.
rartych marked this conversation as resolved.
Show resolved Hide resolved


|Name| Desc| Recom mended|CAMARA use|Spectral severity | CAMARA severity
rartych marked this conversation as resolved.
Show resolved Hide resolved
|---|---|---|--|---|--|
|contact-properties| contact object is full of the most useful properties: `name`, `url`, and `email`|No|No | Warning | |

|duplicated-entry-in-enum| Each value of an `enum` must be different from one another |Yes | Yes | Warning | |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be an error

|info-contact |Info object should contain `contact` object |Yes | Yes| Warning | |
|info-description |Info object should contain `description` object |Yes | Yes| Warning | |
|info-license |Info object should contain `license` object |Yes | Yes| Warning | |
|license-url | link to the full text of licence | Yes | Yes| Warning | |
|no-$ref-siblings| Before OpenAPI v3.1, keywords next to $ref were ignored | Yes | Yes| Error | |
|no-eval-in-markdown | injecting `eval()` JavaScript statements could lead to an XSS attack |Yes |Yes |Warning | |
|no-script-tags-in-markdown | injecting `<script>` tags could lead to execution of an arbitrary | Yes |Yes | Warning | |
|openapi-tags | OpenAPI object should have non-empty `tags` array |No | Yes | Warning | |
|openapi-tags-alphabetical | OpenAPI object should have alphabetical `tags` | No |No | Warning | |
|openapi-tags-uniqueness | OpenAPI object must not have duplicated tag names | No | No | Error | |
rartych marked this conversation as resolved.
Show resolved Hide resolved
|operation-description | Operation `description` must be present and non-empty string | Yes| Yes| Warning | |
|operation-operationId | Operation must have `operationId` |Yes| Yes| Warning | |
|operation-operationId-unique | Every operation must have a unique operationId | Yes| Yes| Error | |
|operation-operationId-valid-in-url | avoid non-URL-safe characters| Yes| Yes| Warning | |
|operation-parameters | Operation parameters are unique and non-repeating | Yes| Yes| Warning | |
|operation-singular-tag | Use just one tag for an operation | No| Yes| Warning | |
|operation-success-response | Operation must have at least one `2xx` or `3xx` response | Yes| Yes| Warning | |
|operation-tags | Operation should have non-empty `tags` array| Yes| Yes| Warning | |
|operation-tag-defined | Operation tags should be defined in global tags| Yes| Yes| Warning | |
|path-declarations-must-exist | Path parameter declarations cannot be empty, ex.`/given/{}` is invalid. | Yes| Yes| Warning | |
|path-keys-no-trailing-slash | Keep trailing slashes off of paths, | Yes| Yes| Warning | |
|path-not-include-query | Don't put query string items in the path, they belong in parameters with `in: query`| Yes| Yes| Warning | |
|path-params | Path parameters are correct and valid | Yes| Yes| Error | |
|tag-description | global tags have description | No | ???| Warning | |
rartych marked this conversation as resolved.
Show resolved Hide resolved
|typed-enum | Enum values should respect the type specifier. | Yes| Yes| Warning | |

### OpenAPI v3-only
Rules applicable only to OpenAPI v3.0 documents.

|Name| Desc| Recom mended|CAMARA use|Spectral severity | CAMARA severity
|---|---|---|--|---|--|
|oas3-api-servers | OpenAPI servers must be present and non-empty array | Yes| Yes| Warning | |
|oas3-examples-value-or-externalValue | Examples for requestBody or response examples can have an `externalValue` or a `value`, but they cannot have both| Yes| Yes| Warning | |
|**oas3-operation-security-defined** | Operation `security` values must match a scheme defined in the `components.securitySchemes` object. | Yes| Yes| Warning | |
|oas3-parameter-description | Parameter objects should have a description| No| Yes?| Warning | |
|oas3-schema | Validate structure of OpenAPI v3 specification | Yes| Yes| Warning | |
|oas3-server-not-example.com | Server URL should not point to *example.com*| No| Yes?| Warning | |
rartych marked this conversation as resolved.
Show resolved Hide resolved
|oas3-server-trailing-slash | Server URL should not have a trailing slash | Yes| Yes| Warning | |
|oas3-unused-component | Potential unused reusable components entry has been detected | Yes| Yes| Warning | |
|oas3-valid-media-example | Examples must be valid against their defined schema. This rule is applied to *Media Type objects* | Yes| Yes| Warning | |
|oas3-valid-schema-example | Examples must be valid against their defined schema. This rule is applied to *Schema objects* | Yes| Yes| Warning | |
|oas3-server-variables | This rule ensures that server variables defined in OpenAPI Specification 3 (OAS3) and 3.1 are valid, not unused | Yes| Yes| Warning | |



## 2. Language
### Spell checking

CAMARA API specification files include inline documentation.

The description attributes should be checked for typos.

_Spectral rule_: [camara-language-spelling]()

*Severity*: `warn`

### Reduce telco-specific terminology in API definitions

API Design Guidelines: [2.5 Reduce telco-specific terminology in API definitions](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#25-reduce-telco-specific-terminology-in-api-definitions)

Consider and account for how the API can be fulfilled on a range of network types.
Avoid terms/types specific to a given telco domain - terms should be inclusive beyond mobile network.

See also [CAMARA Glossary](https://github.com/camaraproject/Commonalities/blob/main/documentation/Glossary.md)


| ❌ &nbsp; Not recommended | 👍 &nbsp; Recommended |
|----------------------------|-------------------------|
| `UE` | `device` |
| `MSISDN` | `phone number` |
| `mobile network` | `network` |


_Spectral rule_: [camara-language-avoid-telco]()

*Severity*: `hint`




## 3. API Definition
Copy link
Collaborator

@sachinvodafone sachinvodafone Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are a few valid scenarios that we can consider for API validation.

  Topic   Description
Openapi version Camara APIs MUST be based on OpenAPI specification with minimum Version 3.0.0.
Request body structure on PUT, POST, PATCH POST / PUT / PATCH methods must have a requestBody. The requestBody content must be "application/json" or "application/xml".
Info object: title, version, description "Info" section is mandatory. Title, Description and Version must be documented.Note: It is provided by Spectral.
Info object: API version format API version within the Info section must follow the format: X.Y.Z
Valid basepath validation API must have valid basepath
Camel case / lower case /Snake_Case Paths URI (tasks, individual resources, etc.) MUST be  lower case and hyphens. OperationIds must be defined in lowerCamelCase. Objects must be defined in CamelCase inside properties field. The event type must be written in UPPER_SNAKE_CASE
Path URI URIs must contain the "major version" of the API.
Resource path must not contain the base URL Path must not contain the base path.
Sensitive data (msisdn/imsi) cannot be a path or query parameter Sensitive data (msisdn/imsi) cannot be a path or query parameter.Note: Needs to list down if we have other sensitive parameters other than MSISDN/IMSI
Valid methods Valid methods method are: GET, PUT, POST, DELETE, PATCH, OPTIONS, HEAD
GET/DELETE methods must not accept a "body" 'GET' and 'DELETE' http methods MUST NOT accept a 'requestBody' attribute
Define common error response pattern Following error responses must be define: 400, 401, 403, 404, 405, 406, 429, 500, 501, 502, 503, 504.Note: List needs to be validated as per Camara API documentation
Verb methods cannot be in the Path Resources must not contain the method name get, put, post, delete, patch.
Parameters must have a description All parameters must have a description.
Path version must be major versions only Path must contain the major API version with format /vX.Example: paths: "/device-status/v0/roaming"
GET/DELETE methods must not accept a "body" 'GET' and 'DELETE' http methods MUST NOT accept a 'requestBody' attribute
Mandatory request body with POST, PATCH and PUT methods The requestBody object MAY be present when the operation is used with one of PUT, POST, PATCH HTTP Verbs.
Summary associated with each operation Summary must be defined on each operation, describing with a short summary what the operation does.
Include valid response examples For each response code, we must define response payload examples



### Openapi property

API Design Guidelines:
[11. Definition in OpenAPI](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#11-definition-in-openapi)

The API functionalities must be implemented following the specifications of the **Open API version 3.0.3**

`/users/{id}`

| ❌ &nbsp; Not recommended | 👍 &nbsp; Recommended |
|----------------------------|-------------------------|
| `openapi: 3.0.1` | `openapi: 3.0.3` |

_Spectral rule_: [camara-oas-version]()

*Severity*: `error`

### Info object

API Design Guidelines:
[11.1 General Information](hhttps://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#111-general-information)


Info object must include the following information: API title with public name.


_Spectral rule_: [camara-info−title]()

*Severity*: `warn`


API Design Guidelines:
[11.1 General Information](hhttps://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#111-general-information)


Info object must include the following information: API Version in the format: X.Y.Z.


_Spectral rule_: [camara-info−version-format]()

*Severity*: `warn` <br>
❕ Note: Currently the format like `version: 0.10.0-wip` is used in the API development branch



### Path parameters

API Design Guidelines:
[3.4 Path Parameters Use](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#34-path-parameters-use)

Point 2 The attribute must be identifying itself, it is not enough with "{id}"

`/users/{id}`

| ❌ &nbsp; Not recommended | 👍 &nbsp; Recommended |
|----------------------------|-------------------------|
| `/users/{id}/documents/{documentId}` | `/users/{userId}/documents/{documentId}` |

_Spectral rule_: [camara-path-param-id]()

*Severity*: `warn`

Point 3 The identifier should have a similar morphology on all endpoints. For example, “*xxxxId*”, where *xxx* is the name of the entity it reference

| 👍 &nbsp; Recommended |
|-------------------------|
| `/users/{userId}` |
|`/accounts/{accountId}` |
|`/vehicles/{vehicleId}` |
|`/users/{userId}/vehicles/{vehicleId}` |

_Spectral rule_: [camara-path-param-id-morphology]()

*Severity*: `warn`


### Sensitive data
Sensitive data (msisdn/imsi) cannot be a path or query parameter.
<br>❕ Note: Needs to list down if we have other sensitive parameters other than MSISDN/IMSI - cf. *monite-security-no-secrets-in-path-or-query-parameters*


_Spectral rule_: [camara-security-no-secrets-in-path-or-query-parameters]()

*Severity*: `warn`

### HTTP verbs

API Design Guidelines:
[3.1 API REST](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#31-api-rest)

Valid methods are: GET, PUT, POST, DELETE, PATCH, OPTIONS

_Spectral rule_: [camara-http-methods]()

*Severity*: `error`



'GET' and 'DELETE' http methods MUST NOT accept a 'requestBody' attribute
<br>❕ Note: https://github.com/team-monite/api-style-guide/blob/main/spectral/monite.section8-requests.yaml

_Spectral rule_: [camara-get-no-request-body]()

*Severity*: `error`


### Reserved words

API Design Guidelines:
[11. Definition in OpenAPI](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#11-definition-in-openapi)

To avoid issues with implementation using Open API generators:

Reserved words must not be used in the following parts of an API specification:
- Path and operation names
- Path or query parameter names
- Request and response body property names
- Security schemes
- Component names
- OperationIds


A reserved word is one whose usage is reserved by any of the following Open API generators:
- [Python Flask](https://openapi-generator.tech/docs/generators/python-flask/#reserved-words)
- [OpenAPI Generator (Java)](https://openapi-generator.tech/docs/generators/java/#reserved-words)
- [OpenAPI Generator (Go)](https://openapi-generator.tech/docs/generators/go/#reserved-words)
- [OpenAPI Generator (Kotlin)](https://openapi-generator.tech/docs/generators/kotlin/#reserved-words)
- [OpenAPI Generator (Swift5)](https://openapi-generator.tech/docs/generators/swift5#reserved-words)

_Spectral rule_: [camara-reserved-words]()

*Severity*: `warn`


Resources must not contain the method name get, put, post, delete, patch.

_Spectral rule_: [camara-resource-reserved-words]()

*Severity*: `warn`


### Descriptions

API Design Guidelines: [11.3 Request Parameters](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#113-request-parameters)

All parameters must have a description.

_Spectral rule_: [camara-parameters-descriptions]()

*Severity*: `warn`

API Design Guidelines: [11.2 Published Routes](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#112-published-routes)
Summary must be defined on each operation, describing with a short summary what the operation does.
_Spectral rule_: [camara-operation-summary]()

*Severity*: `warn`

### Usage of discriminator

API Design Guidelines:
[11.5.1 Usage of discriminator](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#1151-usage-of-discriminator)

When request bodies or response payloads may be one of a number of different schemas (containing `oneOf` or `anyOf` section), a `discriminator` object can be used to aid in serialization, deserialization, and validation.

_Spectral rule_: [camara-discriminator-use]()

*Severity*: `warn`

### Casing convention

Spectral core functions: [casing](https://docs.stoplight.io/docs/spectral/cb95cf0d26b83-core-functions#casing) can be used to verify text match a certain case. Available types are:
|name |sample|
|---|----|
|flat| verylongname|
|camel| veryLongName|
|pascal| VeryLongName|
|kebab| very-long-name|
|cobol| VERY-LONG-NAME|
|snake| very_long_name|
|macro| VERY_LONG_NAME|


#### Enum

API Design Guidelines: **No clear requirement**

❓ This rule verifies that `enum` fields contain values that follow a specific case convention: `macro`.

_Spectral rule_: [camara-enum-casing-convention]()

*Severity*: `info`



#### Operation Id

API Design Guidelines:
[4.1 URL Definition](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#41-url-definition)
> OperationIds are defined in lowerCamelCase: For example: `helloWorld`

Operation ids should follow a specific case convention: `camel` case.

_Spectral rule_: [camara-operationid-casing-convention]()

*Severity*: `error`

#### Path parameters / Query parameters

API Design Guidelines: [4.1 URL Definition](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#41-url-definition)
> URI with lowercase and hyphens. URIs must be "human readable" to facilitate identification of the offered resources. Lowercase words and hyphenation (kebab-case) help achieve this best practice. For example: `/customer-segments`

Path parameter should follow a specific case convention, with the default being `kebab` case.

_Spectral rule_: [camara-parameter-casing-convention]()

*Severity*: `error`

#### Property names

API Design Guidelines: [4.1 URL Definition](https://github.com/camaraproject/Commonalities/blob/main/documentation/API-design-guidelines.md#41-url-definition)

> Objects are defined in CamelCase inside properties field. For example: Greetings, ExampleObject.

❓ **Should it be lowerCamelCase in DG?**

Property names should follow a specific case convention, with the default being `camel` case.

_Spectral rule_: [camara-property-casing-convention]()

*Severity*: `error`

#### Schema names

API Design Guidelines: **No clear requirement**

Schema names (the keys in `components -> schemas`) should follow the "upper camel case" convention - `pascal`


_Spectral rule_: [camara-schema-casing-convention]()

*Severity*: `warn`