diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml new file mode 100644 index 0000000..aa46a98 --- /dev/null +++ b/.github/workflows/dotnet-build.yml @@ -0,0 +1,37 @@ +name: .NET build and tests +on: + push: + branches: [main] + paths: ['**/*.cs', '**/*.csproj', '**/*.props', '**/*.json', '**/*.sln*', '.github/workflows/dotnet-build.yml'] + pull_request: + branches: [main] +permissions: + contents: read +jobs: + build-and-test: + runs-on: ubuntu-latest + timeout-minutes: 25 + env: + DOTNET_CLI_TELEMETRY_OPTOUT: '1' + DOTNET_NOLOGO: '1' + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-dotnet@v6 + with: + global-json-file: global.json + - name: Trust this disposable runner's local development HTTPS certificate + run: | + export SSL_CERT_DIR="$HOME/.aspnet/dev-certs/trust:${SSL_CERT_DIR:-/usr/lib/ssl/certs}" + echo "SSL_CERT_DIR=$SSL_CERT_DIR" >> "$GITHUB_ENV" + dotnet dev-certs https --trust + dotnet dev-certs https --check --trust + - run: dotnet restore dotnet-configuration-in-depth.slnx + - run: dotnet build dotnet-configuration-in-depth.slnx --no-restore --configuration Release -m:2 + - name: Configuration unit tests + run: dotnet test 26-configuration-testing/ConfigurationTesting.csproj --no-build --no-restore --configuration Release + - name: Integration tests (including the unchanged timing assertion) + run: dotnet test 27-integration-testing/IntegrationTesting.csproj --no-build --no-restore --configuration Release + - name: Aspire integration tests on the disposable runner's Docker daemon + run: dotnet 28-aspire/AspireSample.Tests/bin/Release/net10.0/AspireSample.Tests.dll --timeout 180s --no-ansi --no-progress diff --git a/02-generic-host/GenericHost.csproj b/02-generic-host/GenericHost.csproj index dde3de4..4aa1c79 100644 --- a/02-generic-host/GenericHost.csproj +++ b/02-generic-host/GenericHost.csproj @@ -8,6 +8,8 @@ + + diff --git a/12-configuration-precedence/ConfigurationPrecedence.csproj b/12-configuration-precedence/ConfigurationPrecedence.csproj index 36135b8..5147c4a 100644 --- a/12-configuration-precedence/ConfigurationPrecedence.csproj +++ b/12-configuration-precedence/ConfigurationPrecedence.csproj @@ -6,6 +6,8 @@ enable + + diff --git a/13-dependency-injection/DependencyInjection.csproj b/13-dependency-injection/DependencyInjection.csproj index dde3de4..1e1f76f 100644 --- a/13-dependency-injection/DependencyInjection.csproj +++ b/13-dependency-injection/DependencyInjection.csproj @@ -8,6 +8,8 @@ + + diff --git a/14-array-object-access/ArrayObjectAccess.csproj b/14-array-object-access/ArrayObjectAccess.csproj index dde3de4..1e1f76f 100644 --- a/14-array-object-access/ArrayObjectAccess.csproj +++ b/14-array-object-access/ArrayObjectAccess.csproj @@ -8,6 +8,8 @@ + + diff --git a/15-collections-binding/CollectionsBinding.csproj b/15-collections-binding/CollectionsBinding.csproj index 5c60317..9b4f7a3 100644 --- a/15-collections-binding/CollectionsBinding.csproj +++ b/15-collections-binding/CollectionsBinding.csproj @@ -6,6 +6,8 @@ enable + + diff --git a/16-environment-configs/EnvironmentConfigs.csproj b/16-environment-configs/EnvironmentConfigs.csproj index 691ecfd..bd4d40a 100644 --- a/16-environment-configs/EnvironmentConfigs.csproj +++ b/16-environment-configs/EnvironmentConfigs.csproj @@ -6,6 +6,8 @@ enable + + diff --git a/22-azure-app-configuration/AzureAppConfiguration.csproj b/22-azure-app-configuration/AzureAppConfiguration.csproj index 044e0b9..c326a18 100644 --- a/22-azure-app-configuration/AzureAppConfiguration.csproj +++ b/22-azure-app-configuration/AzureAppConfiguration.csproj @@ -8,6 +8,7 @@ + diff --git a/24-configuration-reload/ConfigurationReload.csproj b/24-configuration-reload/ConfigurationReload.csproj index 65fe381..8a1ffa1 100644 --- a/24-configuration-reload/ConfigurationReload.csproj +++ b/24-configuration-reload/ConfigurationReload.csproj @@ -6,6 +6,8 @@ enable + + diff --git a/25-logging-reload/LoggingReload.csproj b/25-logging-reload/LoggingReload.csproj index 79aaed3..975dd55 100644 --- a/25-logging-reload/LoggingReload.csproj +++ b/25-logging-reload/LoggingReload.csproj @@ -6,6 +6,8 @@ enable + + diff --git a/26-configuration-testing/ConfigurationTesting.csproj b/26-configuration-testing/ConfigurationTesting.csproj index 7bc664a..de35c9b 100644 --- a/26-configuration-testing/ConfigurationTesting.csproj +++ b/26-configuration-testing/ConfigurationTesting.csproj @@ -17,6 +17,7 @@ + diff --git a/27-integration-testing/Tests/WebApplicationIntegrationTests.cs b/27-integration-testing/Tests/WebApplicationIntegrationTests.cs index 125c130..21da888 100644 --- a/27-integration-testing/Tests/WebApplicationIntegrationTests.cs +++ b/27-integration-testing/Tests/WebApplicationIntegrationTests.cs @@ -228,6 +228,10 @@ public async Task ApiData_ShouldRun_FasterWithTestConfiguration() { // Arrange var client = _factory.CreateClient(); + // Exercise the real endpoint once before measuring configured request delay. + // Cold-start routing/JIT costs vary by runner and are not the setting under test. + using var warmup = await client.GetAsync("/api/data"); + warmup.EnsureSuccessStatusCode(); var stopwatch = System.Diagnostics.Stopwatch.StartNew(); // Act diff --git a/28-aspire/AspireSample.AppHost/AspireSample.AppHost.csproj b/28-aspire/AspireSample.AppHost/AspireSample.AppHost.csproj index 3736e3c..0ce83f5 100644 --- a/28-aspire/AspireSample.AppHost/AspireSample.AppHost.csproj +++ b/28-aspire/AspireSample.AppHost/AspireSample.AppHost.csproj @@ -1,4 +1,4 @@ - + Exe @@ -15,6 +15,8 @@ + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 48827f0..b77b0ff 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,24 +15,24 @@ - - - - - - - - - + + + + + + + + + - - - - + + + + - - + + diff --git a/docs/runtime-validation.md b/docs/runtime-validation.md new file mode 100644 index 0000000..8d5f055 --- /dev/null +++ b/docs/runtime-validation.md @@ -0,0 +1,10 @@ +# Stable .NET runtime validation + +All 32 sample projects target .NET 10. `global.json` selects SDK 10.0.401; core Microsoft.Extensions and ASP.NET Core packages are aligned to the 10.0.12 servicing release. The previous Azure.Identity and Aspire SDK alignment fixes are preserved. + +The new `.NET build and tests` workflow restores and compiles the full solution, runs the configuration unit tests and integration tests, then executes the native Aspire test runner against Docker on the disposable GitHub-hosted VM. It has read-only repository permissions, no persisted checkout credentials, and no cloud credentials or deployment steps. + +The integration test keeps its strict 200 ms assertion. It first warms the real endpoint to exclude variable routing/JIT cold-start overhead from the configured-delay measurement. A validation-only negative control with the default 300 ms delay must still fail that same assertion. Container tests never require a personal machine or Gateway Docker socket. Azure deployment and secret configuration are outside this build workflow. + +The CI runner generates/trusts its own local development HTTPS certificate before Aspire starts and checks that trust explicitly. TLS certificate validation remains enabled. No certificate or trust store on the Gateway, a personal machine, or a cloud service is changed. +The SDK-required OpenSSL development trust directory is included in `SSL_CERT_DIR` alongside the existing system roots for this CI job only. diff --git a/global.json b/global.json new file mode 100644 index 0000000..e1c5e99 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "10.0.401", + "rollForward": "latestPatch", + "allowPrerelease": false + } +}