From f4f38b38c9e1a1857f65416aa56214039a606355 Mon Sep 17 00:00:00 2001 From: Julian lechner Date: Thu, 8 Oct 2026 10:34:01 +0200 Subject: [PATCH] docs(rules): give each C# rule statement one authoritative file Co-Authored-By: Claude Opus 5.5 --- .../rules/csharp/references/architecture-and-apis.md | 10 +++------- shared/rules/csharp/references/coding-style.md | 3 --- shared/rules/csharp/references/performance.md | 4 ++-- shared/rules/csharp/references/safety-and-errors.md | 5 ++--- shared/rules/csharp/references/security.md | 5 ++--- .../csharp/references/testing-and-dependencies.md | 3 +-- .../rules/csharp/references/types-and-collections.md | 3 +-- 7 files changed, 11 insertions(+), 22 deletions(-) diff --git a/shared/rules/csharp/references/architecture-and-apis.md b/shared/rules/csharp/references/architecture-and-apis.md index bd8d6f2..0149cac 100644 --- a/shared/rules/csharp/references/architecture-and-apis.md +++ b/shared/rules/csharp/references/architecture-and-apis.md @@ -2,14 +2,10 @@ Apply these rules when designing public APIs, service boundaries, or application architecture. -* Give APIs explicit, strongly typed contracts. Validate external input at the boundary and keep trusted internal paths free of redundant checks. +* Give APIs explicit, strongly typed contracts. Keep trusted internal paths free of checks already done at the boundary. * Separate request models from persistence and domain models. Bind only fields the caller may set, and project only fields the caller may read. -* Authenticate and authorize before accessing protected resources. Enforce resource ownership and tenant scope in the data access path, not only in the UI or route layer. -* Bound page size, payload size, query complexity, and operation cost. Use explicit pagination for potentially large collections. +* Authenticate and authorize before accessing protected resources. Keep the decision close to the protected operation, enforce resource ownership and tenant scope in the data access path, not only in the UI or route layer, and fail closed when identity, ownership, or policy evaluation is unavailable. +* Use explicit, bounded pagination for potentially large collections. * Keep application, domain, and infrastructure concerns separate. Avoid cross-layer coupling and service-locator patterns. * Use dependency injection when substitution or lifecycle management is needed. Keep dependencies explicit and avoid excessive constructor dependencies. -* Prefer composition over inheritance; use inheritance only when the contract requires it. Seal types when extension is not intended. -* Keep classes and methods focused. Avoid wrappers, abstractions, reflection, and global mutable state without a concrete need. * Preserve established project and public API conventions unless a concrete compatibility or correctness issue requires a change. -* Keep authorization decisions close to the protected operation and fail closed when identity, ownership, or policy evaluation is unavailable. -* Avoid returning persistence entities, internal exception details, or fields that are not part of the public contract. diff --git a/shared/rules/csharp/references/coding-style.md b/shared/rules/csharp/references/coding-style.md index 88343fc..06f0585 100644 --- a/shared/rules/csharp/references/coding-style.md +++ b/shared/rules/csharp/references/coding-style.md @@ -7,7 +7,4 @@ Apply these rules when editing C# syntax, class structure, and everyday code org * Keep classes, methods, and responsibilities focused. Use descriptive names and established domain terms; avoid unexplained abbreviations. * Prefer composition over inheritance. Use inheritance only for a real substitutable contract, and seal types when extension is not intended. * Avoid unnecessary wrappers, abstractions, reflection, runtime type checks, and global mutable state. -* Prefer immutable or readonly state when it simplifies ownership and reduces accidental mutation. * Keep side effects visible. Make behavior deterministic and easy to test where practical. -* Add comments or API documentation only for non-obvious decisions, public contracts, or documented project requirements. -* Remove dead code instead of leaving commented-out implementations. diff --git a/shared/rules/csharp/references/performance.md b/shared/rules/csharp/references/performance.md index b084278..6ffeca1 100644 --- a/shared/rules/csharp/references/performance.md +++ b/shared/rules/csharp/references/performance.md @@ -5,10 +5,10 @@ Apply these rules when optimizing code or reviewing runtime and resource costs. * Establish a representative baseline before changing code. Measure the affected workload, input size, concurrency, and environment; distinguish average latency from tail latency and throughput. * Find the dominant cost before optimizing: architecture, database access, network and I/O, algorithms, concurrency, allocations and GC, then CPU-level work. * Choose collections and algorithms for actual access patterns. Check asymptotic cost and data growth; avoid repeated scans, unnecessary sorting, copies, and unbounded result sets. -* Keep data close to where it is processed. Filter and project in the database, avoid N+1 queries, bound page sizes, and avoid materializing rows or columns the caller does not use. +* Keep data close to where it is processed. Filter and project in the database, avoid N+1 queries, and avoid materializing rows or columns the caller does not use. * Stream large inputs and outputs when buffering the whole value would waste memory. Bound queues, batches, and parallel work to match downstream capacity. * Reduce allocations in measured hot paths: avoid repeated string construction, iterator/delegate capture, boxing, and collection resizing when profiling identifies them as material costs. * Consider pooling only for expensive reusable objects with clear ownership and reset rules. Pooling can retain memory or leak state between users; measure it and cap retained capacity. -* Use `Span`, `ValueTask`, preallocation, or specialized low-level APIs only when their benefit is demonstrated and they preserve readable, safe ownership. +* Use `Span`, preallocation, or specialized low-level APIs only when their benefit is demonstrated and they preserve readable, safe ownership. * Cache only when repeated work is measurable and the key, lifetime, size bound, invalidation, and sensitive-data handling are explicit. * After an optimization, run the same workload and compare correctness, allocations, GC, CPU, latency, and throughput against the baseline. Keep the simplest change that meets the target. diff --git a/shared/rules/csharp/references/safety-and-errors.md b/shared/rules/csharp/references/safety-and-errors.md index 8e68c4c..a042c82 100644 --- a/shared/rules/csharp/references/safety-and-errors.md +++ b/shared/rules/csharp/references/safety-and-errors.md @@ -7,8 +7,7 @@ Apply these rules when handling external input, failures, logs, or sensitive inf * Fail fast for invalid arguments or impossible state. Do not use exceptions for routine control flow or swallow unexpected exceptions. * Preserve useful exception context without exposing secrets, personal data, or internal details in logs, APIs, or user-facing errors. * Use structured logging and avoid excessive logging, especially in hot paths. Never log credentials, tokens, or sensitive payloads. -* Keep authorization, certificate validation, encryption, and other security controls intact. Follow the focused security rules for the affected boundary. -* Keep side effects explicit and deterministic where practical; propagate cancellation and dispose owned resources correctly. +* Dispose owned resources correctly, including on failure paths. * Use narrow exception handling around the operation that can fail. Do not catch broadly merely to retry, continue with partial state, or convert failures into success. * Avoid returning different error detail to unauthenticated callers when it would disclose whether protected accounts, records, or resources exist. -* Treat resource limits as part of safe error handling: cap request bodies, decompressed data, collection sizes, parser depth, and other attacker-controlled work. +* Treat resource limits as part of safe error handling: cap request bodies, page sizes, query complexity, decompressed data, collection sizes, parser depth, and other attacker-controlled work. diff --git a/shared/rules/csharp/references/security.md b/shared/rules/csharp/references/security.md index 70ec8b4..5e46c68 100644 --- a/shared/rules/csharp/references/security.md +++ b/shared/rules/csharp/references/security.md @@ -2,13 +2,12 @@ Apply these rules when implementing or reviewing security-sensitive .NET code. Load the matching shared security rule for the affected API, identity, data, file, network, cryptographic, or dependency boundary as well. -* Validate untrusted input at the boundary and enforce authorization for the specific resource and operation. Static types and client-side checks do not establish trust. * Use parameterized database APIs. If a query identifier or sort expression cannot be parameterized, select it from a fixed allowlist; never concatenate untrusted input into SQL. * For file access, canonicalize the resolved path and verify it remains inside the authorized root. Account for reparse points and symlinks when the attacker can affect directory contents. * For process execution, avoid a shell. Pass executable and arguments separately using APIs supported by the target framework, validate each argument, and restrict executable paths. * Deserialize into explicit DTOs or allowlisted types. Avoid unsafe polymorphic type activation and unbounded object graphs for untrusted data. -* Bound request and parser work before allocating or processing large values. Apply timeouts to regular expressions that evaluate untrusted input and prefer patterns with predictable complexity. -* Keep secrets in an approved secret store or protected configuration source. Never embed them in assemblies, client bundles, source, diagnostics, or exception messages. +* Apply timeouts to regular expressions that evaluate untrusted input and prefer patterns with predictable complexity. +* Keep secrets in an approved secret store or protected configuration source. Never embed them in assemblies, client bundles, or source. * Use platform TLS and established cryptographic APIs. Do not create custom cryptography or disable certificate validation; use cryptographically secure randomness for security tokens. * Use framework output encoding and safe APIs for HTML, XML, and other interpreters. Do not build executable markup or queries from untrusted strings. * Review security-sensitive changes with tests for rejected, malformed, oversized, unauthenticated, and cross-tenant inputs, as applicable. diff --git a/shared/rules/csharp/references/testing-and-dependencies.md b/shared/rules/csharp/references/testing-and-dependencies.md index 772bbde..3431343 100644 --- a/shared/rules/csharp/references/testing-and-dependencies.md +++ b/shared/rules/csharp/references/testing-and-dependencies.md @@ -5,6 +5,5 @@ Apply these rules when changing tests, package references, analyzers, or build d * Write deterministic behavior-based tests. Avoid coupling assertions to private call order, implementation details, current time, or uncontrolled external services. * Make code testable through clear contracts and dependencies; do not add production hooks or abstractions solely for tests without a concrete need. * Prefer the .NET BCL and existing supported packages over new libraries when they solve the problem adequately. -* Keep dependencies minimal, maintained, compatible, and updated through the repository's normal package-management process. * Treat compiler, analyzer, and nullable warnings seriously. Suppress a diagnostic only for a specific, documented reason and narrow the suppression to the affected code. -* Run focused tests and analyzers for the changed path; broaden verification when shared behavior or compatibility could be affected. +* Include analyzers in the verification of the changed path. diff --git a/shared/rules/csharp/references/types-and-collections.md b/shared/rules/csharp/references/types-and-collections.md index f9e49c7..b4bf562 100644 --- a/shared/rules/csharp/references/types-and-collections.md +++ b/shared/rules/csharp/references/types-and-collections.md @@ -8,5 +8,4 @@ Apply these rules when designing type contracts, choosing collection shapes, or * Expose collection interfaces such as `IReadOnlyList`, `IEnumerable`, `IDictionary`, or `ICollection` only when their capability is part of an intentional boundary or public contract. * Choose collection types based on lookup, ordering, mutation, and iteration needs. Pre-size collections only when expected capacity is known and material. * Avoid large mutable structs and direct exposure of mutable internal collections. -* Prefer immutable data where practical, while preserving established API and serialization contracts. -* Use `Span` and related low-level types only when the performance rule's measurement justifies their lifetime and ownership constraints. +* Prefer immutable data and readonly state where practical, while preserving established API and serialization contracts.