mirror of
https://github.com/bitwarden/server
synced 2026-02-13 23:13:22 +00:00
Update CLAUDE.md with improved testing patterns and architecture docs
Rewrote the Claude Code configuration file to provide clearer guidance: - Added comprehensive build/test commands including single test filtering - Documented architecture overview with deployable services and Core structure - Separated unit test and integration test patterns with AAA examples - Emphasized that integration tests should not mock and use real code paths - Consolidated critical rules and key patterns sections Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,77 +1,201 @@
|
||||
# Bitwarden Server - Claude Code Configuration
|
||||
# CLAUDE.md
|
||||
|
||||
## Project Context Files
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
**Read these files before reviewing to ensure that you fully understand the project and contributing guidelines**
|
||||
## Build and Test Commands
|
||||
|
||||
1. @README.md
|
||||
2. @CONTRIBUTING.md
|
||||
3. @.github/PULL_REQUEST_TEMPLATE.md
|
||||
```bash
|
||||
# Build
|
||||
dotnet build
|
||||
|
||||
# Run all tests
|
||||
dotnet test
|
||||
|
||||
# Run a single test project
|
||||
dotnet test test/Core.Test
|
||||
|
||||
# Run a single test class
|
||||
dotnet test --filter "FullyQualifiedName~DeleteGroupCommandTests"
|
||||
|
||||
# Run a single test method
|
||||
dotnet test --filter "FullyQualifiedName~DeleteGroupCommandTests.DeleteGroup_Success"
|
||||
|
||||
# Run locally (API)
|
||||
dotnet run --project src/Api
|
||||
|
||||
# Run locally (Identity)
|
||||
dotnet run --project src/Identity
|
||||
|
||||
# Database migrations
|
||||
pwsh dev/migrate.ps1 # MSSQL (default)
|
||||
pwsh dev/migrate.ps1 -postgres # PostgreSQL
|
||||
pwsh dev/migrate.ps1 -sqlite # SQLite
|
||||
pwsh dev/migrate.ps1 -mysql # MySQL
|
||||
pwsh dev/migrate.ps1 -all # All databases
|
||||
|
||||
# Generate OpenAPI specs
|
||||
pwsh dev/generate_openapi_files.ps1
|
||||
|
||||
# Enable git pre-commit hook for formatting
|
||||
git config --local core.hooksPath .git-hooks
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Deployable Services
|
||||
- **Api** - Main REST API for client applications
|
||||
- **Identity** - OAuth2/OpenID Connect token server (Duende IdentityServer)
|
||||
- **Admin** - Administrative portal
|
||||
- **Billing** - Billing and subscription management
|
||||
- **Events** - Event logging API
|
||||
- **EventsProcessor** - Background event processing
|
||||
- **Notifications** - Real-time push notifications via SignalR
|
||||
- **Icons** - Domain icon retrieval
|
||||
|
||||
### Core Library Structure (`src/Core`)
|
||||
The Core project is organized by **business domain**, not technical layers:
|
||||
- `Auth/` - Authentication, SSO, WebAuthn, two-factor
|
||||
- `Vault/` - Ciphers, folders, collections, sends
|
||||
- `AdminConsole/` - Organizations, users, policies, groups
|
||||
- `Billing/` - Subscriptions, payments, licensing
|
||||
- `SecretsManager/` - Secrets management (commercial)
|
||||
- `KeyManagement/` - Key rotation, signatures
|
||||
- `Tools/` - Import/export
|
||||
- `NotificationCenter/` - User notifications
|
||||
|
||||
Cross-cutting concerns:
|
||||
- `Entities/` - Domain models
|
||||
- `Repositories/` - Repository interfaces
|
||||
- `Services/` - Business logic services
|
||||
- `Context/` - `ICurrentContext` for request-scoped user/org data
|
||||
|
||||
### Infrastructure Layer
|
||||
Two ORM implementations exist for database flexibility:
|
||||
- **Infrastructure.Dapper** - SQL Server optimized (production cloud)
|
||||
- **Infrastructure.EntityFramework** - Supports PostgreSQL, MySQL, SQLite (self-hosted)
|
||||
|
||||
### Configuration
|
||||
- `dev/secrets.json` - Local development settings (copy from `secrets.json.example`)
|
||||
- `appsettings.{Environment}.json` - Environment-specific config
|
||||
- `GlobalSettings` class - Strongly-typed configuration
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
Tests use **xUnit** with **NSubstitute** for mocking and **AutoFixture** for test data. All tests must follow the **AAA (Arrange-Act-Assert)** pattern with clear section comments.
|
||||
|
||||
### Unit Tests
|
||||
Unit tests mock dependencies and test isolated business logic:
|
||||
|
||||
```csharp
|
||||
[SutProviderCustomize]
|
||||
public class DeleteGroupCommandTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteGroup_Success(SutProvider<DeleteGroupCommand> sutProvider, Group group)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<IGroupRepository>()
|
||||
.GetByIdAsync(group.Id)
|
||||
.Returns(group);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.DeleteGroupAsync(group.OrganizationId, group.Id);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received(1).DeleteAsync(group);
|
||||
await sutProvider.GetDependency<IEventService>().Received(1)
|
||||
.LogGroupEventAsync(group, EventType.Group_Deleted);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Key testing utilities:
|
||||
- `[BitAutoData]` - AutoFixture attribute for generating test data
|
||||
- `SutProvider<T>` - Helper for creating system-under-test with mocked dependencies
|
||||
- `[SutProviderCustomize]` - Attribute to enable SutProvider pattern
|
||||
|
||||
### Integration Tests
|
||||
Integration tests exercise real code paths with actual database operations. **Do not mock** - use real repositories and test helpers to set up data:
|
||||
|
||||
```csharp
|
||||
public class GroupRepositoryTests
|
||||
{
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task AddGroupUsersByIdAsync_CreatesGroupUsers(
|
||||
IGroupRepository groupRepository,
|
||||
IUserRepository userRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IOrganizationRepository organizationRepository)
|
||||
{
|
||||
// Arrange
|
||||
var user1 = await userRepository.CreateTestUserAsync("user1");
|
||||
var user2 = await userRepository.CreateTestUserAsync("user2");
|
||||
var org = await organizationRepository.CreateTestOrganizationAsync();
|
||||
var orgUser1 = await organizationUserRepository.CreateTestOrganizationUserAsync(org, user1);
|
||||
var orgUser2 = await organizationUserRepository.CreateTestOrganizationUserAsync(org, user2);
|
||||
var group = await groupRepository.CreateTestGroupAsync(org);
|
||||
|
||||
// Act
|
||||
await groupRepository.AddGroupUsersByIdAsync(group.Id, [orgUser1.Id, orgUser2.Id]);
|
||||
|
||||
// Assert
|
||||
var actual = await groupRepository.GetManyUserIdsByIdAsync(group.Id);
|
||||
Assert.Equal(new[] { orgUser1.Id, orgUser2.Id }.Order(), actual.Order());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
API integration tests use `ApiApplicationFactory` and real HTTP calls:
|
||||
|
||||
```csharp
|
||||
public class OrganizationsControllerTests : IClassFixture<ApiApplicationFactory>, IAsyncLifetime
|
||||
{
|
||||
[Fact]
|
||||
public async Task Put_AsOwner_CanUpdateOrganization()
|
||||
{
|
||||
// Arrange
|
||||
await _loginHelper.LoginAsync(_ownerEmail);
|
||||
var updateRequest = new OrganizationUpdateRequestModel
|
||||
{
|
||||
Name = "Updated Organization Name",
|
||||
BillingEmail = "newbilling@example.com"
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await _client.PutAsJsonAsync($"/organizations/{_organization.Id}", updateRequest);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var organizationRepository = _factory.GetService<IOrganizationRepository>();
|
||||
var updatedOrg = await organizationRepository.GetByIdAsync(_organization.Id);
|
||||
Assert.Equal("Updated Organization Name", updatedOrg.Name);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Key integration test attributes:
|
||||
- `[DatabaseTheory, DatabaseData]` - For repository tests against real databases
|
||||
- `IClassFixture<ApiApplicationFactory>` - For API controller tests
|
||||
|
||||
## Critical Rules
|
||||
|
||||
- **NEVER** use code regions: If complexity suggests regions, refactor for better readability
|
||||
- **NEVER** compromise zero-knowledge principles: User vault data must remain encrypted and inaccessible to Bitwarden servers
|
||||
- **NEVER** log sensitive data: No PII, passwords, keys, or vault data in logs or error messages
|
||||
- **NEVER** use code regions: Refactor for better readability instead
|
||||
- **ALWAYS** add unit tests with mocking for new features
|
||||
- **ALWAYS** use nullable reference types (enabled project-wide)
|
||||
|
||||
- **NEVER** compromise zero-knowledge principles: User vault data must remain encrypted and inaccessible to Bitwarden
|
||||
## Key Patterns
|
||||
|
||||
- **NEVER** log or expose sensitive data: No PII, passwords, keys, or vault data in logs or error messages
|
||||
|
||||
- **ALWAYS** use secure communication channels: Enforce confidentiality, integrity, and authenticity
|
||||
|
||||
- **ALWAYS** encrypt sensitive data: All vault data must be encrypted at rest, in transit, and in use
|
||||
|
||||
- **ALWAYS** prioritize cryptographic integrity and data protection
|
||||
|
||||
- **ALWAYS** add unit tests (with mocking) for any new feature development
|
||||
|
||||
## Project Structure
|
||||
|
||||
- **Source Code**: `/src/` - Services and core infrastructure
|
||||
- **Tests**: `/test/` - Test logic aligning with the source structure, albeit with a `.Test` suffix
|
||||
- **Utilities**: `/util/` - Migration tools, seeders, and setup scripts
|
||||
- **Dev Tools**: `/dev/` - Local development helpers
|
||||
- **Configuration**: `appsettings.{Environment}.json`, `/dev/secrets.json` for local development
|
||||
|
||||
## Security Requirements
|
||||
|
||||
- **Compliance**: SOC 2 Type II, SOC 3, HIPAA, ISO 27001, GDPR, CCPA
|
||||
- **Principles**: Zero-knowledge, end-to-end encryption, secure defaults
|
||||
- **Validation**: Input sanitization, parameterized queries, rate limiting
|
||||
- **Logging**: Structured logs, no PII/sensitive data in logs
|
||||
|
||||
## Common Commands
|
||||
|
||||
- **Build**: `dotnet build`
|
||||
- **Test**: `dotnet test`
|
||||
- **Run locally**: `dotnet run --project src/Api`
|
||||
- **Database update**: `pwsh dev/migrate.ps1`
|
||||
- **Generate OpenAPI**: `pwsh dev/generate_openapi_files.ps1`
|
||||
|
||||
## Development Workflow
|
||||
|
||||
- Security impact assessed
|
||||
- xUnit tests added / updated
|
||||
- Performance impact considered
|
||||
- Error handling implemented
|
||||
- Breaking changes documented
|
||||
- CI passes: build, test, lint
|
||||
- Feature flags considered for new features
|
||||
- CODEOWNERS file respected
|
||||
|
||||
### Key Architectural Decisions
|
||||
|
||||
- Use .NET nullable reference types (ADR 0024)
|
||||
- TryAdd dependency injection pattern (ADR 0026)
|
||||
- Authorization patterns (ADR 0022)
|
||||
- OpenTelemetry for observability (ADR 0020)
|
||||
- Log to standard output (ADR 0021)
|
||||
- **TryAdd DI pattern** - Services registered via extension methods (ADR 0026)
|
||||
- **Authorization handlers** - Custom `IAuthorizationHandler` implementations per domain
|
||||
- **Feature flags** - `IFeatureService` with LaunchDarkly for opt-in features
|
||||
- **Tokenables** - `DataProtectorTokenFactory` for secure token generation
|
||||
- **Self-hosted branching** - `if (globalSettings.SelfHosted)` for deployment-specific logic
|
||||
|
||||
## References
|
||||
|
||||
- [Server architecture](https://contributing.bitwarden.com/architecture/server/)
|
||||
- [Architectural Decision Records (ADRs)](https://contributing.bitwarden.com/architecture/adr/)
|
||||
- [Contributing guidelines](https://contributing.bitwarden.com/contributing/)
|
||||
- [ADRs](https://contributing.bitwarden.com/architecture/adr/)
|
||||
- [Setup guide](https://contributing.bitwarden.com/getting-started/server/guide/)
|
||||
- [Code style](https://contributing.bitwarden.com/contributing/code-style/)
|
||||
- [Bitwarden security whitepaper](https://bitwarden.com/help/bitwarden-security-white-paper/)
|
||||
- [Bitwarden security definitions](https://contributing.bitwarden.com/architecture/security/definitions)
|
||||
|
||||
Reference in New Issue
Block a user