diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index c1349e8c9d..ac522e6a2a 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -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 sutProvider, Group group) + { + // Arrange + sutProvider.GetDependency() + .GetByIdAsync(group.Id) + .Returns(group); + + // Act + await sutProvider.Sut.DeleteGroupAsync(group.OrganizationId, group.Id); + + // Assert + await sutProvider.GetDependency().Received(1).DeleteAsync(group); + await sutProvider.GetDependency().Received(1) + .LogGroupEventAsync(group, EventType.Group_Deleted); + } +} +``` + +Key testing utilities: +- `[BitAutoData]` - AutoFixture attribute for generating test data +- `SutProvider` - 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, 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(); + 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` - 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)