Repository navigation
Add Nitro schema validation to Fusion Aspire - #10173
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an opt-in Nitro-backed schema validation flow to Fusion Aspire so composed gateway schemas can be uploaded and validated against Nitro in the background, with notifications/logging for client-contract transitions and a portal link on Nitro-composed gateways.
Changes:
- Introduces
NitroSchemaValidator+ validation report model, formatting, coordinator/worker, and notifier plumbing. - Extends schema composition to (optionally) capture the composed gateway schema and schedule Nitro validation; also adds a “recompose” command coordinator.
- Adds embedded Nitro GraphQL operation documents (and hashes) plus broad test coverage for validation/coordinator behavior and portal URL derivation.
Reviewed changes
Copilot reviewed 33 out of 33 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/SchemaCompositionTests.cs | Adds tests for manual recompose command behavior (coalescing/failure). |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/NitroExtensionsTests.cs | Adds tests for the new WithNitroSchemaValidation extension and command registration. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroSchemaValidatorTests.cs | Adds comprehensive tests for Nitro schema validation HTTP/GraphQL behaviors and edge cases. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroSchemaValidationNotifierTests.cs | Adds tests for Aspire notification prompting behavior and worker notification transitions. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroSchemaValidationFormatterTests.cs | Adds tests for formatting/truncation of validation findings. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroSchemaCompositionTests.cs | Adds integration-style tests for portal URL annotations and validation scheduling on composition/recompose. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroOperationDocumentsTests.cs | Adds tests ensuring validation operation names and persisted hashes align with embedded documents. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroDefaultsTests.cs | Adds tests for portal URL derivation from API URL. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/GatewaySchemaValidationWorkerTests.cs | Adds tests for worker coalescing, cancellation, caching, notifications, and logging behavior. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/CompositionHarness.cs | Extends harness to include validation coordinator and lifecycle stopping token behavior. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/SchemaCompositionRegistration.cs | Registers validation coordinator/notifier and the command coordinator; exposes GetOptions. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/SchemaComposition.cs | Adds portal URL annotation, recompose command execution, schema capture for validation, and scheduling of validation runs. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/NitroExtensions.cs | Adds AddNitro(..., portalUrl) and WithNitroSchemaValidation() opt-in API; adds helper to detect validation annotation. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/ValidateNitroSchema.graphql.sha256 | Adds persisted hash for the “validate schema” operation. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/ValidateNitroSchema.graphql | Adds the Nitro schema validation “start” GraphQL document. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/PollNitroSchemaValidation.graphql.sha256 | Adds persisted hash for the “poll schema validation” operation. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/PollNitroSchemaValidation.graphql | Adds the Nitro schema validation polling GraphQL document. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedCoordinator.cs | Injects schema validator; adds connection resolution + schema validation methods. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidator.cs | Implements the Nitro validation client (start + poll, bounded reads, retries, parsing into a report). |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationReport.cs | Adds report model types, status enum, and fingerprint computation for deduplication. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationNotifier.cs | Adds notifier abstraction and Aspire interaction-based implementation. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationFormatter.cs | Adds formatting/truncation for findings emitted to resource logs. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationCoordinator.cs | Adds coordinator + worker that schedules/coalesces validation runs and emits notifications/logging. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationAnnotation.cs | Adds opt-in annotation marker for enabling validation on a gateway resource. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroOperationDocuments.cs | Adds embedded document/hash accessors and operation name constants for validation operations. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroDefaults.cs | Adds portal URL derivation logic from effective Nitro API URL. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroCompositionOptions.cs | Adds PortalUrl option alongside Coordinator. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/INitroSchemaValidator.cs | Adds interface for schema validator implementation. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/HotChocolate.Fusion.Aspire.csproj | Embeds the new operation documents / hashes per configuration. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/GraphQLResourceBuilderExtensions.cs | Registers a “recompose” resource command that routes through the command coordinator. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/GatewayCompositionCommandCoordinator.cs | Adds coordinator that dispatches recompose command executions by resource name. |
| CLAUDE.md | Documents Nitro persisted operations update/verify workflow. |
| AGENTS.md | Documents Nitro persisted operations update/verify workflow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!await compositionGate.WaitAsync(0, cancellationToken)) | ||
| { | ||
| return CommandResults.Success("Composition already in progress"); | ||
| } |
| _pendingHash = null; | ||
| _terminalReports[request.Request.SchemaHash] = report; | ||
| } |
| else | ||
| { | ||
| var connection = await coordinator.ResolveConnectionAsync(logger, cancellationToken); | ||
| portalUrl = NitroDefaults.CreatePortalUrl(connection.ApiUrl).OriginalString; | ||
| } |
Patch coverage84.9% of changed lines covered (1200/1414) Uncovered changed lines (JSON){
"sha": "9f854b4a2f8d600824b5e5d22268d00f9fb65e62",
"files": [
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/GatewayCompositionCommandCoordinator.cs", "ranges": [[14, 16], [19, 22], [27, 27], [30, 32], [34, 37]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/GraphQLResourceBuilderExtensions.cs", "ranges": [[99, 99], [114, 120]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/SchemaComposition.cs", "ranges": [[52, 52], [57, 59], [64, 64], [85, 92], [139, 141], [156, 158], [521, 523], [555, 557], [559, 566], [710, 710], [1340, 1347], [1374, 1376]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroDefaults.cs", "ranges": [[34, 35], [39, 40]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/NitroExtensions.cs", "ranges": [[82, 85], [103, 105]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationCoordinator.cs", "ranges": [[42, 49], [71, 72], [172, 179], [193, 195], [233, 234], [249, 255], [280, 280], [284, 290], [313, 314], [402, 403]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidator.cs", "ranges": [[63, 66], [116, 117], [178, 179], [264, 266], [281, 282], [288, 289], [293, 295], [298, 306], [377, 382], [388, 393], [447, 452], [587, 594], [633, 640], [652, 659], [682, 683], [696, 697], [752, 753], [787, 787]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationNotifier.cs", "ranges": [[47, 49]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationReport.cs", "ranges": [[13, 13], [57, 58], [77, 81]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationFormatter.cs", "ranges": [[42, 43], [57, 58], [76, 77]] }
]
}Project coverage: 54.2% (236268/435869 lines) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 33 out of 33 changed files in this pull request and generated no new comments.
Suppressed comments (3)
src/HotChocolate/Fusion/src/Fusion.Aspire/SchemaComposition.cs:149
- The exception is swallowed when resolving the Nitro portal URL, which makes diagnosing why the link wasn’t added difficult. Log the caught exception with the warning so failures can be investigated without enabling extra instrumentation.
catch (Exception)
{
logger.LogWarning(
"The Nitro Portal URL could not be resolved. The informational link will "
+ "not be added.");
src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationReport.cs:26
- Fingerprint recomputes the SHA256 hash on every access and allocates a list each time. This is called during notification transitions, so repeated accesses can add avoidable CPU/allocations on large reports. Cache the computed fingerprint in the report instance (lazy is fine) so it’s computed at most once.
public int FindingCount =>
Findings.Count
+ Clients.Sum(client => client.Operations.Sum(operation => operation.Errors.Count));
public string Fingerprint => ComputeFingerprint();
src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSchemaValidationFormatter.cs:116
- Finding messages are appended verbatim into an error-level log entry (via NitroSchemaValidationFormatter.Format -> GatewaySchemaValidationWorker). If Nitro returns multi-line or very large messages, this can flood logs and may leak sensitive content. Consider normalizing (single-line) and truncating messages before logging.
{
builder.Append(indent)
.Append("- ")
.Append(finding.Message);
No description provided.