-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Security Solution] Implement shared components conflict resolution functionality #188812
[Security Solution] Implement shared components conflict resolution functionality #188812
Conversation
423afab
to
8a9de00
Compare
Pinging @elastic/security-detections-response (Team:Detections and Resp) |
Pinging @elastic/security-solution (Team: SecuritySolution) |
Pinging @elastic/security-detection-rule-management (Team:Detection Rule Management) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DE changes LGTM! Not sure if we need, but maybe we could add tests around new shared components conflict resolution functionality.
8bf2baa
to
ee41473
Compare
@e40pud it's a good idea, I added tests. |
5e2414f
to
44e74bf
Compare
@xcrzx thank you for careful review and good suggestions 🙏 I addressed your comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for quickly resolving all the comments. LGTM 👍
ff32b84
to
76786d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @maximpn
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Unknown metric groupsESLint disabled in files
ESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: cc @maximpn |
…ce (#189472) **Resolves:** #188817 ## Summary This PR handles OpenAPI discriminator `mapping` (missing in #188812) field by prefixing local references with a namespace (see #188812 for more namespace details). It throws an error If mapping uses external references. ## How to test? Let's consider the following OpenAPI spec **spec1.schema.yaml** ```yaml openapi: 3.0.3 info: title: Spec1 version: '2023-10-31' paths: /api/some_api: get: responses: 200: content: 'application/json': schema: oneOf: - $ref: '#/components/schemas/Cat' - $ref: '#/components/schemas/Dog' - $ref: '#/components/schemas/Lizard' discriminator: propertyName: petType mapping: dog: '#/components/schemas/Dog' components: schemas: Pet: type: object required: [petType] properties: petType: type: string Cat: allOf: - $ref: '#/components/schemas/Pet' - type: object properties: name: type: string Dog: allOf: - $ref: '#/components/schemas/Pet' - type: object properties: bark: type: string Lizard: allOf: - $ref: '#/components/schemas/Pet' - type: object properties: lovesRocks: type: boolean ``` and a merging script ```js const { merge } = require('@kbn/openapi-bundler'); (async () => { await merge({ sourceGlobs: [ `path/to/spec1.schema.yaml`, ], outputFilePath: 'output.yaml, }); })(); ``` After running it it will produce the following bundler with references in `mapping` property prefixed with the spec title. ```yaml openapi: 3.0.3 info: title: Some title version: 1 paths: /api/some_api: get: responses: '200': content: application/json: schema: discriminator: mapping: dog: '#/components/schemas/Spec1_Dog' propertyName: petType oneOf: - $ref: '#/components/schemas/Spec1_Cat' - $ref: '#/components/schemas/Spec1_Dog' - $ref: '#/components/schemas/Spec1_Lizard' components: schemas: Spec1_Cat: allOf: - $ref: '#/components/schemas/Spec1_Pet' - type: object properties: name: type: string Spec1_Dog: allOf: - $ref: '#/components/schemas/Spec1_Pet' - type: object properties: bark: type: string Spec1_Lizard: allOf: - $ref: '#/components/schemas/Spec1_Pet' - type: object properties: lovesRocks: type: boolean Spec1_Pet: type: object properties: petType: type: string required: - petType ```
…unctionality (elastic#188812) **Resolves:** elastic#188817 This PR adds automatic shared components conflict resolution functionality for OpenAPI merger. It boils down to a similar result as `npx @redocly/cli join --prefix-components-with-info-prop title` produces by prefixing shared components with document's title in each source. OpenAPI bundler intentionally won't solve conflicts automatically since it's focused on bundling domain APIs where conflicts are usually indicators of upstream problems. While working with various OpenAPI specs it may happen that different specs use exactly the same name for some shared components but different definitions. It must be avoided inside one API domain but it's a usual situation when merging OpenAPI specs of different API domains. For example domains may define a shared `Id` or `404Response` schemas where `Id` is a string in one domain and a number in another. OpenAPI merger implemented in elastic#188110 and OpenAPI bundler implemented in elastic#171526 do not solve shared components related conflicts automatically. It works perfectly for a single API domain forcing engineers choosing shared schema names carefully. This PR adds automatic shared components conflict resolution for OpenAPI merger. It prefixes shared component names with a normalized document's title. OpenAPI bundler intentionally won't solve conflicts automatically since it's focused on bundling domain APIs where conflicts are usually indicators of upstream problems. Consider two following OpenAPI specs each defining local `MySchema` **spec1.schema.yaml** ```yaml openapi: 3.0.3 info: title: My endpoint version: '2023-10-31' paths: /api/some_api: get: operationId: MyEndpointGet responses: '200': content: application/json: schema: $ref: '#/components/schemas/MySchema' components: schemas: MySchema: type: string enum: - value1 ``` **spec2.schema.yaml** ```yaml openapi: 3.0.3 info: title: My another endpoint version: '2023-10-31' paths: /api/another_api: get: operationId: MyAnotherEndpointGet responses: '200': content: application/json: schema: $ref: '#/components/schemas/MySchema' components: schemas: MySchema: type: number ``` and a script to merge them ```js require('../../src/setup_node_env'); const { resolve } = require('path'); const { merge } = require('@kbn/openapi-bundler'); const { REPO_ROOT } = require('@kbn/repo-info'); (async () => { await merge({ sourceGlobs: [ `${REPO_ROOT}/oas_docs/spec1.schema.yaml`, `${REPO_ROOT}/oas_docs/spec2.schema.yaml`, ], outputFilePath: resolve(`${REPO_ROOT}/oas_docs/merged.yaml`), options: { mergedSpecInfo: { title: 'Merge result', version: 'my version', }, }, }); })(); ``` will be merged successfully to **merged.yaml** ```yaml openapi: 3.0.3 info: title: Merge result version: 'my version' paths: /api/another_api: get: operationId: MyAnotherEndpointGet responses: '200': content: application/json; Elastic-Api-Version=2023-10-31: schema: $ref: '#/components/schemas/My_another_endpoint_MySchema' /api/some_api: get: operationId: MyEndpointGet responses: '200': content: application/json; Elastic-Api-Version=2023-10-31: schema: $ref: '#/components/schemas/My_endpoint_MySchema' components: schemas: My_another_endpoint_MySchema: type: number My_endpoint_MySchema: enum: - value1 type: string ```
…ce (elastic#189472) **Resolves:** elastic#188817 ## Summary This PR handles OpenAPI discriminator `mapping` (missing in elastic#188812) field by prefixing local references with a namespace (see elastic#188812 for more namespace details). It throws an error If mapping uses external references. ## How to test? Let's consider the following OpenAPI spec **spec1.schema.yaml** ```yaml openapi: 3.0.3 info: title: Spec1 version: '2023-10-31' paths: /api/some_api: get: responses: 200: content: 'application/json': schema: oneOf: - $ref: '#/components/schemas/Cat' - $ref: '#/components/schemas/Dog' - $ref: '#/components/schemas/Lizard' discriminator: propertyName: petType mapping: dog: '#/components/schemas/Dog' components: schemas: Pet: type: object required: [petType] properties: petType: type: string Cat: allOf: - $ref: '#/components/schemas/Pet' - type: object properties: name: type: string Dog: allOf: - $ref: '#/components/schemas/Pet' - type: object properties: bark: type: string Lizard: allOf: - $ref: '#/components/schemas/Pet' - type: object properties: lovesRocks: type: boolean ``` and a merging script ```js const { merge } = require('@kbn/openapi-bundler'); (async () => { await merge({ sourceGlobs: [ `path/to/spec1.schema.yaml`, ], outputFilePath: 'output.yaml, }); })(); ``` After running it it will produce the following bundler with references in `mapping` property prefixed with the spec title. ```yaml openapi: 3.0.3 info: title: Some title version: 1 paths: /api/some_api: get: responses: '200': content: application/json: schema: discriminator: mapping: dog: '#/components/schemas/Spec1_Dog' propertyName: petType oneOf: - $ref: '#/components/schemas/Spec1_Cat' - $ref: '#/components/schemas/Spec1_Dog' - $ref: '#/components/schemas/Spec1_Lizard' components: schemas: Spec1_Cat: allOf: - $ref: '#/components/schemas/Spec1_Pet' - type: object properties: name: type: string Spec1_Dog: allOf: - $ref: '#/components/schemas/Spec1_Pet' - type: object properties: bark: type: string Spec1_Lizard: allOf: - $ref: '#/components/schemas/Spec1_Pet' - type: object properties: lovesRocks: type: boolean Spec1_Pet: type: object properties: petType: type: string required: - petType ```
…189262) (#190541) # Backport This will backport the bundler aspects of the following commits from `main` to `8.15`: - [[HTTP/OAS] Merge OpenAPI specs by using `kbn-openapi-bundler` (#189262)](#189262) - #189621 - #189482 - #189348 - #189472 - #188110 - #188812 <!--- Backport version: 8.9.8 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Maxim Palenov","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-08-13T10:45:35Z","message":"[HTTP/OAS] Merge OpenAPI specs by using `kbn-openapi-bundler` (#189262)\n\n**Addresses:** https://github.com/elastic/kibana/issues/186356\r\n**Relates to:** https://github.com/elastic/kibana/issues/184428\r\n\r\n## Summary\r\n\r\nThis PR adds a merging JS script based on the utility implemented in #186356. Resulted OpenAPI bundle as committed in `oas_docs/output/kibana.serverless.bundled.yaml`.\r\n\r\n## Details\r\n\r\nhttps://github.com//pull/188110 implements and exposes `merge` utility design to merge source OpenAPI specs without processing. It's has only a programmatic API. To merge OpenAPI specs it's required to add a JS script like below\r\n\r\n```js\r\nconst { merge } = require('@kbn/openapi-bundler');\r\n\r\n(async () => {\r\n await merge({\r\n sourceGlobs: [/* a list of source globs goes here */],\r\n outputFilePath: 'path/to/the/output/file.yaml',\r\n });\r\n})();\r\n```\r\n\r\nThe JS script added in this PR includes source OpenAPI specs presented in `oas_docs/makefile` plus Security Solution OpenAPI specs based on https://github.com/elastic/kibana/issues/184428.\r\n\r\n**To run** the script use the following command from Kibana root folder\r\n\r\n```bash\r\nnode ./oas_docs/scripts/merge_serverless_oas.js \r\n```\r\n\r\n## Known linting issues with Security Solution OpenAPI specs\r\n\r\nRunning Spectral OpenAPI linter on the result bundle shows a number of errors caused by `no-$ref-siblings` rule. This caused by the current code generator implementation which requires `default` property to be set next to `$ref` though it's not correct for OpenAPI `3.0.3` while it's allowed in `3.1`. It seems that Bump.sh handles such cases properly though by properly showing a default value.\r\n\r\nWe need to analyze the problem and decide if/when we should fix it.\r\n\r\nThe rest of warnings look fixable and will be addressed in the next stage after setting up linter rules.\r\n\r\n## Next steps\r\n\r\nSince `@kbn/openapi-bundler` package is tailored specifically for Kibana it should replace Redocly currently used to merge OpenAPI specs. It also means `oas_docs/makefile` should be superseded by JS script(s) using `merge` utility form `@kbn/openapi-bundler` package.\r\n\r\n`@kbn/openapi-bundler` SHOULD NOT replace OpenAPI linters since it doesn't perform thorough linting. It's good if we continue adopting `spectral-cli` for linting purposes.","sha":"7a2e7bef9644eaf04fd820d16b8ee137b3c00f2b","branchLabelMapping":{"^v8.16.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Core","release_note:skip","backport:skip","docs","Team: SecuritySolution","Feature:OAS","v8.16.0"],"number":189262,"url":"https://github.com/elastic/kibana/pull/189262","mergeCommit":{"message":"[HTTP/OAS] Merge OpenAPI specs by using `kbn-openapi-bundler` (#189262)\n\n**Addresses:** https://github.com/elastic/kibana/issues/186356\r\n**Relates to:** https://github.com/elastic/kibana/issues/184428\r\n\r\n## Summary\r\n\r\nThis PR adds a merging JS script based on the utility implemented in #186356. Resulted OpenAPI bundle as committed in `oas_docs/output/kibana.serverless.bundled.yaml`.\r\n\r\n## Details\r\n\r\nhttps://github.com//pull/188110 implements and exposes `merge` utility design to merge source OpenAPI specs without processing. It's has only a programmatic API. To merge OpenAPI specs it's required to add a JS script like below\r\n\r\n```js\r\nconst { merge } = require('@kbn/openapi-bundler');\r\n\r\n(async () => {\r\n await merge({\r\n sourceGlobs: [/* a list of source globs goes here */],\r\n outputFilePath: 'path/to/the/output/file.yaml',\r\n });\r\n})();\r\n```\r\n\r\nThe JS script added in this PR includes source OpenAPI specs presented in `oas_docs/makefile` plus Security Solution OpenAPI specs based on https://github.com/elastic/kibana/issues/184428.\r\n\r\n**To run** the script use the following command from Kibana root folder\r\n\r\n```bash\r\nnode ./oas_docs/scripts/merge_serverless_oas.js \r\n```\r\n\r\n## Known linting issues with Security Solution OpenAPI specs\r\n\r\nRunning Spectral OpenAPI linter on the result bundle shows a number of errors caused by `no-$ref-siblings` rule. This caused by the current code generator implementation which requires `default` property to be set next to `$ref` though it's not correct for OpenAPI `3.0.3` while it's allowed in `3.1`. It seems that Bump.sh handles such cases properly though by properly showing a default value.\r\n\r\nWe need to analyze the problem and decide if/when we should fix it.\r\n\r\nThe rest of warnings look fixable and will be addressed in the next stage after setting up linter rules.\r\n\r\n## Next steps\r\n\r\nSince `@kbn/openapi-bundler` package is tailored specifically for Kibana it should replace Redocly currently used to merge OpenAPI specs. It also means `oas_docs/makefile` should be superseded by JS script(s) using `merge` utility form `@kbn/openapi-bundler` package.\r\n\r\n`@kbn/openapi-bundler` SHOULD NOT replace OpenAPI linters since it doesn't perform thorough linting. It's good if we continue adopting `spectral-cli` for linting purposes.","sha":"7a2e7bef9644eaf04fd820d16b8ee137b3c00f2b"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.16.0","labelRegex":"^v8.16.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/189262","number":189262,"mergeCommit":{"message":"[HTTP/OAS] Merge OpenAPI specs by using `kbn-openapi-bundler` (#189262)\n\n**Addresses:** https://github.com/elastic/kibana/issues/186356\r\n**Relates to:** https://github.com/elastic/kibana/issues/184428\r\n\r\n## Summary\r\n\r\nThis PR adds a merging JS script based on the utility implemented in #186356. Resulted OpenAPI bundle as committed in `oas_docs/output/kibana.serverless.bundled.yaml`.\r\n\r\n## Details\r\n\r\nhttps://github.com//pull/188110 implements and exposes `merge` utility design to merge source OpenAPI specs without processing. It's has only a programmatic API. To merge OpenAPI specs it's required to add a JS script like below\r\n\r\n```js\r\nconst { merge } = require('@kbn/openapi-bundler');\r\n\r\n(async () => {\r\n await merge({\r\n sourceGlobs: [/* a list of source globs goes here */],\r\n outputFilePath: 'path/to/the/output/file.yaml',\r\n });\r\n})();\r\n```\r\n\r\nThe JS script added in this PR includes source OpenAPI specs presented in `oas_docs/makefile` plus Security Solution OpenAPI specs based on https://github.com/elastic/kibana/issues/184428.\r\n\r\n**To run** the script use the following command from Kibana root folder\r\n\r\n```bash\r\nnode ./oas_docs/scripts/merge_serverless_oas.js \r\n```\r\n\r\n## Known linting issues with Security Solution OpenAPI specs\r\n\r\nRunning Spectral OpenAPI linter on the result bundle shows a number of errors caused by `no-$ref-siblings` rule. This caused by the current code generator implementation which requires `default` property to be set next to `$ref` though it's not correct for OpenAPI `3.0.3` while it's allowed in `3.1`. It seems that Bump.sh handles such cases properly though by properly showing a default value.\r\n\r\nWe need to analyze the problem and decide if/when we should fix it.\r\n\r\nThe rest of warnings look fixable and will be addressed in the next stage after setting up linter rules.\r\n\r\n## Next steps\r\n\r\nSince `@kbn/openapi-bundler` package is tailored specifically for Kibana it should replace Redocly currently used to merge OpenAPI specs. It also means `oas_docs/makefile` should be superseded by JS script(s) using `merge` utility form `@kbn/openapi-bundler` package.\r\n\r\n`@kbn/openapi-bundler` SHOULD NOT replace OpenAPI linters since it doesn't perform thorough linting. It's good if we continue adopting `spectral-cli` for linting purposes.","sha":"7a2e7bef9644eaf04fd820d16b8ee137b3c00f2b"}}]}] BACKPORT--> --------- Co-authored-by: Maxim Palenov <[email protected]>
Resolves: #188817
Summary
This PR adds automatic shared components conflict resolution functionality for OpenAPI merger. It boils down to a similar result as
npx @redocly/cli join --prefix-components-with-info-prop title
produces by prefixing shared components with document's title in each source.OpenAPI bundler intentionally won't solve conflicts automatically since it's focused on bundling domain APIs where conflicts are usually indicators of upstream problems.
Details
While working with various OpenAPI specs it may happen that different specs use exactly the same name for some shared components but different definitions. It must be avoided inside one API domain but it's a usual situation when merging OpenAPI specs of different API domains. For example domains may define a shared
Id
or404Response
schemas whereId
is a string in one domain and a number in another.OpenAPI merger implemented in #188110 and OpenAPI bundler implemented in #171526 do not solve shared components related conflicts automatically. It works perfectly for a single API domain forcing engineers choosing shared schema names carefully.
This PR adds automatic shared components conflict resolution for OpenAPI merger. It prefixes shared component names with a normalized document's title.
OpenAPI bundler intentionally won't solve conflicts automatically since it's focused on bundling domain APIs where conflicts are usually indicators of upstream problems.
Example
Consider two following OpenAPI specs each defining local
MySchema
spec1.schema.yaml
spec2.schema.yaml
and a script to merge them
will be merged successfully to
merged.yaml