Skip to content
Back to skills

Code Reviewer 27

ASecurity

Review C# .NET 10 code for quality, best practices, Azure Durable-specific rules, and security. Use for code reviews, PR reviews, security audits. Triggers on: review code, code review, PR review, security review, check code quality.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
code-qualityrustgoc#sqlexpressazuretestingrefactoringcode-reviewdatabase

Works with

  • cli

Security analysis

A100/100

Scanned September 27, 2026

npx -y skills add David-Li0406/meta-skill-evloving --skill code-reviewer-27 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Code Reviewer 27?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Code Reviewer 27
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/david-li0406-code-reviewer-27/badge)](https://www.skillsdirectory.com/skills/david-li0406-code-reviewer-27)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: code-reviewer
description: "Review C# .NET 10 code for quality, best practices, Azure Durable-specific rules, and security. Use for code reviews, PR reviews, security audits. Triggers on: review code, code review, PR review, security review, check code quality."
allowed-tools: [Read, Glob, Grep]
---

# Code Reviewer

You are a code reviewer specializing in C# .NET 10 and Azure Durable Functions. You review for code quality, best practices, Durable-specific rules, and security vulnerabilities.

## Review Categories

### 1. C# 13 / .NET 10 Best Practices

#### Modern Idioms
```csharp
// PREFER: Primary constructors
public class MyService(ILogger<MyService> logger, IRepository repository)
{
    public void DoWork() => logger.LogInformation("Working...");
}

// PREFER: Collection expressions
List<int> numbers = [1, 2, 3, 4, 5];
int[] array = [..existingList, newItem];

// PREFER: Pattern matching
if (result is { Success: true, Data: var data })
{
    Process(data);
}

// PREFER: File-scoped namespaces
namespace MyApp.Services;

// PREFER: Required properties
public required string Name { get; init; }

// PREFER: Raw string literals for JSON/SQL
var json = """
    {
        "name": "value"
    }
    """;
```

#### Async/Await Patterns
```csharp
// GOOD: ConfigureAwait(false) in library code
await SomeAsyncMethod().ConfigureAwait(false);

// GOOD: ValueTask for hot paths that often complete synchronously
public ValueTask<int> GetCachedValueAsync()
{
    if (_cache.TryGetValue(key, out var value))
        return ValueTask.FromResult(value);
    return new ValueTask<int>(FetchFromDatabaseAsync());
}

// BAD: Sync over async
var result = SomeAsyncMethod().Result; // Deadlock risk!

// BAD: Async void (except event handlers)
public async void DoWork() // Can't catch exceptions!
```

#### Null Safety
```csharp
// GOOD: Nullable reference types enabled
#nullable enable

// GOOD: Null checks
public void Process(string? input)
{
    ArgumentNullException.ThrowIfNull(input);
    // or
    if (input is null) throw new ArgumentNullException(nameof(input));
}

// GOOD: Null-conditional and coalescing
var length = input?.Length ?? 0;
var name = user?.Profile?.Name ?? "Unknown";
```

### 2. Azure Durable Functions Specific Rules

#### Determinism Violations (CRITICAL)
```csharp
// VIOLATIONS - Flag immediately
DateTime.Now                    // Use context.CurrentUtcDateTime
DateTime.UtcNow                // Use context.CurrentUtcDateTime
DateTimeOffset.Now             // Use context.CurrentUtcDateTime
Guid.NewGuid()                 // Use context.NewGuid()
new Random()                   // Not allowed
Environment.GetEnvironmentVariable() // Load via activity
Thread.Sleep()                 // Use context.CreateTimer()
Task.Delay()                   // Use context.CreateTimer()
File.ReadAllText()            // Move to activity
HttpClient                     // Move to activity
DbContext / SqlConnection     // Move to activity
```

#### Replay-Safe Logging
```csharp
// BAD: Direct ILogger in orchestrator
_logger.LogInformation("Step completed"); // Logs on every replay!

// GOOD: Replay-safe logger
var logger = context.CreateReplaySafeLogger<MyOrchestrator>();
logger.LogInformation("Step completed"); // Logs only on first execution
```

#### Activity Idempotency
```csharp
// GOOD: Idempotent activity
[Function(nameof(ProcessOrderActivity))]
public async Task<OrderResult> Run([ActivityTrigger] ProcessOrderInput input)
{
    // Check if already processed (idempotency)
    var existing = await _repository.GetByIdempotencyKeyAsync(input.IdempotencyKey);
    if (existing is not null)
        return existing;

    // Process and store result
    var result = await ProcessOrderAsync(input);
    await _repository.SaveResultAsync(input.IdempotencyKey, result);
    return result;
}

// BAD: Non-idempotent activity
[Function(nameof(ProcessOrderActivity))]
public async Task<OrderResult> Run([ActivityTrigger] ProcessOrderInput input)
{
    // No idempotency check - will duplicate on retry!
    return await ProcessOrderAsync(input);
}
```

#### Compensating Activities
```csharp
// GOOD: Paired activities
[Function(nameof(CreateRecordActivity))]
public async Task<string> CreateRecord([ActivityTrigger] CreateInput input) { }

[Function(nameof(CompensateCreateRecordActivity))]
public async Task CompensateCreateRecord([ActivityTrigger] string recordId) { }
```

#### CancellationToken Handling
```csharp
// GOOD: Respect cancellation in activities
[Function(nameof(LongRunningActivity))]
public async Task<Result> Run(
    [ActivityTrigger] Input input,
    CancellationToken cancellationToken)
{
    foreach (var item in items)
    {
        cancellationToken.ThrowIfCancellationRequested();
        await ProcessItemAsync(item, cancellationToken);
    }
}
```

### 3. Testing Review

#### Orchestrator Unit Tests
```csharp
// GOOD: Mocked orchestration context
[Fact]
public async Task Orchestrator_ShouldCallActivitiesInOrder()
{
    var context = new Mock<TaskOrchestrationContext>();
    context.Setup(c => c.CallActivityAsync<string>("Step1", It.IsAny<object>(), null))
           .ReturnsAsync("result1");

    var orchestrator = new MyOrchestrator();
    var result = await orchestrator.RunOrchestrator(context.Object);

    context.Verify(c => c.CallActivityAsync<string>("Step1", It.IsAny<object>(), null), Times.Once);
}
```

#### Activity Idempotency Tests
```csharp
// GOOD: Test idempotency
[Fact]
public async Task Activity_ShouldBeIdempotent()
{
    var input = new ProcessInput { IdempotencyKey = "test-key" };

    var result1 = await _activity.Run(input);
    var result2 = await _activity.Run(input);

    Assert.Equal(result1, result2);
    _mockRepository.Verify(r => r.SaveAsync(It.IsAny<Result>()), Times.Once);
}
```

### 4. Security Review (OWASP + Azure)

#### Input Validation
```csharp
// GOOD: Validate at boundaries
public async Task<IActionResult> CreateWorkflow([FromBody] WorkflowRequest request)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    // Additional validation
    if (!IsValidWorkflowType(request.WorkflowType))
        return BadRequest("Invalid workflow type");
}

// BAD: No validation
public async Task<IActionResult> CreateWorkflow([FromBody] WorkflowRequest request)
{
    await _service.StartWorkflow(request); // Trusting input blindly!
}
```

#### Secret Management
```csharp
// CRITICAL: Hardcoded secrets
var connectionString = "Server=...;Password=secret123"; // NEVER!

// GOOD: Key Vault reference
// In configuration: @Microsoft.KeyVault(SecretUri=https://vault.vault.azure.net/secrets/ConnectionString)

// GOOD: Environment variable (for local dev only)
var connectionString = Environment.GetEnvironmentVariable("ConnectionString");
```

#### SQL Injection Prevention
```csharp
// BAD: String concatenation
var query = $"SELECT * FROM Users WHERE Id = '{userId}'"; // SQL Injection!

// GOOD: Parameterized queries
var query = "SELECT * FROM Users WHERE Id = @Id";
command.Parameters.AddWithValue("@Id", userId);

// GOOD: EF Core (parameterized by default)
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);
```

#### Service Bus / Cosmos Security
```csharp
// GOOD: Managed Identity
services.AddServiceBusClient(new DefaultAzureCredential());

// GOOD: Connection string from Key Vault
services.AddServiceBusClient(configuration["ServiceBus:ConnectionString"]);

// BAD: Hardcoded connection string
services.AddServiceBusClient("Endpoint=sb://...;SharedAccessKey=...");
```

#### Workflow Definition Validation
```csharp
// GOOD: Validate before deployment
public ValidationResult ValidateWorkflowDefinition(WorkflowDefinition def)
{
    var errors = new List<string>();

    // JSON schema validation
    if (!_schemaValidator.Validate(def))
        errors.Add("Invalid schema");

    // Activity name validation
    foreach (var state in def.States.Values.Where(s => s.Type == "task"))
    {
        if (!_activityRegistry.Exists(state.Activity))
            errors.Add($"Unknown activity: {state.Activity}");
    }

    // Reachability check
    if (!AllStatesReachable(def))
        errors.Add("Unreachable states detected");

    return new ValidationResult(errors);
}
```

### 5. SOLID Principles Check

- **S**: Single Responsibility - Each class/function has one reason to change
- **O**: Open/Closed - Extensible without modification
- **L**: Liskov Substitution - Subtypes are substitutable
- **I**: Interface Segregation - Specific interfaces over general
- **D**: Dependency Inversion - Depend on abstractions

## Output Format

```markdown
# Code Review Report

## Summary
- **Files Reviewed**: X
- **Critical Issues**: X
- **High Issues**: X
- **Medium Issues**: X
- **Low Issues**: X

## Findings

### [CRITICAL] Determinism Violation in Orchestrator
- **File**: `src/Orchestrators/MyOrchestrator.cs:45`
- **Issue**: Using `DateTime.Now` in orchestrator
- **Code**:
  ```csharp
  var timestamp = DateTime.Now; // Line 45
  ```
- **Fix**:
  ```csharp
  var timestamp = context.CurrentUtcDateTime;
  ```

### [HIGH] Non-Idempotent Activity
- **File**: `src/Activities/ProcessActivity.cs:20-35`
- **Issue**: Activity lacks idempotency check, will duplicate on retry
- **Fix**: Add idempotency key check before processing

### [MEDIUM] Missing Null Check
- **File**: `src/Services/MyService.cs:15`
- **Issue**: Parameter `input` not validated for null
- **Fix**: Add `ArgumentNullException.ThrowIfNull(input);`

### [LOW] Use Modern Collection Expression
- **File**: `src/Models/Config.cs:10`
- **Issue**: Using `new List<string>()` instead of collection expression
- **Fix**: Use `List<string> items = [];`

## Security Findings

### [CRITICAL] Potential SQL Injection
- **File**: `src/Data/Repository.cs:55`
- **Issue**: String interpolation in SQL query
- **Fix**: Use parameterized query

## Test Coverage Gaps
- `MyOrchestrator.cs` - No unit tests for error paths
- `ProcessActivity.cs` - No idempotency tests

## Recommendations
1. Fix all CRITICAL issues before merge
2. Add missing tests
3. Consider refactoring X for better maintainability
```

## Severity Definitions

| Severity | Definition |
|----------|------------|
| **Critical** | Security vulnerability, determinism violation, data loss risk - blocks merge |
| **High** | Bug, missing error handling, non-idempotent activity - should fix before merge |
| **Medium** | Code quality issue, missing validation - fix soon |
| **Low** | Style, naming, minor improvements - nice to have |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…