diff --git a/.github/workflows/megalinter.yml b/.github/workflows/megalinter.yml deleted file mode 100644 index 6bda700..0000000 --- a/.github/workflows/megalinter.yml +++ /dev/null @@ -1,78 +0,0 @@ ---- -# 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/pr_validation_caller.yml b/.github/workflows/pr_validation_caller.yml new file mode 100644 index 0000000..d847f6e --- /dev/null +++ b/.github/workflows/pr_validation_caller.yml @@ -0,0 +1,49 @@ +# ========================================================================================= +# CAMARA Project - Pull Request Validation Workflow Caller +# +# This GitHub Actions workflow is responsible for invoking a reusable PR validation workflow +# from the camaraproject/tooling repository. It is intended to ensure consistent validation +# steps for all PRs targeting the main branch in this repository. +# +# CHANGELOG: +# - 2025-08-01: Initial version for v0 +# +# USAGE: +# - Automatically triggers on pull requests targeting main. +# - Can be triggered manually via workflow_dispatch. +# - Calls by default the reusable workflow at +# camaraproject/tooling/.github/workflows/pr_validation.yml@v0 +# +# DOCUMENTATION: +# see https://github.com/camaraproject/tooling/tree/main/linting/docs +# ========================================================================================= + +name: Caller for PR validation workflow + +on: + # Trigger on pull requests to the main branch only + pull_request: + branches: main + # Enable manual trigger via the GitHub UI + workflow_dispatch: + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +permissions: + # Grant necessary write permissions for PRs, contents, and issues + pull-requests: write + contents: write + issues: write + statuses: write + +jobs: + pr_validation: + # Invoke the reusable PR validation workflow from "v0" tag of camaraproject/tooling + uses: camaraproject/tooling/.github/workflows/pr_validation.yml@v0 + secrets: inherit +# Tools configuration from the tooling repository subfolder of /linting/config/ indicated by `configurations` variable +# If needed, you can specify a configuration from another subfolder of camaraproject/tooling/linting/config/ (uncomment below) +# with: +# configurations: api-name diff --git a/.github/workflows/spectral-oas-caller.yml b/.github/workflows/spectral-oas-caller.yml new file mode 100644 index 0000000..05cde3f --- /dev/null +++ b/.github/workflows/spectral-oas-caller.yml @@ -0,0 +1,42 @@ +# ========================================================================================= +# CAMARA Project - Linting OpenAPI Specification with CAMARA Ruleset Caller +# +# This GitHub Actions workflow is responsible for invoking a reusable "Spectral linting with +# CAMARA ruleset" workflow from the camaraproject/tooling repository. It is intended to +# provide more detailed output from Spectral tool (warnings, hints) +# +# CHANGELOG: +# - 2025-08-01: Initial version for v0 +# +# USAGE: +# - Can be triggered manually via workflow_dispatch. +# - Calls by default the reusable workflow at +# camaraproject/tooling/.github/workflows/spectral-oas.yml@v0 +# +# DOCUMENTATION: +# see https://github.com/camaraproject/tooling/tree/main/linting/docs +# ========================================================================================= + +name: Caller for Spectral linting with CAMARA ruleset + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +permissions: + # Grant necessary write permissions for PRs and issues + pull-requests: write + contents: read + issues: write + +jobs: + spectral: + # Invoke the reusable PR validation workflow from the main branch of camaraproject/tooling + uses: camaraproject/tooling/.github/workflows/spectral-oas.yml@v0 +# Spectral configuration from the tooling repository subfolder of /linting/config/ indicated by `configurations` variable +# If needed, you can specify a configuration from another subfolder of camaraproject/tooling/linting/config/ (uncomment below) +# with: +# configurations: api-name diff --git a/.github/workflows/spectral_oas_lint.yml b/.github/workflows/spectral_oas_lint.yml deleted file mode 100644 index a828fd5..0000000 --- a/.github/workflows/spectral_oas_lint.yml +++ /dev/null @@ -1,36 +0,0 @@ ---- -# 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 deleted file mode 100644 index 7599b00..0000000 --- a/.spectral.yml +++ /dev/null @@ -1,261 +0,0 @@ -# CAMARA Project - linting ruleset - documentation avaialable here: -# https://github.com/camaraproject/Commonalities/blob/main/documentation/Linting-rules.md -# Changelog: -# - 31.01.2024: Initial version -# - 19.03.2024: Corrected camara-http-methods rule - - -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|parameters)$" - 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 deleted file mode 100644 index 231787b..0000000 --- a/.yamllint.yaml +++ /dev/null @@ -1,35 +0,0 @@ ---- -# 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/code/Test_definitions/region-device-count.feature b/code/Test_definitions/region-device-count.feature index 6eee943..23bc560 100644 --- a/code/Test_definitions/region-device-count.feature +++ b/code/Test_definitions/region-device-count.feature @@ -1,4 +1,3 @@ -@RegionDeviceCount Feature: CAMARA Region Device Count API v0.2.0-rc.1 - Operations for device count in specified area # Input to be provided by the implementation to the tester @@ -19,261 +18,257 @@ Feature: CAMARA Region Device Count API v0.2.0-rc.1 - Operations for device coun # # References to OAS spec schemas refer to schemas specifies in region-device-count.yaml, version 0.2.0-rc.1 -Background: Common Region Device Count setup - Given the resource "{api-root}/regionDeviceCount/v0.2rc1/count" set as base-url - And the header "Content-Type" is set to "application/json" - And the header "Authorization" is set to a valid access token - And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" - And the request body is set by default to a request body compliant with the schema + Background: Common Region Device Count setup + Given the resource "{api-root}/regionDeviceCount/v0.2rc1/count" set as base-url + And the header "Content-Type" is set to "application/json" + And the header "Authorization" is set to a valid access token + And the header "x-correlator" complies with the schema at "#/components/schemas/XCorrelator" + And the request body is set by default to a request body compliant with the schema # Happy path scenarios -@region_device_count_count_01_supported_area_success_scenario -Scenario: Validate success response for a supported area request - Given the request body property "$.area" is set to the provided area, starttime, and endtime so that the result of the request is below the density requirement - When the request "count" is sent - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" - And the response property "$.status" value is "SUPPORTED_AREA" - And the response property "$.count" is a non-negative integer + @region_device_count_count_01_supported_area_success_scenario + Scenario: Validate success response for a supported area request + Given the request body property "$.area" is set to the provided area, starttime, and endtime so that the result of the request is below the density requirement + When the request "count" is sent + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + And the response property "$.status" value is "SUPPORTED_AREA" + And the response property "$.count" is a non-negative integer -@region_device_count_count_02_partial_area_success -Scenario: Validate success response for a partial supported area request - Given the request body property "$.area" is set to a valid testing area partially within supported regions - When the request "count" is sent - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" - And the response property "$.status" value is "PART_OF_AREA_NOT_SUPPORTED" - And the response property "$.count" is a non-negative integer + @region_device_count_count_02_partial_area_success + Scenario: Validate success response for a partial supported area request + Given the request body property "$.area" is set to a valid testing area partially within supported regions + When the request "count" is sent + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + And the response property "$.status" value is "PART_OF_AREA_NOT_SUPPORTED" + And the response property "$.count" is a non-negative integer -@region_device_count_count_03_not_supported_area_success -Scenario: Validate success response for unsupported area request - Given the request body property "$.area" is set to a valid testing area outside supported regions - When the request "count" is sent - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" - And the response property "$.status" value is "AREA_NOT_SUPPORTED" - And the response property "$.count" is absent + @region_device_count_count_03_not_supported_area_success + Scenario: Validate success response for unsupported area request + Given the request body property "$.area" is set to a valid testing area outside supported regions + When the request "count" is sent + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + And the response property "$.status" value is "AREA_NOT_SUPPORTED" + And the response property "$.count" is absent -@region_device_count_count_04_density_below_privacy_threshold_success -Scenario: Validate success response for density below privacy threshold request - Given the request body property "$.area","$.starttime","$.endtime" is set to the provided area, start time, and end time, so that the result of the request is DENSITY_BELOW_PRIVACY_THRESHOLD. - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" - And the response property "$.status" value is "DENSITY_BELOW_PRIVACY_THRESHOLD" - And the response property "$.count" is absent + @region_device_count_count_04_density_below_privacy_threshold_success + Scenario: Validate success response for density below privacy threshold request + Given the request body property "$.area","$.starttime","$.endtime" is set to the provided area, start time, and end time, so that the result of the request is DENSITY_BELOW_PRIVACY_THRESHOLD. + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + And the response property "$.status" value is "DENSITY_BELOW_PRIVACY_THRESHOLD" + And the response property "$.count" is absent -@region_device_count_count_05_supported_area_time_interval_success_scenario -Scenario: Validate success response for a supported area request - Given the request body property "$.area" is set to a valid testing area within supported regions -And the request body property "$.starttime" is set to a valid testing time within the allowed time range -And the request body property "$.endtime" is set to a valid testing time later than body property "$.starttime" - When the request "count" is sent - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" - And the response property "$.status" value is "SUPPORTED_AREA" - And the response property "$.count" is a non-negative integer + @region_device_count_count_05_supported_area_time_interval_success_scenario + Scenario: Validate success response for a supported area and a supported time interval request + Given the request body property "$.area" is set to a valid testing area within supported regions + And the request body property "$.starttime" is set to a valid testing time within the allowed time range + And the request body property "$.endtime" is set to a valid testing time later than body property "$.starttime" + When the request "count" is sent + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + And the response property "$.status" value is "SUPPORTED_AREA" + And the response property "$.count" is a non-negative integer -@region_device_count_count_06_supported_area_filter_success_scenario -Scenario: Validate success response for a supported area request - Given the request body property "$.area" is set to a valid testing area within supported regions -And the request body property "$.filter" is set to a valid testing filter the API supported - When the request "count" is sent - Then the response status code is 200 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" - And the response property "$.status" value is "SUPPORTED_AREA" - And the response property "$.count" is a non-negative integer + @region_device_count_count_06_supported_area_filter_success_scenario + Scenario: Validate success response for a supported area and a supported filter request + Given the request body property "$.area" is set to a valid testing area within supported regions + And the request body property "$.filter" is set to a valid testing filter the API supported + When the request "count" is sent + Then the response status code is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + And the response property "$.status" value is "SUPPORTED_AREA" + And the response property "$.count" is a non-negative integer + @region_device_count_count_07_async_success + Scenario: Validate success async response for a request when sink is provided + Given the request body property "$.area" is set to a valid area within supported regions + And the request body property "$.starttime" is set to a valid time + And the request body property "$.endtime" is set to a valid time later than "$.starttime" + And the request property "$.sink" is set to a valid URL + And the request property "$.sinkCredential.credentialType" is set to "ACCESSTOKEN" + And the request property "$.sinkCredential.accessTokenType" is set to "bearer" + And the request property "$.sinkCredential.accessToken" is set to a valid access token + And the request property "$.sinkCredential.accessTokenExpiresUtc" is set to a value long enough in the future + When the request "count" is sent + Then the response status code is 202 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the request with the response body will be received at the address of the request property "$.sink" + And the request will have header "Authorization" set to "Bearer: " + the value of the request property "$.sinkCredential.accessToken" + And the request body received complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + # Generic errors + @region_device_count_count_08_missing_required_property + Scenario: Error response for missing required property in request body + Given the request body property "" is not included + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + @region_device_count_count_09_invalid_date_format + Scenario Outline: Error 400 when the datetime format is not RFC-3339 + Given the request body property "" is not set to a valid RFC-3339 date-time + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text + Examples: + | date_property | + | $.starttime | + | $.endtime | -@region_device_count_count_07_async_success -Scenario: Validate success async response for a request when sink is provided - Given the request body property "$.area" is set to a valid area within supported regions - And the request body property "$.starttime" is set to a valid time - And the request body property "$.endtime" is set to a valid time later than "$.starttime" - And the request property "$.sink" is set to a valid URL - And the request property "$.sinkCredential.credentialType" is set to "ACCESSTOKEN" - And the request property "$.sinkCredential.accessTokenType" is set to "bearer" - And the request property "$.sinkCredential.accessToken" is set to a valid access token - And the request property "$.sinkCredential.accessTokenExpiresUtc" is set to a value long enough in the future - When the request "count" is sent - Then the response status code is 202 - And the response header "Content-Type" is "application/json" - And the response header "x-correlator" has same value as the request header "x-correlator" - And the request with the response body will be received at the address of the request property "$.sink" - And the request will have header "Authorization" set to "Bearer: " + the value of the request property "$.sinkCredential.accessToken" - And the request body received complies with the OAS schema at "/components/schemas/RegionDeviceCountResponse" + @region_device_count_count_10_invalid_sink_credential + Scenario Outline: Invalid credential + Given the request body property "$.sinkCredential.credentialType" is set to "" + When the request "count" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_CREDENTIAL" + And the response property "$.message" contains a user friendly text -# Generic errors -@region_device_count_count_08_missing_required_property -Scenario Outline: Error response for missing required property in request body - Given the request body property "" is not included - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_ARGUMENT" - And the response property "$.message" contains a user friendly text -@region_device_count_count_09_invalid_date_format -Scenario Outline: Error 400 when the datetime format is not RFC-3339 - Given the request body property "" is not set to a valid RFC-3339 date-time - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_ARGUMENT" - And the response property "$.message" contains a user friendly text + Examples: + | unsupported_credential_type | + | PLAIN | + | REFRESHTOKEN | - Examples: - | date_property | - | $.starttime | - | $.endtime | + # Only "bearer" is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, + # and both could be accepted + @region_device_count_count_11_sink_credential_invalid_token + Scenario: Invalid token + Given the request body property "$.sinkCredential.accessTokenType" is set to a value other than "bearer" + When the request "count" is sent + Then the response status code is 400 + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text -@region_device_count_count_10_invalid_sink_credential -Scenario Outline: Invalid credential - Given the request body property "$.sinkCredential.credentialType" is set to "" - When the request "count" is sent - Then the response status code is 400 - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_CREDENTIAL" - And the response property "$.message" contains a user friendly text + @region_device_count_count_12_expired_access_token + Scenario: Error response for expired access token + Given an expired access token + And the request body is set to a valid request body + When the request "count" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text - Examples: - | unsupported_credential_type | - | PLAIN | - | REFRESHTOKEN | + @region_device_count_count_13_invalid_access_token + Scenario: Error response for invalid access token + Given an invalid access token + And the request body is set to a valid request body + When the request "count" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text -# Only "bearer" is considered in the schema so a generic schema validator may fail and generate a 400 INVALID_ARGUMENT without further distinction, - # and both could be accepted -@region_device_count_count_11_sink_credential_invalid_token -Scenario: Invalid token - Given the request body property "$.sinkCredential.accessTokenType" is set to a value other than "bearer" - When the request "count" is sent - Then the response status code is 400 - And the response header "x-correlator" has same value as the request header "x-correlator" - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "INVALID_TOKEN" or "INVALID_ARGUMENT" - And the response property "$.message" contains a user friendly text + @region_device_count_count_14_missing_authorization_header + Scenario: Error response for no header "Authorization" + Given the header "Authorization" is not sent + And the request body is set to a valid request body + When the request "count" is sent + Then the response status code is 401 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 401 + And the response property "$.code" is "UNAUTHENTICATED" + And the response property "$.message" contains a user friendly text -@region_device_count_count_12_expired_access_token -Scenario: Error response for expired access token - Given an expired access token - And the request body is set to a valid request body - When the request "count" is sent - Then the response status code is 401 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text + # API Specific Errors + @region_device_count_count_15_time_interval_not_safisfiable + Scenario: Error response for Invalid Time Interval + Given the request body property "$.starttime" is set to a valid time and "$.endtime" is absent + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "REGION_DEVICE_COUNT.TIME_INVALID_ARGUMENT" + And the response property "$.message" contains a user friendly text -@region_device_count_count_13_invalid_access_token -Scenario: Error response for invalid access token - Given an invalid access token - And the request body is set to a valid request body - When the request "count" is sent - Then the response status code is 401 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text + @region_device_count_invalid_end_time + Scenario: Error 400 when endtime is set to a date earlier than starttime + Given the request body property "$.endtime" is set to a time earlier than request body property "$.starttime" + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_END_DATE" + And the response property "$.message" contains a user friendly text -@region_device_count_count_14_missing_authorization_header -Scenario: Error response for no header "Authorization" - Given the header "Authorization" is not sent - And the request body is set to a valid request body - When the request "count" is sent - Then the response status code is 401 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 401 - And the response property "$.code" is "UNAUTHENTICATED" - And the response property "$.message" contains a user friendly text + @region_device_count_count_16_invalid_circle_area + Scenario: Error response for Invalid Circle Area + Given the request body property "$.area.areaType" is set to "CIRCLE" + And the request body property "$.area.center" is missing + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_CIRCLE_AREA" + And the response property "$.message" contains a user friendly text -# API Specific Errors -@region_device_count_count_15_time_interval_not_safisfiable -Scenario: Error response for Invalid Time Interval - Given the request body property "$.starttime" is set to a valid time and "$.endtime" is absent - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "REGION_DEVICE_COUNT.TIME_INVALID_ARGUMENT" - And the response property "$.message" contains a user friendly text + @region_device_count_count_17_invalid_polygon_area + Scenario: Error response for Invalid Polygon Area + Given the request body property "$.area.areaType" is set to "POLYGON" + And the request body property "$.area.boundary" is set to an array of coordinates that does not form a polygon + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_POLYGON_AREA" + And the response property "$.message" contains a user friendly text -@region_device_count_invalid_end_time -Scenario: Error 400 when endtime is set to a date earlier than starttime -Given the request body property "$.endtime" is set to a time earlier than request body property "$.starttime" - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_END_DATE" - And the response property "$.message" contains a user friendly text + @region_device_count_count_18_too_complex_area + Scenario: Error 400 when the requested area is too complex + Given the request body property "$.area.boundary" is set to an array of coordinates that form a too complex area + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_AREA" + And the response property "$.message" contains a user friendly text -@region_device_count_count_16_invalid_circle_area -Scenario: Error response for Invalid Circle Area - Given the request body property "$.area.areaType" is set to "CIRCLE" - And the request body property "$.area.center" is missing - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_CIRCLE_AREA" - And the response property "$.message" contains a user friendly text + @region_device_count_count_19_unsupported_sync_response + Scenario: Error 400 when the response is unsupported for a sync response + Given the request body properties "$.area", "$.starttime" and "$.endtime" are set to values that generate a response too big for a synchronous response + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "REGION_DEVICE_COUNT.UNSUPPORTED_SYNC_RESPONSE" + And the response property "$.message" contains a user friendly text -@region_device_count_count_17_invalid_polygon_area -Scenario: Error response for Invalid Polygon Area - Given the request body property "$.area.areaType" is set to "POLYGON" - And the request body property "$.area.boundary" is set to an array of coordinates that does not form a polygon - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_POLYGON_AREA" - And the response property "$.message" contains a user friendly text - -@region_device_count_count_18_too_complex_area -Scenario: Error 400 when the requested area is too complex - Given the request body property "$.area.boundary" is set to an array of coordinates that form a too complex area - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "REGION_DEVICE_COUNT.INVALID_AREA" - And the response property "$.message" contains a user friendly text - - -@region_device_count_count_19_unsupported_sync_response -Scenario: Error 400 when the response is unsupported for a sync response - Given the request body properties "$.area", "$.starttime" and "$.endtime" are set to values that generate a response too big for a synchronous response - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "REGION_DEVICE_COUNT.UNSUPPORTED_SYNC_RESPONSE" - And the response property "$.message" contains a user friendly text - -@region_device_count_count_20_unsupported_request -Scenario: Error 400 when the response is too big for a sync and async response - Given the request body properties "$.area", "$.starttime" and "$.endtime" are set to values that generate a response too big for both synchronous and asynchronous responses - When the request "count" is sent - Then the response status code is 400 - And the response header "Content-Type" is "application/json" - And the response property "$.status" is 400 - And the response property "$.code" is "REGION_DEVICE_COUNT.UNSUPPPORTED_REQUEST" - And the response property "$.message" contains a user friendly text + @region_device_count_count_20_unsupported_request + Scenario: Error 400 when the response is too big for a sync and async response + Given the request body properties "$.area", "$.starttime" and "$.endtime" are set to values that generate a response too big for both synchronous and asynchronous responses + When the request "count" is sent + Then the response status code is 400 + And the response header "Content-Type" is "application/json" + And the response property "$.status" is 400 + And the response property "$.code" is "REGION_DEVICE_COUNT.UNSUPPPORTED_REQUEST" + And the response property "$.message" contains a user friendly text diff --git a/lint_function/camara-language-avoid-telco.js b/lint_function/camara-language-avoid-telco.js deleted file mode 100644 index b846ef6..0000000 --- a/lint_function/camara-language-avoid-telco.js +++ /dev/null @@ -1,40 +0,0 @@ -// 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 deleted file mode 100644 index 64257de..0000000 --- a/lint_function/camara-reserved-words.js +++ /dev/null @@ -1,98 +0,0 @@ -// 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 deleted file mode 100644 index e149352..0000000 --- a/lint_function/camara-security-no-secrets-in-path-or-query-parameters.js +++ /dev/null @@ -1,26 +0,0 @@ -// 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}`); - - } - } - } - } -}