From 53adef6671fc5b9e88bf23b4ca2aed99bdc278ed Mon Sep 17 00:00:00 2001 From: frantuma Date: Thu, 27 Oct 2022 22:39:03 +0200 Subject: [PATCH] fix internal references validation for nested schemas --- .../v3/parser/util/OpenAPIDeserializer.java | 10 ++- .../v3/parser/test/OpenAPIV3ParserTest.java | 8 ++ .../src/test/resources/internal-refs.yaml | 76 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 modules/swagger-parser-v3/src/test/resources/internal-refs.yaml diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java index 07ad4fd57b..e5ae493f33 100644 --- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java +++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java @@ -332,6 +332,10 @@ public OpenAPI parseRoot(JsonNode node, ParseResult result, String path) { openAPI.setComponents(components); this.components = components; if(result.validateInternalRefs) { + /* TODO currently only capable of validating if ref is to root schema withing #/components/schemas + * need to evaluate json pointer instead to also allow validation of nested schemas + * e.g. #/components/schemas/foo/properties/bar + */ for (String schema : localSchemaRefs.keySet()) { if (components.getSchemas().get(schema) == null) { result.invalidType(localSchemaRefs.get(schema), schema, "schema", rootNode); @@ -2763,7 +2767,11 @@ at the moment path passed as string (basePath) from upper components can be both } else { schema.set$ref(ref.asText()); } - if(schema.get$ref().startsWith("#/components/schemas")){// it's internal + /* TODO currently only capable of validating if ref is to root schema withing #/components/schemas + * need to evaluate json pointer instead to also allow validation of nested schemas + * e.g. #/components/schemas/foo/properties/bar + */ + if(schema.get$ref().startsWith("#/components/schemas") && StringUtils.countMatches(schema.get$ref(), "/") == 3){ String refName = schema.get$ref().substring(schema.get$ref().lastIndexOf("/")+1); localSchemaRefs.put(refName,location); } diff --git a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java index 148bfe66d2..35dbf99de8 100644 --- a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java +++ b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java @@ -3362,4 +3362,12 @@ public void testNullExample() throws Exception{ Assert.assertNotNull(openAPI); assertEquals(Yaml.pretty(openAPI), yamlStringResolved); } + + @Test + public void testInternalRefsValidation() throws Exception { + String yamlString = FileUtils.readFileToString(new File("src/test/resources/internal-refs.yaml"), "UTF-8"); + ParseOptions options = new ParseOptions(); + SwaggerParseResult parseResult = new OpenAPIV3Parser().readContents(yamlString, null, options); + assertEquals(parseResult.getMessages().size(), 1); + } } diff --git a/modules/swagger-parser-v3/src/test/resources/internal-refs.yaml b/modules/swagger-parser-v3/src/test/resources/internal-refs.yaml new file mode 100644 index 0000000000..9b97b5f773 --- /dev/null +++ b/modules/swagger-parser-v3/src/test/resources/internal-refs.yaml @@ -0,0 +1,76 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: test +paths: {} +components: + schemas: + MemberRef: + description: Provides basic ID info about a member with an href to the full object + type: object + properties: + uuid: + description: "Uniquely identifies a member across the entire platform" + type: string + format: uuid + minLength: 36 + maxLength: 36 + example: "26a0bac8-5c37-4c54-b3b1-1ad4551db061" + alt_id: + description: "An ID defined for a member, typically provided by a customer during integration, which will be unique within a given group." + type: string + minLength: 1 + maxLength: 36 + example: "ABC-123" + group: + $ref: "#/components/schemas/MemberGroup" + href: + type: string + format: uri + readOnly: true + anyOf: + - required: ["uuid"] + properties: + uuid: + $ref: "#/components/schemas/MemberRef/properties/uuid" + alt_id: + $ref: "#/components/schemas/MemberRef/properties/alt_id" + group: + $ref: "#/components/schemas/MemberRef/properties/group" + href: + $ref: "#/components/schemas/MemberRef/properties/href" + - required: ["alt_id", "group"] + properties: + uuid: + $ref: "#/components/schemas/MemberRef/properties/uuid" + alt_id: + $ref: "#/components/schemas/MemberRef/properties/alt_id" + group: + $ref: "#/components/schemas/MemberRef/properties/group" + href: + $ref: "#/components/schemas/MemberRef/properties/href" + MemberSmall: + description: >- + Provides abbreviated information about a member and is used when returning an array of members + readOnly: true + properties: + uuid: + $ref: "#/components/schemas/MemberRef/properties/uuid" + alt_id: + $ref: "#/components/schemas/MemberRef/properties/alt_id" + group: + $ref: "#/components/schemas/MemberRef/properties/group" + href: + $ref: "#/components/schemas/MemberRef/properties/href" + activated: + description: >- + Indicates that the member has logged into their account + type: boolean + example: true + disabled: + description: >- + Indicates that the member's account is disabled and they will no longer be able to login + type: boolean + example: false + + \ No newline at end of file