From 02879258b0062b485fe49407bff4d2bdb3e56317 Mon Sep 17 00:00:00 2001 From: Fernando Prado Date: Tue, 7 May 2024 10:36:07 +0200 Subject: [PATCH 1/9] update version to wip as per commonalities guideline --- code/API_definitions/sim-swap-notification-subscription.yaml | 2 +- code/API_definitions/sim_swap.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/API_definitions/sim-swap-notification-subscription.yaml b/code/API_definitions/sim-swap-notification-subscription.yaml index bab8d78..bcc1342 100644 --- a/code/API_definitions/sim-swap-notification-subscription.yaml +++ b/code/API_definitions/sim-swap-notification-subscription.yaml @@ -61,7 +61,7 @@ info: license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html - version: 0.1.0-wip + version: wip externalDocs: description: Product documentation at CAMARA url: hhttps://github.com/camaraproject/SimSwap diff --git a/code/API_definitions/sim_swap.yaml b/code/API_definitions/sim_swap.yaml index 352c0fc..f771ae5 100644 --- a/code/API_definitions/sim_swap.yaml +++ b/code/API_definitions/sim_swap.yaml @@ -52,7 +52,7 @@ info: license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html - version: 0.5.0-wip + version: wip externalDocs: description: Product documentation at Camara url: https://github.com/camaraproject/SimSwap From b970802fb316d54d5f9c4516b08a924b4cea908e Mon Sep 17 00:00:00 2001 From: Herbert Damker <52109189+hdamker@users.noreply.github.com> Date: Mon, 13 May 2024 20:22:05 +0200 Subject: [PATCH 2/9] Update CODEOWNERS --- CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 792f293..6c7695a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -7,3 +7,7 @@ # These are the default owners for the whole content of this repository. The default owners are automatically added as reviewers when you open a pull request, unless different owners are specified in the file. * @bigludo7 @fernandopradocabrillo + +# Owners of the CODEOWNER and Maintainer.md files are the admins of CAMARA (to allow them to keep the teams within the CAMARA organization in sync in case of changes) +/CODEOWNERS @camaraproject/admins +/MAINTAINERS.MD @camaraproject/admins From ba764d7590bc2ed97cdf1383cf28f1fbd6b8aa18 Mon Sep 17 00:00:00 2001 From: Herbert Damker <52109189+hdamker@users.noreply.github.com> Date: Mon, 13 May 2024 20:26:07 +0200 Subject: [PATCH 3/9] Update MAINTAINERS.MD --- MAINTAINERS.MD | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MAINTAINERS.MD b/MAINTAINERS.MD index 954c16f..0058999 100644 --- a/MAINTAINERS.MD +++ b/MAINTAINERS.MD @@ -1,7 +1,7 @@ -| Org | Name | -| :-----------------------:| ----------------------------------------------------| -| KDDI | Toshiyasu Wakayama | -| Telefónica | José Luis Urien | -| Telefónica | Fernando Prado | -| SK Telecom | Jung Yun-sun (Serena) | -| Orange | Ludovic Robert | +| Org | Name | GitHub Username | +| :-----------------------:| --------------------------|--------------------------| +| KDDI | Toshiyasu Wakayama | ToshiWakayama-KDDI | +| Telefónica | José Luis Urien | jlurien | +| Telefónica | Fernando Prado | fernandopradocabrillo | +| SK Telecom | Jung Yun-sun (Serena) | ?? | +| Orange | Ludovic Robert | bigludo7 | From 6b7a2bd000c9afb08c3dad2affaecbe07132167b Mon Sep 17 00:00:00 2001 From: Ludovic Robert <30499179+bigludo7@users.noreply.github.com> Date: Tue, 14 May 2024 15:21:57 +0200 Subject: [PATCH 4/9] Update MAINTAINERS.MD Agree with you @hdamker Following ProjectStructureAndRoles rulings. Happy to re insert Jung Yun-Sun in future. --- MAINTAINERS.MD | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS.MD b/MAINTAINERS.MD index 0058999..29a4915 100644 --- a/MAINTAINERS.MD +++ b/MAINTAINERS.MD @@ -3,5 +3,4 @@ | KDDI | Toshiyasu Wakayama | ToshiWakayama-KDDI | | Telefónica | José Luis Urien | jlurien | | Telefónica | Fernando Prado | fernandopradocabrillo | -| SK Telecom | Jung Yun-sun (Serena) | ?? | | Orange | Ludovic Robert | bigludo7 | From 3c9b07e119303df39700a94870d40e21cdaefaa9 Mon Sep 17 00:00:00 2001 From: Ludovic Robert <30499179+bigludo7@users.noreply.github.com> Date: Wed, 15 May 2024 13:55:28 +0200 Subject: [PATCH 5/9] Update sim-swap-notification-subscription.yaml Fixed MegaLinter issues --- .../sim-swap-notification-subscription.yaml | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/code/API_definitions/sim-swap-notification-subscription.yaml b/code/API_definitions/sim-swap-notification-subscription.yaml index bcc1342..13809bb 100644 --- a/code/API_definitions/sim-swap-notification-subscription.yaml +++ b/code/API_definitions/sim-swap-notification-subscription.yaml @@ -13,7 +13,7 @@ info: * **SIM swap**: A SIM swap is a process in which a mobile phone user's current SIM card is deactivated or replaced with a new one. This is typically done by contacting the user's mobile service provider and requesting a new SIM card for various reasons, such as a lost or damaged SIM card, upgrading to a new phone, or changing phone numbers while keeping the same device. - # API Functionality + # API Functionality The API exposes following capabilities: * **/subscriptions**: This endpoint has two operations, one that allows to retrieve the list of Sim Swap event subscriptions and another one to create new event subscriptions. @@ -21,12 +21,12 @@ info: ## Sim Swap notification subscription - Theses endpoints allow to manage notification subscription on Sim Swap event. + Theses endpoints allow to manage notification subscription on Sim Swap event. The CAMARA subscription model is detailed in the CAMARA API design guideline document and follows Cloudevents specification. It is mandatory in the subscription to provide the event `type` subscribed are several are managed in this API. - Only one event ``type`` is managed for this API: + Only one event ``type`` is managed for this API: - ``org.camaraproject.sim-swap.v0.swapped`` - Event triggered when a sim swap occurs on the associated phoneNumber @@ -466,7 +466,7 @@ components: specversion: type: string description: Version of the specification to which this event conforms (must be 1.0 if it conforms to cloudevents 1.0.2 version) - example: 1.0 + example: "1.0" datacontenttype: type: string description: 'media-type that describes the event payload encoding, must be "application/json" for CAMARA APIs' @@ -486,14 +486,17 @@ components: type: string format: uri-reference minLength: 1 - description: "Identifies the context in which an event happened in the specific Provider Implementation." - example: - - https://github.com/cloudevents - - mailto:cncf-wg-serverless@lists.cncf.io - - urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66 - - cloudevents/spec/pull/123 - - /sensors/tn-1234567/alerts - - 1-555-123-4567 + description: | + Identifies the context in which an event happened, as a non-empty `URI-reference` like: + - URI with a DNS authority: + * https://github.com/cloudevents + * mailto:cncf-wg-serverless@lists.cncf.io + - Universally-unique URN with a UUID: + * urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66 + - Application-specific identifier: + * /cloudevents/spec/pull/123 + * 1-555-123-4567 + example: "https://notificationSendServer12.supertelco.com" DateTime: type: string @@ -678,7 +681,7 @@ components: examples: SWAPPED: value: - id: 123655 + id: "123655" source: supertelco.notificationSendServer12 type: org.camaraproject.sim-swap.v0.swapped specversion: "1.0" @@ -690,7 +693,7 @@ components: SUBSCRIPTION_ENDS: value: - id: 123658 + id: "123658" source: supertelco.notificationSendServer12 type: org.camaraproject.sim-swap.v0.subscription-ends specversion: "1.0" From 213cebab444c3d0b33b6b24cb0bb4c4ee68f07fd Mon Sep 17 00:00:00 2001 From: Ludovic Robert <30499179+bigludo7@users.noreply.github.com> Date: Wed, 15 May 2024 13:58:47 +0200 Subject: [PATCH 6/9] Update sim_swap.yaml Fixed Mega-Linter issues --- code/API_definitions/sim_swap.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/code/API_definitions/sim_swap.yaml b/code/API_definitions/sim_swap.yaml index f771ae5..75cb1a6 100644 --- a/code/API_definitions/sim_swap.yaml +++ b/code/API_definitions/sim_swap.yaml @@ -3,27 +3,27 @@ info: title: SIM Swap description: | The SIM swap API provides a programmable interface for developers and other users (capabilities consumers) to request the last date of a SIM swap performed on the mobile line, or, to check whether a SIM swap has been performed during a past period. - + # Introduction The SIM Swap API performs real-time checks on the last SIM Swap event. The SIM Swap API is useful to prevent fraud by reducing the risk of account takeover fraud by strengthening SIM based authentication processes such as SMS One-time passwords. Fraudsters are using SIM swap techniques to intercept SMS messages and reset passwords or receive verification codes that allow them to access protected accounts. - The SIM Swap API can also be used to protect non-automated actions. For example, when a call center expect contacts a user to clarify or confirm a sensitive operation. + The SIM Swap API can also be used to protect non-automated actions. For example, when a call center expect contacts a user to clarify or confirm a sensitive operation. This API is used by an application to get information about a mobile line latest SIM swap date. It can be easily integrated and used through this secured API and allows SPs (Service Provider) to get this information an easy & secured way. The API provides management of 2 endpoints answering 2 distinct questions: * When did the last SIM swap occur? * Has a SIM swap occurred during last n hours? - + Depending on the network provider implementation, legal enforcement, etc... either one or both endpoints could be implemented. # Relevant terms and definitions **SIM swap**: A SIM swap is a process in which a user's mobile phone number (MSISDN) is associated with a new SIM card (IMSI). This is typically done by contacting the user's mobile service provider and requesting a new SIM card for various reasons, such as a lost or damaged SIM card or upgrading to a new phone. - + SimSwap also happens during other actions like changing user's phone number, changing mobile service provider keeping user's mobile phone number or when activating a new SIM associated to the same phone number, known as multisim service. # API functionality @@ -67,7 +67,7 @@ paths: post: security: - openId: - - sim-swap:retrieve-date + - sim-swap:retrieve-date tags: - Retrieve SIM swap date description: Get timestamp of last MSISDN <-> IMSI pairing change for a mobile user account provided with MSIDN. @@ -77,7 +77,7 @@ paths: requestBody: description: | Create a SIM swap date request for a MSISDN identifier. - content : + content: application/json: schema: $ref: "#/components/schemas/CreateSimSwapDate" @@ -112,9 +112,9 @@ paths: post: security: - openId: - - sim-swap:check + - sim-swap:check tags: - - Check SIM swap + - Check SIM swap description: Check if SIM swap has been performed during a past period operationId: checkSimSwap parameters: @@ -122,7 +122,7 @@ paths: requestBody: description: | Create a check SIM swap request for a MSISDN identifier. - content : + content: application/json: schema: $ref: "#/components/schemas/CreateCheckSimSwap" @@ -176,7 +176,7 @@ components: required: - latestSimChange properties: - latestSimChange: + latestSimChange: type: string format: date-time description: Timestamp of latest SIM swap performed. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. Recommended format is yyyy-MM-dd'T'HH:mm:ss.SSSZ (i.e. which allows 2023-07-03T14:27:08.312+02:00 or 2023-07-03T12:27:08.312Z) From 84c72d43b263146e016c5327832fc9dc43a11af3 Mon Sep 17 00:00:00 2001 From: rartych Date: Wed, 29 May 2024 16:06:29 +0200 Subject: [PATCH 7/9] Linting rules & workflows --- .github/workflows/megalinter.yml | 78 ++++++ .github/workflows/spectral_oas_lint.yml | 36 +++ .spectral.yml | 258 ++++++++++++++++++ .yamllint.yaml | 35 +++ lint_function/camara-language-avoid-telco.js | 40 +++ lint_function/camara-reserved-words.js | 98 +++++++ ...-no-secrets-in-path-or-query-parameters.js | 26 ++ 7 files changed, 571 insertions(+) create mode 100644 .github/workflows/megalinter.yml create mode 100644 .github/workflows/spectral_oas_lint.yml create mode 100644 .spectral.yml create mode 100644 .yamllint.yaml create mode 100644 lint_function/camara-language-avoid-telco.js create mode 100644 lint_function/camara-reserved-words.js create mode 100644 lint_function/camara-security-no-secrets-in-path-or-query-parameters.js diff --git a/.github/workflows/megalinter.yml b/.github/workflows/megalinter.yml new file mode 100644 index 0000000..6bda700 --- /dev/null +++ b/.github/workflows/megalinter.yml @@ -0,0 +1,78 @@ +--- +# MegaLinter GitHub Action configuration file +# More info at https://megalinter.io +# CAMARA Project - Github Action for Pull Reqests +# 31.01.2024 - initial version + +name: MegaLinter + +on: # yamllint disable-line rule:truthy + # Pull Requests to main + pull_request: + branches: [master, main] + +env: # Comment env block if you do not want to apply fixes + # Apply linter fixes configuration + APPLY_FIXES: all # When active, APPLY_FIXES must also be defined as environment variable (in github/workflows/mega-linter.yml or other CI tool) + APPLY_FIXES_EVENT: pull_request # Decide which event triggers application of fixes in a commit or a PR (pull_request, push, all) + APPLY_FIXES_MODE: commit # If APPLY_FIXES is used, defines if the fixes are directly committed (commit) or posted in a PR (pull_request) + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + build: + name: MegaLinter + runs-on: ubuntu-latest + permissions: + # Give the default GITHUB_TOKEN write permission to commit and push, comment issues & post new PR + # Remove the ones you do not need + contents: write + issues: write + pull-requests: write + steps: + # Git Checkout + - name: Checkout Code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 # If you use VALIDATE_ALL_CODEBASE = true, you can remove this line to improve performances + - name: Install Spectral + run: npm install -g @stoplight/spectral + - name: Install Spectral functions + run: npm install -g @stoplight/spectral-functions + # - name: Run spectral:oas Spectral Linting + # run: spectral lint code/API_definitions/*.yaml --verbose --ruleset .spectral.yml + # Replace openapi.yaml file with your API specification file + + # MegaLinter + - name: MegaLinter + id: ml + # You can override MegaLinter flavor used to have faster performances + # More info at https://megalinter.io/flavors/ + uses: oxsecurity/megalinter/flavors/java@v7.3.0 + env: + # All available variables are described in documentation + # https://megalinter.io/configuration/ + PRINT_ALPACA: false + # VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} # Validates all source when push on main, else just the git diff with main. Override with true if you always want to lint all sources + VALIDATE_ALL_CODEBASE: true + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # ADD YOUR CUSTOM ENV VARIABLES HERE OR DEFINE THEM IN A FILE .mega-linter.yml AT THE ROOT OF YOUR REPOSITORY + DISABLE: COPYPASTE,MARKDOWN + DISABLE_LINTERS: SPELL_CSPELL,SPELL_LYCHEE,YAML_PRETTIER,REPOSITORY_GRYPE, REPOSITORY_SEMGREP,REPOSITORY_DEVSKIM,REPOSITORY_KICS,REPOSITORY_TRIVY,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,REPOSITORY_CHECKOV,REPOSITORY_GITLEAKS,YAML_V8R,JAVA_PMD,JAVA_CHECKSTYLE + YAML_YAMLLINT_CONFIG_FILE: ".yamllint.yaml" + OPENAPI_SPECTRAL_CONFIG_FILE: ".spectral.yml" + YAML_YAMLLINT_FILTER_REGEX_INCLUDE: "(code/)" + OPENAPI_SPECTRAL_FILTER_REGEX_INCLUDE: "(code/)" + + # Upload MegaLinter artifacts + - name: Archive production artifacts + if: ${{ success() }} || ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: MegaLinter reports + path: | + megalinter-reports + mega-linter.log diff --git a/.github/workflows/spectral_oas_lint.yml b/.github/workflows/spectral_oas_lint.yml new file mode 100644 index 0000000..a828fd5 --- /dev/null +++ b/.github/workflows/spectral_oas_lint.yml @@ -0,0 +1,36 @@ +--- +# CAMARA Project - workflow configuration to manually run CAMARA OAS rules +# see https://docs.github.com/en/actions/using-workflows/manually-running-a-workflow +# 31.01.2024 - initial version + +name: Spectral manual run + +on: workflow_dispatch + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + build: + name: Spectral linting + runs-on: ubuntu-latest + permissions: + # Give the default GITHUB_TOKEN write permission to commit and push, comment issues & post new PR + # Remove the ones you do not need + contents: write + issues: write + pull-requests: write + steps: + # Git Checkout + - name: Checkout Code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 # If you use VALIDATE_ALL_CODEBASE = true, you can remove this line to improve performances + - name: Install Spectral + run: npm install -g @stoplight/spectral + - name: Install Spectral functions + run: npm install -g @stoplight/spectral-functions + - name: Run Spectral linting + run: spectral lint code/API_definitions/*.yaml --verbose --ruleset .spectral.yml diff --git a/.spectral.yml b/.spectral.yml new file mode 100644 index 0000000..0b16508 --- /dev/null +++ b/.spectral.yml @@ -0,0 +1,258 @@ +# CAMARA Project - linting ruleset - documentation avaialable here: +# https://github.com/camaraproject/Commonalities/blob/main/documentation/Linting-rules.md +# 31.01.2024 - initial version + +extends: "spectral:oas" +functions: + - camara-reserved-words + - camara-language-avoid-telco + - camara-security-no-secrets-in-path-or-query-parameters +functionsDir: "./lint_function" +rules: + # Built-in OpenAPI Specification ruleset. Each rule then can be enabled individually. + # The severity keyword is optional in rule definition and can be error, warn, info, hint, or off. The default value is warn. + contact-properties: false + duplicated-entry-in-enum: true + info-contact: true + info-description: true + info-license: true + license-url: true + no-$ref-siblings: error + no-eval-in-markdown: true + no-script-tags-in-markdown: true + openapi-tags: false + openapi-tags-alphabetical: false + openapi-tags-uniqueness: error + operation-description: true + operation-operationId: true + operation-operationId-unique: error + operation-operationId-valid-in-url: true + operation-parameters: true + operation-singular-tag: true + operation-success-response: true + operation-tags: true + operation-tag-defined: true + path-declarations-must-exist: true + path-keys-no-trailing-slash: true + path-not-include-query: true + path-params: error + tag-description: false + typed-enum: true + oas3-api-servers: true + oas3-examples-value-or-externalValue: true + oas3-operation-security-defined: false + oas3-parameter-description: false + oas3-schema: true + oas3-server-not-example.com: false + oas3-server-trailing-slash: true + oas3-unused-component: true + oas3-valid-media-example: true + oas3-valid-schema-example: true + # oas3-server-variables: true + + # Custom Rules Utilizing Spectral's Built-in Functions and JavaScript Implementations + + camara-language-avoid-telco: + message: "{{error}}" + severity: hint + description: | + This rule checks for telco-specific terminology in your API definitions and suggests more inclusive terms. + given: "$..*.*" + then: + function: camara-language-avoid-telco + recommended: false # Set to true/false to enable/disable this rule + + camara-oas-version: + message: "OpenAPI Version Error: The OpenAPI specification must adhere to version 3.0.3." + severity: error + description: | + This rule validates the OpenAPI version in your specification and requires compliance with version 3.0.3. + given: "$" + then: + field: openapi + function: pattern + functionOptions: + match: 3.0.3 + recommended: true # Set to true/false to enable/disable this rule + + camara-path-param-id: + message: "Path Parameter Naming Warning: Use 'resource_id' instead of just 'id' in path parameters." + severity: warn + description: | + This rule ensures consistent and descriptive naming for path parameters in your OpenAPI specification. + Please use 'resource_id' instead of just 'id' for your path parameters. + given: "$..parameters[?(@.in == 'path')]" + then: + field: name + function: pattern + functionOptions: + notMatch: \b(id|Id|ID|iD)\b + recommended: true # Set to true/false to enable/disable this rule + + camara-security-no-secrets-in-path-or-query-parameters: + message: "Sensitive data found in path: {{error}} Consider avoiding the use of Sesentive data " + severity: warn + description: | + This rule checks for sensitive data ('MSISDN' and 'IMSI') in API paths and suggests avoiding their use. + given: + - "$.paths" + then: + function: camara-security-no-secrets-in-path-or-query-parameters + recommended: true # Set to true/false to enable/disable this rule + + camara-http-methods: + description: "Ensure that all path URLs have valid HTTP methods (GET, PUT, POST, DELETE, PATCH, OPTIONS)." + message: "Invalid HTTP method for '{{path}}'. Must be one of get, put, post, delete, patch, options." + severity: error + given: $.paths[*][*]~ + then: + function: pattern + functionOptions: + match: "^(get|put|post|delete|patch|options)$" + recommended: true # Set to true/false to enable/disable this rule + + camara-get-no-request-body: + message: There must be no request body for Get and DELETE + severity: error + given: + - "$.paths.*.get" + - "$.paths.*.delete" + then: + field: requestBody + function: falsy + recommended: true # Set to true/false to enable/disable this rule + + camara-reserved-words: + message: "Reserved words found {{error}} Consider avoiding the use of reserved word " + severity: warn + description: | + This rule checks Reserved words must not be used in the following parts of an API specification [Paths, Request Body properties, Component, Operation Id, Security Schema] + given: + - "$.paths" # Paths + - "$..parameters[*]" # Path or Query Parameter Names: + - "$..components.schemas.*.properties.*" # Request and Response body parameter + - "$.paths.*." # Path and Operation Names: + - "$.components.securitySchemes" # Security Schemes: + - "$.components.*.*" # Component Names: + - "$.paths.*.*.operationId" # OperationIds: + then: + function: camara-reserved-words + recommended: true # Set to true/false to enable/disable this rule + + camara-routes-description: + message: "Functionality method description Warning: Each method should have description." + severity: warn + description: | + This rule checks if each operation (POST, GET, DELETE, PUT, PATCH, OPTIONS) in your API specification has a description. + Ensure that you have added a 'summary' field for each operation in your OpenAPI specification. + given: + - "$.paths.*.post" + - "$.paths.*.get" + - "$.paths.*.delete" + - "$.paths.*.put" + - "$.paths.*.patch" + - "$.paths.*.options" + then: + field: description + function: truthy + recommended: true # Set to true/false to enable/disable this rule + + camara-parameters-descriptions: + message: "Parameter description is missing or empty: {{error}}" + severity: warn + description: | + This Spectral rule ensures that each path parameter in the API specification has a descriptive and meaningful description. + given: + - "$.paths..parameters.*" + then: + field: description + function: truthy + recommended: true # Set to true/false to enable/disable this rule + + camara-response-descriptions: + message: "Parameter description is missing or empty: {{error}}" + severity: warn + description: | + This Spectral rule ensures that each responese object in the API specification has a descriptive and meaningful description. + given: + - "$.paths..responses.*" + then: + field: description + function: truthy + recommended: true # Set to true/false to enable/disable this rule + + camara-properties-descriptions: + message: "Property description is missing or empty: {{error}}" + severity: warn + description: | + This Spectral rule ensures that each propoerty within objects in the API specification has a descriptive and meaningful description. + given: + - "$.components.*.*" + - "$.components.*.*.properties.*" + then: + field: description + function: truthy + recommended: true # Set to true/false to enable/disable this rule + + camara-operation-summary: + message: "Operation Summary Warning: Each operation should include a short summary for better understanding." + severity: warn + description: | + This rule checks if each operation (POST, GET, DELETE, PUT, PATCH, OPTIONS) in your API specification has a meaningful summary. + Ensure that you have added a 'summary' field for each operation in your OpenAPI specification. + given: + - "$.paths.*.post" + - "$.paths.*.get" + - "$.paths.*.delete" + - "$.paths.*.put" + - "$.paths.*.patch" + - "$.paths.*.options" + then: + field: summary + function: truthy + recommended: true # Set to true/false to enable/disable this rule + + camara-discriminator-use: + description: | + Ensure that API definition YAML files with oneOf or anyOf sections include a discriminator object for serialization, deserialization, and validation. + severity: hint + given: "$..[?(@.oneOf || @.anyOf)]" + then: + field: discriminator + function: truthy + description: "Discriminator object is required when using oneOf or anyOf." + recommended: true # Set to true/false to enable/disable this rule + + camara-operationid-casing-convention: + message: Operation Id must be in Camel case "{{error}}" + severity: hint + description: | + This rule checks Operation ids should follow a specific case convention: camel case. + given: "$.paths.*.*.operationId" + then: + function: casing + functionOptions: + type: camel + recommended: true # Set to true/false to enable/disable this rule + + camara-schema-casing-convention: + description: This rule checks schema should follow a specific case convention pascal case. + message: "{{property}} should be pascal case (UppperCamelCase)" + severity: warn + given: $.components.schemas[*]~ + then: + function: casing + functionOptions: + type: pascal + recommended: true # Set to true/false to enable/disable this rule + + camara-parameter-casing-convention: + description: Paths should be kebab-case. + severity: error + message: "{{property}} is not kebab-case: {{error}}" + given: $.paths[*]~ + then: + function: pattern + functionOptions: + match: "^\/([a-z0-9]+(-[a-z0-9]+)*)?(\/[a-z0-9]+(-[a-z0-9]+)*|\/{.+})*$" # doesn't allow /asasd{asdas}sadas pattern or not closed braces + recommended: true # Set to true/false to enable/disable this rule diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..081ef09 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,35 @@ +--- +# CAMARA Project - YAML linting configuration for yamllint https://yamllint.readthedocs.io/en/latest/rules.html +# 31.01.2024 - initial version + +yaml-files: + - '*.yaml' + - '*.yml' + - '.yamllint' + +rules: + braces: enable + brackets: enable + colons: enable + commas: enable + comments: + min-spaces-from-content: 1 + level: error + comments-indentation: + level: error + document-end: disable + document-start: disable + empty-lines: enable + empty-values: disable + hyphens: enable + indentation: enable + key-duplicates: enable + key-ordering: disable + line-length: disable + new-line-at-end-of-file: enable + new-lines: disable + octal-values: disable + quoted-strings: disable + trailing-spaces: enable + truthy: + level: error diff --git a/lint_function/camara-language-avoid-telco.js b/lint_function/camara-language-avoid-telco.js new file mode 100644 index 0000000..061b543 --- /dev/null +++ b/lint_function/camara-language-avoid-telco.js @@ -0,0 +1,40 @@ +// CAMARA Project - support function for Spectral linter +// 31.01.2024 - initial version + +const replacements = [ + { original: 'UE', recommended: 'device' }, + { original: 'MSISDN', recommended: 'phone number' }, + { original: 'mobile network', recommended: 'network' } +]; + +export default async function (input) { + const errors = []; + const suggestions = []; + + // Iterate over properties of the input object + for (const path in input) { + const value = input[path]; + + // Check if the value is a string + if (typeof value === 'string') { + for (const replacement of replacements) { + const original = replacement.original; + const recommended = replacement.recommended; + + // Use a regular expression to match 'original' as a standalone word + const regex = new RegExp(`\\b${original}\\b`, 'g'); + + // Check if 'original' exists in the value + if (regex.test(value)) { + errors.push(replacement); + suggestions.push(` Telco-specific terminology found in input: Consider replacing '${original}' with '${recommended}'.`); + } + } + } + } + + // Check if any word from 'replacements' is in the suggestions + if (errors.length > 0) { + console.log(`Hint camara-language-avoid-telco ` + suggestions.join(', ')); + } +}; diff --git a/lint_function/camara-reserved-words.js b/lint_function/camara-reserved-words.js new file mode 100644 index 0000000..c28e63a --- /dev/null +++ b/lint_function/camara-reserved-words.js @@ -0,0 +1,98 @@ +// CAMARA Project - support function for Spectral linter +// 31.01.2024 - initial version + +const reservedWords = [ + 'abstract', + 'apiclient', + 'apiexception', + 'apiresponse', + 'assert', + 'boolean', + 'break', + 'byte', + 'case', + 'catch', + 'char', + 'class', + 'configuration', + 'const', + 'continue', + 'do', + 'double', + 'else', + 'extends', + 'file', + 'final', + 'finally', + 'float', + 'for', + 'goto', + 'if', + 'implements', + 'import', + 'instanceof', + 'int', + 'interface', + 'list', + 'localdate', + 'localreturntype', + 'localtime', + 'localvaraccept', + 'localvaraccepts', + 'localvarauthnames', + 'localvarcollectionqueryparams', + 'localvarcontenttype', + 'localvarcontenttypes', + 'localvarcookieparams', + 'localvarformparams', + 'localvarheaderparams', + 'localvarpath', + 'localvarpostbody', + 'localvarqueryparams', + 'long', + 'native', + 'new', + 'null', + 'object', + 'offsetdatetime', + 'package', + 'private', + 'protected', + 'public', + 'return', + 'short', + 'static', + 'strictfp', + 'stringutil', + 'super', + 'switch', + 'synchronized', + 'this', + 'throw', + 'throws', + 'transient', + 'try', + 'void', + 'volatile', + 'while' +]; +// Reserved word 'enum' and 'default' are removed from above reserved word array as they are common in openAPI keyword +export default async function lintReservedWords(input) { + // Iterate over properties of the input object + for (const path in input) { + if (typeof path === 'string') { + + for (const word of reservedWords) { + const regex = new RegExp(`\\b${word}\\b`, 'g'); // Use a regular expression to match 'word' as a standalone word + + if (regex.test(path)) { + const warningRuleName = 'camara-reserved-words'; + const description = `Reserved words found in input: Consider avoiding the use of reserved word '${word}'`; + // const location = `${path}`; + + console.log(`warning ${warningRuleName} ${description} ${path}`); + } + } + } + } +} diff --git a/lint_function/camara-security-no-secrets-in-path-or-query-parameters.js b/lint_function/camara-security-no-secrets-in-path-or-query-parameters.js new file mode 100644 index 0000000..ebbff2a --- /dev/null +++ b/lint_function/camara-security-no-secrets-in-path-or-query-parameters.js @@ -0,0 +1,26 @@ +// CAMARA Project - support function for Spectral linter +// 31.01.2024 - initial version + +const sensitiveData = ['MSISDN','IMSI','phoneNumber']; + +export default async function (input) { + + // Iterate over properties of the input object + for (const path in input) { + + if (typeof path === 'string') { + for (const word of sensitiveData ) { + const regex = new RegExp(`\\b${word}\\b`, 'g'); // Use a regular expression to match 'word' as a standalone word + + if (regex.test(path)) { + + const warningRuleName = 'camara-security-no-secrets-in-path-or-query-parameters'; + const description = `sensitiveData Data found in path: Consider avoiding the use of sensitiveData data '${word}'`; + const location = `paths.${path}`; + console.log(`warning ${warningRuleName} ${description} ${location}`); + + } + } + } + } +} From eb750b651b9d0eaab181b39c8b40c50733a77fbe Mon Sep 17 00:00:00 2001 From: Rafal Artych <121048129+rartych@users.noreply.github.com> Date: Wed, 29 May 2024 16:24:53 +0200 Subject: [PATCH 8/9] Update sim-swap-notification-subscription.yaml --- .../sim-swap-notification-subscription.yaml | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/code/API_definitions/sim-swap-notification-subscription.yaml b/code/API_definitions/sim-swap-notification-subscription.yaml index 13809bb..cac3150 100644 --- a/code/API_definitions/sim-swap-notification-subscription.yaml +++ b/code/API_definitions/sim-swap-notification-subscription.yaml @@ -30,10 +30,10 @@ info: - ``org.camaraproject.sim-swap.v0.swapped`` - Event triggered when a sim swap occurs on the associated phoneNumber - Note: Additionally to these list, ``org.camaraproject.sim-swap.v0.subscription-ends`` notification `type` is sent when the subscription ends. - This notification does not require dedicated subscription. + Note: Additionally to these list, ``org.camaraproject.sim-swap.v0.subscription-ends`` notification `type` is sent when the subscription ends. + This notification does not require dedicated subscription. It is used when: - - the subscription expire time (optionally set by the requester) has been reached + - the subscription expire time (optionally set by the requester) has been reached - the maximum number of subscription events (optionally set by the requester) has been reached - the API server has to stop sending notification prematurely @@ -42,7 +42,7 @@ info: This endpoint describes the event notification received on subscription listener side when the event occurred. As for subscription, detailed description of the event notification is provided in the CAMARA API design guideline document. **WARNING**: This callback endpoint must be exposed on the listener side as `POST /{$request.body#/webhook/notificationUrl}` - will be posted by the sim swap resource server to the webhook url provided by notification + will be posted by the sim swap resource server to the webhook url provided by notification listener. # Authorization and authentication @@ -87,7 +87,7 @@ paths: - $ref: '#/components/parameters/x-correlator' security: - openId: - - sim-swap:subscriptions:create + - sim-swap:subscriptions:create requestBody: content: application/json: @@ -117,7 +117,7 @@ paths: SWAPPED: $ref: '#/components/examples/SWAPPED' SUBSCRIPTION_ENDS: - $ref: '#/components/examples/SUBSCRIPTION_ENDS' + $ref: '#/components/examples/SUBSCRIPTION_ENDS' responses: "204": description: Successful notification @@ -135,8 +135,8 @@ paths: "503": $ref: "#/components/responses/Generic503" security: - - { } - - notificationsBearerAuth: [ ] + - {} + - notificationsBearerAuth: [] responses: "201": @@ -179,7 +179,7 @@ paths: - $ref: '#/components/parameters/x-correlator' security: - openId: - - sim-swap:subscriptions:read + - sim-swap:subscriptions:read responses: "200": description: List of event subscription details @@ -211,7 +211,7 @@ paths: operationId: retrieveSubscription security: - openId: - - sim-swap:subscriptions:read + - sim-swap:subscriptions:read parameters: - $ref: "#/components/parameters/SubscriptionId" - $ref: '#/components/parameters/x-correlator' @@ -245,7 +245,7 @@ paths: description: delete a given event subscription. security: - openId: - - sim-swap:subscriptions:delete + - sim-swap:subscriptions:delete parameters: - $ref: "#/components/parameters/SubscriptionId" - $ref: '#/components/parameters/x-correlator' @@ -323,7 +323,7 @@ components: message: type: string description: Detailed error description - + CreateSubscription: description: The request for creating a sim swap event subscription type: object @@ -439,8 +439,8 @@ components: description: Response for a sim swap operation managed asynchronously (Creation or Deletion) type: object properties: - subscriptionId: - $ref: '#/components/schemas/SubscriptionId' + subscriptionId: + $ref: '#/components/schemas/SubscriptionId' SubscriptionId: type: string @@ -479,8 +479,8 @@ components: discriminator: propertyName: 'type' mapping: - org.camaraproject.sim-swap.v0.swapped: '#/components/schemas/EventSimSwap' - org.camaraproject.sim-swap.v0.subscription-ends: '#/components/schemas/EventSubscriptionEnds' + org.camaraproject.sim-swap.v0.swapped: '#/components/schemas/EventSimSwap' + org.camaraproject.sim-swap.v0.subscription-ends: '#/components/schemas/EventSubscriptionEnds' Source: type: string @@ -505,7 +505,7 @@ components: example: '2018-04-05T17:31:00Z' EventSimSwap: - description: event structure for swapped event + description: event structure for swapped event allOf: - $ref: '#/components/schemas/CloudEvent' - type: object @@ -514,7 +514,7 @@ components: $ref: '#/components/schemas/Swapped' EventSubscriptionEnds: - description: event structure for event subscription ends + description: event structure for event subscription ends allOf: - $ref: '#/components/schemas/CloudEvent' - type: object @@ -524,7 +524,7 @@ components: Swapped: description: Event detail structure for ROAMING_ON & ROAMING_OFF event - type : object + type: object required: - phoneNumber - subscriptionId @@ -536,7 +536,7 @@ components: SubscriptionEnds: description: Event detail structure for SUBSCRIPTION_ENDS event - type : object + type: object required: - phoneNumber - terminationReason @@ -686,9 +686,9 @@ components: type: org.camaraproject.sim-swap.v0.swapped specversion: "1.0" datacontenttype: application/json - data: - phoneNumber: +123456788 - subscriptionId: 2ghy-55gg-7iup-yuo9 + data: + phoneNumber: +123456788 + subscriptionId: 2ghy-55gg-7iup-yuo9 time: 2023-01-18T13:18:23.682Z SUBSCRIPTION_ENDS: @@ -698,9 +698,9 @@ components: type: org.camaraproject.sim-swap.v0.subscription-ends specversion: "1.0" datacontenttype: application/json - data: - phoneNumber: +123456789 - terminationReason: SUBSCRIPTION_EXPIRED - subscriptionId: 2ghy-55gg-7iup-yuo9 - terminationDescription: subscription expire time reached + data: + phoneNumber: +123456789 + terminationReason: SUBSCRIPTION_EXPIRED + subscriptionId: 2ghy-55gg-7iup-yuo9 + terminationDescription: subscription expire time reached time: 2023-01-19T13:18:23.682Z From fd35d02a1afc222c3e750b4ec2ed71e9cf425891 Mon Sep 17 00:00:00 2001 From: Rafal Artych <121048129+rartych@users.noreply.github.com> Date: Wed, 29 May 2024 16:28:02 +0200 Subject: [PATCH 9/9] Update sim-swap-notification-subscription.yaml --- code/API_definitions/sim-swap-notification-subscription.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/API_definitions/sim-swap-notification-subscription.yaml b/code/API_definitions/sim-swap-notification-subscription.yaml index cac3150..b1da1d0 100644 --- a/code/API_definitions/sim-swap-notification-subscription.yaml +++ b/code/API_definitions/sim-swap-notification-subscription.yaml @@ -359,7 +359,7 @@ components: notificationAuthToken: type: string example: "c8974e592c2fa383d4a3960714" - description: | + description: | OAuth2 token to be used by the callback API endpoint. It MUST be indicated within HTTP Authorization header e.g. Authorization: Bearer $notificationAuthToken SubscriptionDetail: @@ -440,7 +440,7 @@ components: type: object properties: subscriptionId: - $ref: '#/components/schemas/SubscriptionId' + $ref: '#/components/schemas/SubscriptionId' SubscriptionId: type: string