feat(#356): Build credential CRUD API endpoints

Implement comprehensive CRUD API for managing user credentials with encryption,
RLS, and audit logging following TDD methodology.

Features:
- POST /api/credentials - Create encrypted credential
- GET /api/credentials - List credentials (masked values only)
- GET /api/credentials/:id - Get single credential (masked)
- GET /api/credentials/:id/value - Decrypt plaintext (rate limited 10/min)
- PATCH /api/credentials/:id - Update metadata
- POST /api/credentials/:id/rotate - Rotate credential value
- DELETE /api/credentials/:id - Soft delete

Security:
- All values encrypted via VaultService (TransitKey.CREDENTIALS)
- List/Get endpoints NEVER return plaintext (only maskedValue)
- getValue endpoint rate limited to 10 requests/minute per user
- All operations audit-logged with CREDENTIAL_* ActivityAction
- RLS enforces per-user isolation via getRlsClient() pattern
- Input validation via class-validator DTOs

Testing:
- 26/26 unit tests passing
- 95.71% code coverage (exceeds 85% requirement)
  - Service: 95.16%
  - Controller: 100%
- TypeScript checks pass

Files created:
- apps/api/src/credentials/credentials.service.ts
- apps/api/src/credentials/credentials.service.spec.ts
- apps/api/src/credentials/credentials.controller.ts
- apps/api/src/credentials/credentials.controller.spec.ts
- apps/api/src/credentials/credentials.module.ts
- apps/api/src/credentials/dto/*.dto.ts (5 DTOs)

Files modified:
- apps/api/src/app.module.ts - imported CredentialsModule

Note: Admin credentials endpoints deferred to future issue. Current
implementation covers all user credential endpoints.

Refs #346
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 16:50:02 -06:00
parent aa2ee5aea3
commit 46d0a06ef5
14 changed files with 1566 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
# Issue #356: Build credential CRUD API endpoints
## Objective
Implement CRUD API endpoints for managing user credentials with encryption, RLS, and audit logging.
## Approach
Following TDD approach:
1. Create DTOs with validation
2. Write service tests first (RED)
3. Implement service with VaultService integration (GREEN)
4. Write controller tests (RED)
5. Implement controller with guards (GREEN)
6. Create module and wire dependencies
7. Verify all tests pass with 85%+ coverage
## Key Patterns Followed
- RLS: Use `getRlsClient() ?? this.prisma` pattern
- Encryption: Use VaultService with TransitKey.CREDENTIALS
- Activity logging: Fire-and-forget pattern like existing activity helpers
- DTOs: class-validator decorators for input validation
- Guards: AuthGuard + WorkspaceGuard + PermissionGuard
- Rate limiting: @Throttle decorator on getValue endpoint (10/minute)
## Files Created
- [x] apps/api/src/credentials/dto/create-credential.dto.ts
- [x] apps/api/src/credentials/dto/update-credential.dto.ts
- [x] apps/api/src/credentials/dto/query-credential.dto.ts
- [x] apps/api/src/credentials/dto/credential-response.dto.ts
- [x] apps/api/src/credentials/dto/rotate-credential.dto.ts
- [x] apps/api/src/credentials/dto/index.ts
- [x] apps/api/src/credentials/credentials.service.spec.ts (18 tests - all passing)
- [x] apps/api/src/credentials/credentials.service.ts
- [x] apps/api/src/credentials/credentials.controller.spec.ts (8 tests - all passing)
- [x] apps/api/src/credentials/credentials.controller.ts
- [x] apps/api/src/credentials/credentials.module.ts
- [x] apps/api/src/credentials/index.ts
## Files Modified
- [x] apps/api/src/app.module.ts - imported CredentialsModule
## Admin Credentials Controller
**Decision: Not implemented in this phase**
- Issue #356 listed admin endpoints as optional ("Admin Secret Endpoints")
- The UserCredential model supports SYSTEM scope for admin secrets
- Admin endpoints can be added in a future issue when needed
- Current implementation covers all user credential endpoints
## Testing Results
- Service tests: 18/18 passing
- Controller tests: 8/8 passing
- Total: 26/26 tests passing
- Coverage: **95.71%** (exceeds 85% requirement)
- Service: 95.16%
- Controller: 100%
- TypeScript: All checks pass
## Endpoints Implemented
- POST /api/credentials - Create credential
- GET /api/credentials - List credentials (masked values only)
- GET /api/credentials/:id - Get single credential (masked value only)
- GET /api/credentials/:id/value - Decrypt and return plaintext (rate limited 10/min)
- PATCH /api/credentials/:id - Update metadata
- POST /api/credentials/:id/rotate - Rotate credential value
- DELETE /api/credentials/:id - Soft delete
## Security Features
- All credential values encrypted with VaultService (TransitKey.CREDENTIALS)
- List/Get endpoints NEVER return plaintext (only maskedValue)
- getValue endpoint rate limited to 10 requests/minute per user
- All operations audit-logged with CREDENTIAL\_\* ActivityAction enums
- RLS enforces per-user isolation
- Input validation via class-validator DTOs
## Notes
- CREDENTIAL\_\* ActivityAction enums already existed in schema (from issue #355)
- Used existing activity logging pattern (fire-and-forget)
- Followed existing controller patterns for guards and decorators
- maskedValue shows last 4 characters with \*\*\*\* prefix
- TypeScript exactOptionalPropertyTypes required careful handling in update method