Introduces a non-breaking, multi-instance authorization-check pipeline
that runs alongside the existing single-instance auth services.
Motivation
- Cross-cutting checks (proof-of-work, mobile attestation, rate-limit
gates, IP allow-lists) don't belong in consumer auth services — they
ship from framework modules and self-apply via attributes.
- The existing ICommandAuthorizationService takes only a Type; checks
need the request *instance* to read payload fields (e.g. an Altcha
solution carried on the command).
Shape
- New abstractions: ICommandAuthorizationCheck, IQueryAuthorizationCheck,
CommandAuthorizationCheckContext, QueryAuthorizationCheckContext.
- Context carries (Type, Instance, IServiceProvider, Items dict). The
Items dict lets sibling checks signal one another — e.g. a future
mobile-attestation check stamps "mobile_attested" for the Altcha
check to read as a bypass.
- AND semantics: framework resolves IEnumerable<…Check>, runs each in
registration order, first non-Allowed short-circuits.
- Wired into MinimalApi (commands + queries, POST + GET) and the
Svrnty.CQRS.Grpc.Generators source generator (commands, queries,
dynamic queries). In all paths the checks run AFTER the instance
is materialized and validated, BEFORE handler invocation.
Backward compatibility
- No registered checks = today's behavior exactly.
- ICommandAuthorizationService / IQueryAuthorizationService signatures
unchanged; consumers' existing auth services keep working untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generated CommandServiceImpl.g.cs had warnings like:
Slug = request.Slug?.ToList(), // CS8601 if Slug is non-nullable List<T>
The ?. was over-defensive: proto3 repeated fields are emitted as
RepeatedField<T> in C# and are NEVER null. The conditional access
made the result List<T>? which then triggered CS8601 when assigned
to a non-nullable target on the command POCO.
Dropped ?. in 4 emission sites in GrpcGenerator.cs covering:
- Top-level primitive list mapping (line 872)
- Top-level Guid list mapping (line 861)
- Nested primitive list mapping in NestedPropertyAssignment (line 1083)
- Complex list .Select chain in GenerateComplexListMapping (line 974,
conditional: kept ?. for value-type collections where source.Items is
read off a possibly-null wrapper message)
Real fix in the generator instead of CS8601 NoWarn suppression in
consumer csprojs. Consumers can drop the suppression after bumping.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generated code was using locale-dependent parsing for decimal values.
On systems with comma decimal separator (e.g., French locale), parsing
"0.95" would throw FormatException because the system expected "0,95".
Switched all 4 decimal.Parse() call sites in the generated proto→domain
mappers to pass System.Globalization.CultureInfo.InvariantCulture for
consistent behavior across locales.
Inspired by JP's commit 599204d on feat/grpc-generator-improvements
(applied manually since cherry-pick had heavy context conflicts).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Automated formatting: BOM removal, using sort order, final newlines,
whitespace normalization across all projects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ICommandAuthorizationService check to CommandServiceImpl
- Add IQueryAuthorizationService check to QueryServiceImpl
- Add IQueryAuthorizationService check to DynamicQueryServiceImpl
- Return Unauthenticated/PermissionDenied gRPC status codes
- Use global:: prefix for Grpc.Core namespace to avoid conflicts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Resolve ICommandAuthorizationService and IQueryAuthorizationService from request-scoped serviceProvider
- Allows Scoped authorization services that depend on DbContext
- Updated both MinimalApi and DynamicQuery.MinimalApi
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add DateTime/Timestamp conversion in nested property mapping
- Add IsReadOnly property detection to skip computed properties
- Extract ElementNestedProperties for complex list element types
- Skip read-only properties in GenerateComplexObjectMapping and GenerateComplexListMapping
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add proper complex type mapping for command results (same as queries already had)
- Handle nullable primitives (long?, int?, etc.) with default value fallback
- Fixes CS0029 and CS0266 compilation errors in generated gRPC service implementations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The MapToProtoModel function was silently failing when mapping Guid
properties to proto string fields, causing IDs to be empty in gRPC
responses. Added explicit Guid → string conversion handling.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>