diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 44ae4d602..27eb18d23 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -30,13 +30,13 @@ jobs: id: getversion - name: Push to GitHub Packages - Nightly if: ${{ github.ref == 'refs/heads/vnext' }} - uses: docker/build-push-action@v5.4.0 + uses: docker/build-push-action@v6.1.0 with: push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly - name: Push to GitHub Packages - Release if: ${{ github.ref == 'refs/heads/master' }} - uses: docker/build-push-action@v5.4.0 + uses: docker/build-push-action@v6.1.0 with: push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.getversion.outputs.version }} diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj index 01e5c1427..7162a07e9 100644 --- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj +++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj @@ -9,7 +9,7 @@ enable hidi ./../../artifacts - 1.4.5 + 1.4.6 OpenAPI.NET CLI tool for slicing OpenAPI documents true @@ -35,7 +35,7 @@ - + diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs index 8b10bb83f..790940759 100644 --- a/src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs +++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Collections.Generic; @@ -113,11 +113,11 @@ public static IOpenApiAny LoadAny(ParseNode node) private static IOpenApiExtension LoadExtension(string name, ParseNode node) { - if (node.Context.ExtensionParsers.TryGetValue(name, out var parser)) + if (node.Context.ExtensionParsers.TryGetValue(name, out var parser) && parser( + OpenApiAnyConverter.GetSpecificOpenApiAny(node.CreateAny()), + OpenApiSpecVersion.OpenApi2_0) is { } result) { - return parser( - OpenApiAnyConverter.GetSpecificOpenApiAny(node.CreateAny()), - OpenApiSpecVersion.OpenApi2_0); + return result; } else { diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiV3Deserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiV3Deserializer.cs index 79b5f0671..558864854 100644 --- a/src/Microsoft.OpenApi.Readers/V3/OpenApiV3Deserializer.cs +++ b/src/Microsoft.OpenApi.Readers/V3/OpenApiV3Deserializer.cs @@ -171,11 +171,11 @@ public static IOpenApiAny LoadAny(ParseNode node) private static IOpenApiExtension LoadExtension(string name, ParseNode node) { - if (node.Context.ExtensionParsers.TryGetValue(name, out var parser)) + if (node.Context.ExtensionParsers.TryGetValue(name, out var parser) && parser( + OpenApiAnyConverter.GetSpecificOpenApiAny(node.CreateAny()), + OpenApiSpecVersion.OpenApi3_0) is { } result) { - return parser( - OpenApiAnyConverter.GetSpecificOpenApiAny(node.CreateAny()), - OpenApiSpecVersion.OpenApi3_0); + return result; } else { diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs index 25a3b56a5..683082e2c 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs @@ -78,7 +78,7 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// When the source element is not an object public static OpenApiDeprecationExtension Parse(IOpenApiAny source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not OpenApiObject rawObject) return null; var extension = new OpenApiDeprecationExtension(); if (rawObject.TryGetValue(nameof(RemovalDate).ToFirstCharacterLowerCase(), out var removalDate) && removalDate is OpenApiDateTime removalDateValue) extension.RemovalDate = removalDateValue.Value; diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs index e7dcf88f8..946537478 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs @@ -45,7 +45,7 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// When the source element is not an object public static OpenApiEnumFlagsExtension Parse(IOpenApiAny source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not OpenApiObject rawObject) return null; var extension = new OpenApiEnumFlagsExtension(); if (rawObject.TryGetValue(nameof(IsFlags).ToFirstCharacterLowerCase(), out var flagsValue) && flagsValue is OpenApiBoolean isFlags) { diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs index 5c7c1ba31..272f4b313 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs @@ -64,7 +64,7 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// When the source element is not an object public static OpenApiEnumValuesDescriptionExtension Parse(IOpenApiAny source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not OpenApiObject rawObject) return null; var extension = new OpenApiEnumValuesDescriptionExtension(); if (rawObject.TryGetValue("values", out var values) && values is OpenApiArray valuesArray) { diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs index a73ecf005..9b81e2561 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs @@ -73,7 +73,7 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// When the source element is not an object public static OpenApiPagingExtension Parse(IOpenApiAny source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not OpenApiObject rawObject) return null; var extension = new OpenApiPagingExtension(); if (rawObject.TryGetValue(nameof(NextLinkName).ToFirstCharacterLowerCase(), out var nextLinkName) && nextLinkName is OpenApiString nextLinkNameStr) { diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs index fde7a54ea..0250af758 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------ +// ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ @@ -39,7 +39,7 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// The . public static OpenApiPrimaryErrorMessageExtension Parse(IOpenApiAny source) { - if (source is not OpenApiBoolean rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not OpenApiBoolean rawObject) return null; return new() { IsPrimaryErrorMessage = rawObject.Value diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs index 77428e186..e45d9e7e9 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs @@ -41,7 +41,7 @@ public bool? IsReserved /// public static OpenApiReservedParameterExtension Parse(IOpenApiAny source) { - if (source is not OpenApiBoolean rawBoolean) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not OpenApiBoolean rawBoolean) return null; return new() { IsReserved = rawBoolean.Value diff --git a/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs b/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs index abf945258..1a9ab3014 100644 --- a/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs +++ b/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs @@ -124,7 +124,7 @@ internal static string InvalidReferenceId { } /// - /// Looks up a localized string similar to Invalid Reference Type.. + /// Looks up a localized string similar to Invalid Reference Type '{0}'.. /// internal static string InvalidReferenceType { get { @@ -340,7 +340,7 @@ internal static string Validation_PathItemMustBeginWithSlash { } /// - /// Looks up a localized string similar to The path signature '{0}' MUST begin be unique.. + /// Looks up a localized string similar to The path signature '{0}' MUST be unique.. /// internal static string Validation_PathSignatureMustBeUnique { get { diff --git a/src/Microsoft.OpenApi/Properties/SRResource.resx b/src/Microsoft.OpenApi/Properties/SRResource.resx index 38c4763d4..f0bb497d3 100644 --- a/src/Microsoft.OpenApi/Properties/SRResource.resx +++ b/src/Microsoft.OpenApi/Properties/SRResource.resx @@ -139,7 +139,7 @@ Invalid Reference identifier '{0}'. - Invalid Reference Type. + Invalid Reference Type '{0}'. Local reference must have type specified. diff --git a/src/Microsoft.OpenApi/Services/OpenApiReferenceResolver.cs b/src/Microsoft.OpenApi/Services/OpenApiReferenceResolver.cs index dd98b4317..00c069f30 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiReferenceResolver.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiReferenceResolver.cs @@ -259,6 +259,13 @@ private void ResolveTags(IList tags) { try { + var referencedObject = typeof(T).Name; + var referenceType = reference?.Type.ToString(); + if (referenceType is not null && !referencedObject.Contains(referenceType)) + { + throw new OpenApiException(string.Format(Properties.SRResource.InvalidReferenceType, referenceType)); + } + return _currentDocument.ResolveReference(reference, false) as T; } catch (OpenApiException ex) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index a9401897b..d67c0054f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -9,8 +9,10 @@ using System.Threading; using FluentAssertions; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Readers.Interface; using Microsoft.OpenApi.Validations; using Microsoft.OpenApi.Validations.Rules; using Microsoft.OpenApi.Writers; @@ -1355,5 +1357,15 @@ public void ValidateExampleShouldNotHaveDataTypeMismatch() var warnings = diagnostic.Warnings; Assert.False(warnings.Any()); } + + [Fact] + public void ParseDocumetWithWrongReferenceTypeShouldReturnADiagnosticError() + { + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "docWithWrongRef.json")); + _ = new OpenApiStreamReader().Read(stream, out var diagnostic); + + diagnostic.Errors.Should().BeEquivalentTo(new List { + new( new OpenApiException("Invalid Reference Type 'Schema'.")) }); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/docWithWrongRef.json b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/docWithWrongRef.json new file mode 100644 index 000000000..6edf46be8 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/docWithWrongRef.json @@ -0,0 +1,27 @@ +{ + "openapi":"3.0.0", + "info":{ + "title":"some api", + "description":"some description", + "version": "1" + }, + "servers":[{"url":"https://localhost"}], + "paths":{ + "/count":{ + "get":{ + "responses":{ + "200":{ + "$ref":"#/components/schemas/count" + }, + }, + } + } + }, + "components":{ + "schemas":{ + "count":{ + "type": "number" + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj index a516ec7e5..351a72df4 100644 --- a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj +++ b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs index ca7870bc0..0ebeea11a 100644 --- a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs +++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs @@ -17,6 +17,19 @@ public void Parses() Assert.NotNull(value); Assert.True(value.IsReserved); } + + [Fact] + public void DoesNotThrowExceptionIfValueIsNull() + { + var oaiValue = new OpenApiObject + { + ["foo"] = new OpenApiString("foo") + }; + + var value = OpenApiReservedParameterExtension.Parse(oaiValue); + Assert.Null(value); + } + [Fact] public void Serializes() {