mirror of
https://github.com/samiyev/puaros.git
synced 2025-12-28 07:16:53 +05:00
feat: add entity exposure detection (v0.3.0)
Implement entity exposure detection to prevent domain entities from leaking to API responses. Detects when controllers/routes return domain entities instead of DTOs. Features: - EntityExposure value object with detailed suggestions - IEntityExposureDetector interface in domain layer - EntityExposureDetector implementation in infrastructure - Integration into AnalyzeProject use case - CLI display with helpful suggestions - 24 comprehensive unit tests (98% coverage) - Examples for bad and good patterns Detection scope: - Infrastructure layer only (controllers, routes, handlers, resolvers, gateways) - Identifies PascalCase entities without Dto/Request/Response suffixes - Parses async methods with Promise<T> return types - Provides step-by-step remediation suggestions Test coverage: - EntityExposureDetector: 98.07% - Overall project: 90.6% statements, 83.97% branches - 218 tests passing BREAKING CHANGE: Version bump to 0.3.0
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
// ❌ BAD: Exposing domain entity Order in API response
|
||||
|
||||
class Order {
|
||||
constructor(
|
||||
public id: string,
|
||||
public items: OrderItem[],
|
||||
public total: number,
|
||||
public customerId: string,
|
||||
) {}
|
||||
}
|
||||
|
||||
class OrderItem {
|
||||
constructor(
|
||||
public productId: string,
|
||||
public quantity: number,
|
||||
public price: number,
|
||||
) {}
|
||||
}
|
||||
|
||||
class BadOrderController {
|
||||
async getOrder(orderId: string): Promise<Order> {
|
||||
return {
|
||||
id: orderId,
|
||||
items: [],
|
||||
total: 100,
|
||||
customerId: "customer-123",
|
||||
}
|
||||
}
|
||||
|
||||
async listOrders(): Promise<Order[]> {
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* BAD EXAMPLE: Entity Exposure
|
||||
*
|
||||
* Guardian should detect:
|
||||
* ❌ Domain entity returned from controller
|
||||
* ❌ No DTO layer
|
||||
*
|
||||
* Why bad:
|
||||
* - Exposes internal structure
|
||||
* - Breaking changes propagate to API
|
||||
* - Can't version API independently
|
||||
* - Security risk (password fields, etc.)
|
||||
* - Violates Clean Architecture
|
||||
*/
|
||||
|
||||
class User {
|
||||
constructor(
|
||||
public id: string,
|
||||
public email: string,
|
||||
public passwordHash: string,
|
||||
public isAdmin: boolean,
|
||||
) {}
|
||||
}
|
||||
|
||||
export class BadUserController {
|
||||
/**
|
||||
* ❌ BAD: Returning domain entity directly!
|
||||
*/
|
||||
public async getUser(id: string): Promise<User> {
|
||||
return new User(id, "user@example.com", "hashed_password_exposed!", true)
|
||||
}
|
||||
|
||||
/**
|
||||
* ❌ BAD: Accepting domain entity as input!
|
||||
*/
|
||||
public async updateUser(user: User): Promise<User> {
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ GOOD VERSION:
|
||||
*
|
||||
* // application/dtos/UserResponseDto.ts
|
||||
* export interface UserResponseDto {
|
||||
* readonly id: string
|
||||
* readonly email: string
|
||||
* // NO password, NO internal fields
|
||||
* }
|
||||
*
|
||||
* // infrastructure/controllers/UserController.ts
|
||||
* export class UserController {
|
||||
* async getUser(id: string): Promise<UserResponseDto> {
|
||||
* const user = await this.getUserUseCase.execute(id)
|
||||
* return UserMapper.toDto(user) // Convert to DTO!
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
Reference in New Issue
Block a user