Skip to content

Commit abeddfd

Browse files
[Fusion] Added post-merge validation rule InputFieldReferencesInaccessibleTypeRule
1 parent b8fcc1c commit abeddfd

File tree

7 files changed

+244
-184
lines changed

7 files changed

+244
-184
lines changed

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/LogEntryCodes.cs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public static class LogEntryCodes
1414
public const string ExternalUnused = "EXTERNAL_UNUSED";
1515
public const string FieldArgumentTypesNotMergeable = "FIELD_ARGUMENT_TYPES_NOT_MERGEABLE";
1616
public const string InputFieldDefaultMismatch = "INPUT_FIELD_DEFAULT_MISMATCH";
17+
public const string InputFieldReferencesInaccessibleType = "INPUT_FIELD_REFERENCES_INACCESSIBLE_TYPE";
1718
public const string InputFieldTypesNotMergeable = "INPUT_FIELD_TYPES_NOT_MERGEABLE";
1819
public const string InputWithMissingRequiredFields = "INPUT_WITH_MISSING_REQUIRED_FIELDS";
1920
public const string InvalidGraphQL = "INVALID_GRAPHQL";

src/HotChocolate/Fusion-vnext/src/Fusion.Composition/Logging/LogEntryHelper.cs

+21
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,27 @@ public static LogEntry InputFieldDefaultMismatch(
279279
schemaA);
280280
}
281281

282+
public static LogEntry InputFieldReferencesInaccessibleType(
283+
InputFieldDefinition field,
284+
string typeName,
285+
string referenceTypeName,
286+
SchemaDefinition schema)
287+
{
288+
var coordinate = new SchemaCoordinate(typeName, field.Name);
289+
290+
return new LogEntry(
291+
string.Format(
292+
LogEntryHelper_InputFieldReferencesInaccessibleType,
293+
field.Name,
294+
typeName,
295+
referenceTypeName),
296+
LogEntryCodes.InputFieldReferencesInaccessibleType,
297+
LogSeverity.Error,
298+
coordinate,
299+
field,
300+
schema);
301+
}
302+
282303
public static LogEntry InputFieldTypesNotMergeable(
283304
InputFieldDefinition field,
284305
string typeName,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Collections.Immutable;
2+
using System.Diagnostics;
3+
using HotChocolate.Fusion.Events;
4+
using HotChocolate.Fusion.Events.Contracts;
5+
using HotChocolate.Fusion.Extensions;
6+
using HotChocolate.Skimmed;
7+
using static HotChocolate.Fusion.Logging.LogEntryHelper;
8+
9+
namespace HotChocolate.Fusion.PostMergeValidationRules;
10+
11+
/// <summary>
12+
/// In a composed schema, a field within an input type must only reference types that are exposed.
13+
/// This requirement guarantees that public types do not reference <c>inaccessible</c> structures
14+
/// which are intended for internal use.
15+
/// </summary>
16+
/// <seealso href="https://graphql.github.io/composite-schemas-spec/draft/#sec-Input-Fields-cannot-reference-inaccessible-type">
17+
/// Specification
18+
/// </seealso>
19+
internal sealed class InputFieldReferencesInaccessibleTypeRule
20+
: IEventHandler<SchemaEvent>, IEventHandler<InputFieldEvent>
21+
{
22+
private ImmutableHashSet<string>? _inaccessibleTypes;
23+
24+
public void Handle(SchemaEvent @event, CompositionContext context)
25+
{
26+
var builder = ImmutableHashSet.CreateBuilder<string>();
27+
foreach (var type in @event.Schema.Types)
28+
{
29+
if (type.HasInaccessibleDirective())
30+
{
31+
builder.Add(type.Name);
32+
}
33+
}
34+
35+
_inaccessibleTypes = builder.ToImmutable();
36+
}
37+
38+
public void Handle(InputFieldEvent @event, CompositionContext context)
39+
{
40+
Debug.Assert(_inaccessibleTypes is not null);
41+
42+
var (field, type, schema) = @event;
43+
44+
if (field.HasInaccessibleDirective())
45+
{
46+
return;
47+
}
48+
49+
var fieldTypeName = field.Type.NamedType().Name;
50+
if (_inaccessibleTypes.Contains(fieldTypeName))
51+
{
52+
context.Log.Write(
53+
InputFieldReferencesInaccessibleType(
54+
field,
55+
type.Name,
56+
fieldTypeName,
57+
schema));
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)