Document ID: CFG-0001 Status: APPROVED Scope: Repository build, compilation-safety, and secure release gates Target Baseline: .NET 10.0 (SDK 10.0.302)
The Sentinel repository enforces a strict, zero-warning cryptographic build baseline. All projects transitively inherit these compiler policies through central configuration files.
- SDK Pinned: .NET SDK
10.0.302(enforced viaglobal.json,rollForward: latestPatch). - Target Framework Monoculture (TFM):
net10.0(with multi-targeting ready). - Null Safety:
Nullable: enabledstrictly checked (warnings treated as errors). - Modern C# Compiler:
ImplicitUsings: enabledwith C# 13/14 language features active. - Strict Quality Gate:
TreatWarningsAsErrors: truein Release and CI builds (local Debug builds are explicitlyfalse). - Static Analysis:
AnalysisMode: All(Roslyn analyzers active on every build). - Documentation:
GenerateDocumentationFile: true(all public/internal APIs must be fully documented).
These settings are centralized in three primary files in the repository root:
global.json(SDK lock)Directory.Build.props(Compiler flags and signing rules)Directory.Packages.props(Central Package Management)
Ensures that all local developer environments and CI/CD runners build the solution using the exact same .NET SDK version, preventing runtime behavior drift:
{
"sdk": {
"version": "10.0.302",
"rollForward": "latestPatch"
}
}Centralizes common compiler settings, static analysis levels, and our SOTA Hybrid Strong-Name Signing configuration.
Enforces Central Package Management (CPM). Individual project files (.csproj) are prohibited from defining explicit Version attributes on <PackageReference> elements. All versions must be centrally registered inside Directory.Packages.props to prevent transitive dependency drift and vulnerabilities.
To restore and build the entire solution with strict compiler checks:
dotnet restore Sentinel.slnx --locked-mode
dotnet build Sentinel.slnx -c ReleaseTo run the standard unit, security, and integration test suites:
dotnet test Sentinel.slnx -c Release --logger "console;verbosity=normal"To run the programmatic xUnit concurrency test suite under Coyote's systematic scheduling engine:
# 1. Compile the concurrency suite (triggers the post-build binary rewriter)
cd tests/Sentinel.Tests.Concurrency
dotnet build -c Release
# 2. Run the programmatic xUnit tests
dotnet test -c ReleaseTo execute the container-based network chaos test suite:
dotnet test tests/Sentinel.Tests.Security/Sentinel.Tests.Security.csproj --filter "FullyQualifiedName~Chaos" -c ReleaseTo run high-precision, zero-allocation micro-benchmarks on cryptographic hot paths:
dotnet run -c Release --project tests/Sentinel.BenchmarksTo execute coverage-guided generative fuzzing against DPoP and SD-JWT parsers:
cd tests/Sentinel.FuzzTests
powershell -ExecutionPolicy Bypass -File .\run-fuzzing.ps1To execute the high-assurance end-to-end acceptance suite validating FAPI 2.0 and CAEP SSF:
# The test runner automatically manages the entire local Docker (Redis + Keycloak)
# and Minimal API host lifecycle under AcceptanceTestHooks.
dotnet test tests/Sentinel.Tests.Acceptance/Sentinel.Tests.Acceptance.csproj -c ReleaseTo protect corporate binary identity and prevent intermediate DLL tampering, Sentinel enforces strong-name signing. To avoid "cold-clone" failures and external contributor build blocks, we implement a SOTA Hybrid Signing Model:
- Local Developer / Contributor Builds (Unsigned fallback):
- If the private key
Sentinel.snkis absent (default clone state), MSBuild automatically falls back toSentinel.public.snkand enables<PublicSign>true</PublicSign>. - If neither key is present, assembly signing is gracefully disabled locally to allow instant compilation, avoiding any compiler errors.
- If the private key
- Staging / Release Packaging (Secure signing):
- Release builds in CI/CD inject the base64-encoded private key via GitHub Secrets (
SENTINEL_SNK_BASE64) and compile with-p:SignSentinelRelease=true. - This fully signs the released NuGet packages (
.nupkgand.snupkg) while keeping the private key out of source control.
- Release builds in CI/CD inject the base64-encoded private key via GitHub Secrets (
To compile and pack with full strong-name signing enabled:
dotnet pack Sentinel.slnx -c Release -p:SignSentinelRelease=true -o ./artifactsThe reference Minimal API host (Sentinel.Sample.MinimalApi) is configured with <PublishAot>true</PublishAot> to prove Native AOT compatibility.
CI publishes Sentinel.Tests.Load/AdversarialTestHost as a true Native AOT binary (the host wires the full Sentinel.AspNetCore/DPoP/Redis/SSF/SdJwt pipeline and deliberately avoids EF Core) and sweeps its endpoint matrix at runtime, failing on any HTTP 5xx, on a NotSupportedException or "Reflection-based serialization has been disabled" entry in the host log, and on a failed boot:
./tests/scripts/validate-native-aot.sh linux-x64 # also: win-x64, linux-arm64The native-aot-gate job in .github/workflows/security-pipeline.yml runs this gate on every push. Note the PowerShell/.cmd shim caveat: -p: values containing semicolons must escape them as %3B.
- No Reflection-based Serialization: All HTTP request/response DTOs, collection types, and framework error models (e.g.
ProblemDetails) must be registered inside a dedicatedJsonSerializerContext(e.g.,AspNetCoreJsonContextandSampleJsonContext). - Registering JSON Contexts: Ensure all contexts are registered in the DI serializer options at startup:
builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options => { options.SerializerOptions.TypeInfoResolverChain.Insert(0, SampleJsonContext.Default); });
- No Anonymous Types: Returning anonymous objects (
new { token = "..." }) inside route handlers is strictly prohibited. It requires runtime reflection and crashes under AOT withNotSupportedException. Always use named C# records registered in your JSON context. - Options classes must not use
initaccessors: theMicrosoft.Extensions.Configurationbinder silently skips scalarinit-only properties under Native AOT (collections are mutated in place and appear bound, which masks the bug). Every options type bound from configuration must use{ get; set; }. Collection properties then require a documentedCA2227suppression (the binder needs a settable collection):[SuppressMessage("Design", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Configuration binding requires a settable collection; init-only setters are silently skipped by the NativeAOT configuration binder.")] public Dictionary<string, string> KeyRing { get; set; } = new();
- Known, deliberate scope limit: the full Sentinel graph is not yet true-AOT-clean end to end. EF Core (
Sentinel.EntityFrameworkCore) cannot run under Native AOT (documentedRequiresDynamicCodelimitation), andOptions.ValidateDataAnnotationsuses reflection. The gate downgrades exactlyIL2026/IL3050(-p:WarningsNotAsErrors=IL2026;IL3050— never-p:NoWarn, which would override the repo-wide suppressions and re-surfaceCA1848/CA2234errors). Neither path is exercised by the gated host at runtime.
The repository contains a production-ready, highly secure multi-stage Docker build located at src/Sentinel.AspNetCore/Dockerfile.
- Distroless Runtime: Uses
mcr.microsoft.com/dotnet/aspnet:10.0.10-noble-chiseledas the minimal execution layer (no shell, no package manager, minimizing attack surface). - Non-Root Execution: Runs under a dedicated unprivileged user (
USER app/ UID 1654) to mitigate container escape exploits. - Disabled Diagnostics:
DOTNET_EnableDiagnostics=0is set to block runtime profiling, heap dumps, and memory scanning vectors. - TLS 1.3 & mTLS Ready: Hardened to negotiate TLS 1.3 exclusively for service-to-service secure mesh topologies.
If you receive obsolete warnings regarding new ContainerBuilder() during Testcontainers execution, ensure you pass the image string directly to the constructor to support modern Testcontainers v4 API standards:
var container = new ContainerBuilder("ghcr.io/shopify/toxiproxy:2.11.0")If the external Coyote CLI (coyote test ...) fails to load System.Runtime, Version=10.0.0.0 at runtime, use the Programmatic xUnit Integration via TestingEngine instead. This executes Coyote directly inside the native .NET 10 test host, completely resolving TFM version conflicts.
If a code analyzer demands a concrete type (CA1859), but the concrete type implements an interface explicitly (causing CS0053 on public properties), suppress the performance analyzer rule locally inside your dedicated test or fuzzing projects:
#pragma warning disable CA1859
IDpopProofValidator validator = new DpopProofValidator(replayCache, options);
#pragma warning restore CA1859