diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2ecc109360..07bb0090a0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -20,6 +20,10 @@ updates: schedule: interval: weekly day: tuesday + groups: + spectral: + patterns: + - "@stoplight/spectral-*" commit-message: prefix: "chore" - package-ecosystem: npm diff --git a/.github/workflows/optional-spec-validations.yml b/.github/workflows/optional-spec-validations.yml index 6cf63e6f14..1a3bf15a2f 100644 --- a/.github/workflows/optional-spec-validations.yml +++ b/.github/workflows/optional-spec-validations.yml @@ -2,10 +2,6 @@ name: 'Optional Spec Validations' on: workflow_call: inputs: - spectral_version: - description: 'Version of Spectral to use' - type: string - required: true env: description: 'Environment to generate the OpenAPI Spec for.' required: true @@ -17,11 +13,6 @@ on: required: true workflow_dispatch: inputs: - spectral_version: - description: 'Version of Spectral to use' - type: string - required: true - default: 'latest' env: description: 'Environment to validate the OpenAPI Spec for.' type: choice @@ -49,7 +40,7 @@ jobs: node-version: '20.x' cache: 'npm' - name: Install npm dependencies - run: npm install + run: npm ci - name: Download openapi-foas uses: actions/download-artifact@v8 with: @@ -58,14 +49,12 @@ jobs: run-id: ${{ github.run_id }} - name: Validate the FOAS can be used to generate Postman collection id: spectral-validation - env: - SPECTRAL_VERSION: ${{ inputs.spectral_version }} run: | cp -rf "openapi-foas.json" "./tools/postman/openapi/atlas-api.json" pushd tools/postman make convert_to_collection - npx -- @stoplight/spectral-cli@"${SPECTRAL_VERSION}" lint ./tmp/collection.json --ruleset=./validation/spectral.yaml popd + npm run spectral-lint -- ./tools/postman/tmp/collection.json --ruleset=./tools/postman/validation/spectral.yaml retry-handler: needs: [ optional-validations ] diff --git a/.github/workflows/release-spec-runner.yml b/.github/workflows/release-spec-runner.yml index f3d27ceb9b..91cd74863f 100644 --- a/.github/workflows/release-spec-runner.yml +++ b/.github/workflows/release-spec-runner.yml @@ -59,7 +59,6 @@ jobs: aws_s3_role_to_assume: ${{ vars.AWS_S3_ROLE_TO_ASSUME }} env: dev branch: dev - spectral_version: ${{ vars.SPECTRAL_VERSION }} foascli_version: ${{ vars.FOASCLI_VERSION }} atlas_admin_v2_doc_id: ${{vars.ATLAS_ADMIN_V2_DOC_ID_DEV }} @@ -79,7 +78,6 @@ jobs: aws_s3_bucket: ${{ vars.S3_BUCKET_QA}} env: qa branch: qa - spectral_version: ${{ vars.SPECTRAL_VERSION }} foascli_version: ${{ vars.FOASCLI_VERSION }} atlas_admin_v2_doc_id: ${{vars.ATLAS_ADMIN_V2_DOC_ID_QA }} @@ -99,7 +97,6 @@ jobs: aws_s3_bucket: ${{ vars.S3_BUCKET_STAGING}} env: stage branch: staging - spectral_version: ${{ vars.SPECTRAL_VERSION }} foascli_version: ${{ vars.FOASCLI_VERSION }} atlas_admin_v2_doc_id: ${{vars.ATLAS_ADMIN_V2_DOC_ID_STAGING }} @@ -121,7 +118,6 @@ jobs: aws_s3_bucket: ${{ vars.S3_BUCKET_PROD}} env: prod branch: main - spectral_version: ${{ vars.SPECTRAL_VERSION }} foascli_version: ${{ vars.FOASCLI_VERSION }} atlas_prod_base_url: ${{ vars.ATLAS_PROD_BASE_URL }} atlas_admin_v2_doc_id: ${{vars.ATLAS_ADMIN_V2_DOC_ID }} diff --git a/.github/workflows/release-spec.yml b/.github/workflows/release-spec.yml index e94c33622f..98378a849d 100644 --- a/.github/workflows/release-spec.yml +++ b/.github/workflows/release-spec.yml @@ -18,10 +18,6 @@ on: description: 'Branch to release the OpenAPI Spec to.' required: true type: string - spectral_version: - description: 'Version of Spectral to use.' - required: true - type: string foascli_version: description: 'Version of FOASCLI to use.' required: true @@ -86,7 +82,6 @@ jobs: secrets: api_bot_pat: ${{ secrets.api_bot_pat }} with: - spectral_version: ${{ inputs.spectral_version }} env: ${{ inputs.env }} # Optional validations won't stop the release but only open a GH issue if they fail @@ -99,7 +94,6 @@ jobs: jira_api_token: ${{ secrets.jira_api_token }} with: env: ${{ inputs.env }} - spectral_version: ${{ vars.SPECTRAL_VERSION }} release: name: Release OpenAPI Spec for V2 APIs diff --git a/.github/workflows/required-spec-validations.yml b/.github/workflows/required-spec-validations.yml index 5e5e50432b..5a97d2be49 100644 --- a/.github/workflows/required-spec-validations.yml +++ b/.github/workflows/required-spec-validations.yml @@ -2,10 +2,6 @@ name: 'Required Spec Validations' on: workflow_call: inputs: - spectral_version: - description: 'Version of Spectral to use' - type: string - required: true env: description: 'Environment to generate the OpenAPI Spec for.' required: true @@ -28,7 +24,7 @@ jobs: node-version: '22.x' cache: 'npm' - name: Install npm dependencies - run: npm install + run: npm ci - name: Download openapi-foas uses: actions/download-artifact@v8 with: @@ -37,13 +33,10 @@ jobs: run-id: ${{ github.run_id }} - name: Run IPA validation id: ipa-spectral-validation - run: | - npx spectral lint openapi-foas.json --ruleset=./tools/spectral/ipa/ipa-spectral.yaml - - name: Run + run: npm run spectral-lint -- openapi-foas.json --ruleset=./tools/spectral/ipa/ipa-spectral.yaml + - name: Run Spectral validation id: spectral-validation - env: - SPECTRAL_VERSION: ${{ inputs.spectral_version }} - run: npx -- @stoplight/spectral-cli@"${SPECTRAL_VERSION}" lint openapi-foas.yaml --ruleset=tools/spectral/.spectral.yaml + run: npm run spectral-lint -- openapi-foas.yaml --ruleset=tools/spectral/.spectral.yaml - name: Install Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e with: diff --git a/.github/workflows/spectral-lint.yml b/.github/workflows/spectral-lint.yml index e71b9ee608..b7d2c098dd 100644 --- a/.github/workflows/spectral-lint.yml +++ b/.github/workflows/spectral-lint.yml @@ -33,7 +33,7 @@ jobs: node-version: '20.x' cache: 'npm' - name: Install npm dependencies - run: npm install + run: npm ci - name: Fetch OAS file from Dev Branch run: curl -O "https://raw.githubusercontent.com/mongodb/openapi/refs/heads/dev/openapi/.raw/v2.yaml" working-directory: ${{ github.workspace }} @@ -44,5 +44,4 @@ jobs: file_glob: openapi/.raw/v2.yaml spectral_ruleset: tools/spectral/.spectral.yaml #If updated, need to update in MMS too. - name: IPA validation action - run: npx spectral lint v2.yaml --ruleset=./tools/spectral/ipa/ipa-spectral.yaml - \ No newline at end of file + run: npm run spectral-lint -- v2.yaml --ruleset=./tools/spectral/ipa/ipa-spectral.yaml diff --git a/package-lock.json b/package-lock.json index 11fb693a56..ac4ba4d07a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,11 +7,12 @@ "name": "mongodb-openapi", "dependencies": { "@aws-sdk/client-s3": "^3.1101.0", - "@stoplight/spectral-cli": "^6.16.1", - "@stoplight/spectral-core": "^1.23.1", - "@stoplight/spectral-functions": "^1.10.5", - "@stoplight/spectral-ref-resolver": "^1.0.5", - "@stoplight/spectral-ruleset-bundler": "^1.7.0", + "@stoplight/spectral-cli": "6.16.1", + "@stoplight/spectral-core": "1.23.1", + "@stoplight/spectral-functions": "1.10.5", + "@stoplight/spectral-ref-resolver": "1.0.5", + "@stoplight/spectral-ruleset-bundler": "1.7.0", + "@stoplight/spectral-rulesets": "1.22.7", "apache-arrow": "^21.2.0", "dotenv": "^17.4.2", "eslint-plugin-jest": "^29.16.0", @@ -44,9 +45,9 @@ } }, "node_modules/@asyncapi/specs": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.8.0.tgz", - "integrity": "sha512-1i6xs8+IOh6U5T7yH+bCMGQBF+m7kP/NpwyAlt++XaDQutoGCgACf24mQBgcDVqDWWoY81evQv+9ABvw0BviVg==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.11.1.tgz", + "integrity": "sha512-A3WBLqAKGoJ2+6FWFtpjBlCQ1oFCcs4GxF7zsIGvNqp/klGUHjlA3aAcZ9XMMpLGE8zPeYDz2x9FmO6DSuKraQ==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.11" @@ -5055,25 +5056,26 @@ "license": "Apache-2.0" }, "node_modules/@stoplight/spectral-rulesets": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.21.3.tgz", - "integrity": "sha512-SQp/NNDykfCvgmo9DW1pBAbmyKRHhEHmsc28kuRHC6nJblGFsLyNVGkEDjSIJuviR7ooC2Y00vmf0R3OGcyhyw==", + "version": "1.22.7", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.22.7.tgz", + "integrity": "sha512-cT1B6Ly21923lvr235lu7iIgmcnoCTJaN3ANOyTqr4D5GA/4p2k0+yhjhdfj/1ks/Os3kUzSFnFkzpWH7WszFA==", "license": "Apache-2.0", "dependencies": { - "@asyncapi/specs": "^6.8.0", + "@asyncapi/specs": "6.11.1", + "@scarf/scarf": "^1.4.0", "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "^3.17.0", - "@stoplight/spectral-core": "^1.19.4", + "@stoplight/spectral-core": "^1.23.0", "@stoplight/spectral-formats": "^1.8.1", "@stoplight/spectral-functions": "^1.9.1", "@stoplight/spectral-runtime": "^1.1.2", "@stoplight/types": "^13.6.0", "@types/json-schema": "^7.0.7", - "ajv": "^8.17.1", - "ajv-formats": "~2.1.0", + "ajv": "^8.18.0", + "ajv-formats": "~2.1.1", "json-schema-traverse": "^1.0.0", "leven": "3.1.0", - "lodash": "~4.17.21", + "lodash": "^4.18.1", "tslib": "^2.8.1" }, "engines": { @@ -5093,6 +5095,12 @@ "node": "^12.20 || >=14.13" } }, + "node_modules/@stoplight/spectral-rulesets/node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, "node_modules/@stoplight/spectral-runtime": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@stoplight/spectral-runtime/-/spectral-runtime-1.1.3.tgz", diff --git a/package.json b/package.json index 0903894da7..e086615b31 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "gen-ipa-docs": "node tools/spectral/ipa/scripts/generateRulesetReadme.js", "ipa-validation": "spectral lint ./openapi/.raw/v2.yaml --ruleset=./tools/spectral/ipa/ipa-spectral.yaml", "ipa-filter-violations": "node tools/spectral/ipa/scripts/filter-ipa-violations.js", + "spectral-lint": "spectral lint", "spectral-validation": "spectral lint ./openapi/.raw/v2.yaml --ruleset=./tools/spectral/.spectral.yaml", "test": "jest", "precommit": "husky" @@ -24,11 +25,12 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.1101.0", - "@stoplight/spectral-cli": "^6.16.1", - "@stoplight/spectral-core": "^1.23.1", - "@stoplight/spectral-functions": "^1.10.5", - "@stoplight/spectral-ref-resolver": "^1.0.5", - "@stoplight/spectral-ruleset-bundler": "^1.7.0", + "@stoplight/spectral-cli": "6.16.1", + "@stoplight/spectral-core": "1.23.1", + "@stoplight/spectral-functions": "1.10.5", + "@stoplight/spectral-ref-resolver": "1.0.5", + "@stoplight/spectral-ruleset-bundler": "1.7.0", + "@stoplight/spectral-rulesets": "1.22.7", "apache-arrow": "^21.2.0", "dotenv": "^17.4.2", "eslint-plugin-jest": "^29.16.0", diff --git a/tools/spectral/__tests__/spectralNullExample.test.js b/tools/spectral/__tests__/spectralNullExample.test.js new file mode 100644 index 0000000000..de412ee3fe --- /dev/null +++ b/tools/spectral/__tests__/spectralNullExample.test.js @@ -0,0 +1,43 @@ +import { Spectral } from '@stoplight/spectral-core'; +import { oas } from '@stoplight/spectral-rulesets'; + +describe('Spectral OAS ruleset compatibility', () => { + it('does not crash when a request-body example contains a null value', async () => { + const spectral = new Spectral(); + spectral.setRuleset(oas); + + const document = { + openapi: '3.0.3', + info: { + title: 'Null example regression', + version: '1.0.0', + }, + paths: { + '/dashboards/import': { + post: { + responses: { + 200: { + description: 'OK', + }, + }, + requestBody: { + content: { + 'application/json': { + example: { + items: { + 'item-1': { + query: null, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }; + + await expect(spectral.run(JSON.stringify(document))).resolves.toEqual(expect.any(Array)); + }); +});