Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1bace68

Browse filesBrowse files
baywetCopilot
andcommitted
fix(library): avoid false circular refs for external schema re-exports
Fixes #2872. The false positive came from workspace schema registration preferring item.Value.Id for component aliases. For OpenApiSchemaReference values, reading Id eagerly dereferenced the external target during registration, which triggered "Circular reference detected while resolving schema" for a root schema re-export plus a direct external reference. This faulty behavior traces back to PR #1826, which introduced the item.Value.Id ?? fallback to support JSON Schema identifier-based resolution. Under JSON Schema 2020-12, JSON Pointer still identifies a lexical location in the containing document, but $id establishes the canonical schema resource URI. This change preserves explicit $id alias registration for concrete schemas while always registering component keys for schema references so workspace registration does not resolve refs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b215087 commit 1bace68
Copy full SHA for 1bace68

2 files changed

+75-1Lines changed: 75 additions & 1 deletion

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs‎

Copy file name to clipboardExpand all lines: src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,13 @@ public void RegisterComponents(OpenApiDocument document)
9494
foreach (var item in document.Components.Schemas)
9595
{
9696
if (item.Value == null) continue;
97-
location = item.Value.Id ?? baseUri + ReferenceType.Schema.GetDisplayName() + ComponentSegmentSeparator + item.Key;
97+
location = baseUri + ReferenceType.Schema.GetDisplayName() + ComponentSegmentSeparator + item.Key;
9898
RegisterComponent(location, item.Value);
99+
100+
if (item.Value is not OpenApiSchemaReference && item.Value.Id is string schemaId && schemaId.Length > 0)
101+
{
102+
RegisterComponent(schemaId, item.Value);
103+
}
99104
}
100105
}
101106

Collapse file

‎test/Microsoft.OpenApi.Readers.Tests/V31Tests/RelativeReferenceTests.cs‎

Copy file name to clipboardExpand all lines: test/Microsoft.OpenApi.Readers.Tests/V31Tests/RelativeReferenceTests.cs
+69Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,75 @@ public async Task ParseLocalReferenceToJsonSchemaResourceWorks()
203203
Assert.Equal(JsonSchemaType.Object | JsonSchemaType.Null, schema.Type);
204204
}
205205

206+
[Fact]
207+
public async Task ParseExternalSchemaReferencedDirectlyAndReExportedAtRootWorks()
208+
{
209+
var tempDirectory = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
210+
Directory.CreateDirectory(tempDirectory);
211+
212+
var rootPath = Path.Join(tempDirectory, "root.yaml");
213+
var sharedPath = Path.Join(tempDirectory, "shared.yaml");
214+
215+
await File.WriteAllTextAsync(rootPath,
216+
@"openapi: 3.1.0
217+
info:
218+
title: T
219+
version: 1.0.0
220+
paths:
221+
/a:
222+
get:
223+
responses:
224+
'200':
225+
description: ok
226+
content:
227+
application/json:
228+
schema:
229+
type: object
230+
properties:
231+
meta:
232+
$ref: './shared.yaml#/Leaf'
233+
components:
234+
schemas:
235+
Leaf:
236+
$ref: './shared.yaml#/Leaf'
237+
");
238+
239+
await File.WriteAllTextAsync(sharedPath,
240+
@"Leaf:
241+
type: object
242+
properties:
243+
x:
244+
type: string
245+
y:
246+
type: integer
247+
");
248+
249+
try
250+
{
251+
var settings = new OpenApiReaderSettings
252+
{
253+
LoadExternalRefs = true,
254+
BaseUrl = new Uri(rootPath),
255+
};
256+
settings.AddYamlReader();
257+
258+
var result = await OpenApiDocument.LoadAsync(rootPath, settings);
259+
var responseSchema = result.Document.Paths["/a"].Operations[HttpMethod.Get].Responses["200"].Content["application/json"].Schema;
260+
var metaSchema = responseSchema.Properties["meta"];
261+
var leafSchema = result.Document.Components.Schemas["Leaf"];
262+
263+
Assert.NotNull(result.Document);
264+
Assert.DoesNotContain(result.Diagnostic.Errors, error => error.Message.Contains("Circular reference detected while resolving schema", StringComparison.Ordinal));
265+
Assert.DoesNotContain(result.Diagnostic.Warnings, warning => warning.Message.Contains("Circular reference detected while resolving schema", StringComparison.Ordinal));
266+
Assert.IsType<OpenApiSchemaReference>(metaSchema);
267+
Assert.IsType<OpenApiSchemaReference>(leafSchema);
268+
}
269+
finally
270+
{
271+
Directory.Delete(tempDirectory, true);
272+
}
273+
}
274+
206275
[Fact]
207276
public void ResolveSubSchema_ShouldTraverseKnownKeywords()
208277
{

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.