fix(SEC-API-21): Add DTO validation for semantic/hybrid search body
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

Replace inline type annotations with proper class-validator DTOs for the
semantic and hybrid search endpoints. Adds SemanticSearchBodyDto,
HybridSearchBodyDto (query: @IsString @MaxLength(500), status:
@IsOptional @IsEnum(EntryStatus)), and SemanticSearchQueryDto (page/limit
with @IsInt @Min/@Max validation). Includes 22 new tests covering DTO
validation edge cases and controller integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-06 13:35:06 -06:00
parent 17cfeb974b
commit bb6e08208c
4 changed files with 338 additions and 14 deletions

View File

@@ -1,10 +1,16 @@
import { Controller, Get, Post, Body, Query, UseGuards } from "@nestjs/common";
import { SearchService, PaginatedSearchResults } from "./services/search.service";
import { SearchQueryDto, TagSearchDto, RecentEntriesDto } from "./dto";
import {
SearchQueryDto,
TagSearchDto,
RecentEntriesDto,
SemanticSearchBodyDto,
SemanticSearchQueryDto,
HybridSearchBodyDto,
} from "./dto";
import { AuthGuard } from "../auth/guards/auth.guard";
import { WorkspaceGuard, PermissionGuard } from "../common/guards";
import { Workspace, Permission, RequirePermission } from "../common/decorators";
import { EntryStatus } from "@prisma/client";
import type { PaginatedEntries, KnowledgeEntryWithTags } from "./entities/knowledge-entry.entity";
/**
@@ -112,14 +118,13 @@ export class SearchController {
@RequirePermission(Permission.WORKSPACE_ANY)
async semanticSearch(
@Workspace() workspaceId: string,
@Body() body: { query: string; status?: EntryStatus },
@Query("page") page?: number,
@Query("limit") limit?: number
@Body() body: SemanticSearchBodyDto,
@Query() query: SemanticSearchQueryDto
): Promise<PaginatedSearchResults> {
return this.searchService.semanticSearch(body.query, workspaceId, {
status: body.status,
page,
limit,
page: query.page,
limit: query.limit,
});
}
@@ -138,14 +143,13 @@ export class SearchController {
@RequirePermission(Permission.WORKSPACE_ANY)
async hybridSearch(
@Workspace() workspaceId: string,
@Body() body: { query: string; status?: EntryStatus },
@Query("page") page?: number,
@Query("limit") limit?: number
@Body() body: HybridSearchBodyDto,
@Query() query: SemanticSearchQueryDto
): Promise<PaginatedSearchResults> {
return this.searchService.hybridSearch(body.query, workspaceId, {
status: body.status,
page,
limit,
page: query.page,
limit: query.limit,
});
}
}