fix: M2-02/06 audit — system KB seed + candidate Content Safety
Some checks failed
Deploy API Server / build-and-deploy (push) Failing after 19s

- SystemKnowledgeBaseSeed: auto-creates built-in 新手引导知识库
- Content Safety check on candidate accept() and createCandidates()

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
WangDL 2026-05-24 13:58:50 +08:00
parent 0c07b59765
commit 3c242a807a
3 changed files with 52 additions and 3 deletions

View File

@ -1,14 +1,22 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { Injectable, NotFoundException, Optional } from '@nestjs/common';
import { ImportCandidateRepository } from './import-candidate.repository';
import { KnowledgeItemsRepository } from '../knowledge-items/knowledge-items.repository';
import { ContentSafetyService } from '../content-safety/content-safety.service';
@Injectable()
export class ImportCandidateService {
constructor(
private readonly repository: ImportCandidateRepository,
private readonly itemsRepo: KnowledgeItemsRepository,
@Optional() private readonly safety?: ContentSafetyService,
) {}
private async checkSafety(title: string, content: string, userId: string): Promise<boolean> {
if (!this.safety) return true;
const check = await this.safety.check(title + ' ' + (content || '').slice(0, 200), { userId, contentType: 'candidate' });
return check.safe;
}
async findBySource(sourceId: string) {
return this.repository.findBySource(sourceId);
}
@ -23,6 +31,10 @@ export class ImportCandidateService {
const candidate = await this.repository.findById(id);
if (!candidate) throw new NotFoundException('候选知识点不存在');
// Content safety check before accepting
const safe = await this.checkSafety(candidate.title, candidate.content || '', candidate.userId);
if (!safe) return { status: 'BLOCKED', reason: '内容安全审核未通过' };
await this.repository.updateStatus(id, 'ACCEPTED');
// 生成 KnowledgeItem
@ -60,6 +72,13 @@ export class ImportCandidateService {
}
async createCandidates(userId: string, knowledgeBaseId: string, sourceId: string, importId: string, candidates: Array<any>) {
return this.repository.createMany(userId, knowledgeBaseId, sourceId, importId, candidates);
// Filter out unsafe candidates
const safeCandidates = [];
for (const c of candidates) {
const safe = await this.checkSafety(c.title || '', c.content || '', userId);
if (safe) safeCandidates.push(c);
}
if (safeCandidates.length === 0) return { created: 0, filtered: candidates.length };
return this.repository.createMany(userId, knowledgeBaseId, sourceId, importId, safeCandidates);
}
}

View File

@ -2,11 +2,12 @@ import { Module } from '@nestjs/common';
import { KnowledgeBaseController } from './knowledge-base.controller';
import { KnowledgeBaseService } from './knowledge-base.service';
import { KnowledgeBaseRepository } from './knowledge-base.repository';
import { SystemKnowledgeBaseSeed } from './system-kb.seed';
import { PrismaService } from '../../infrastructure/database/prisma.service';
@Module({
controllers: [KnowledgeBaseController],
providers: [KnowledgeBaseService, KnowledgeBaseRepository, PrismaService],
providers: [KnowledgeBaseService, KnowledgeBaseRepository, SystemKnowledgeBaseSeed, PrismaService],
exports: [KnowledgeBaseService],
})
export class KnowledgeBaseModule {}

View File

@ -0,0 +1,29 @@
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { PrismaService } from '../../infrastructure/database/prisma.service';
const SYSTEM_KB = {
id: 'system-builtin-kb',
userId: 'system',
title: '新手引导知识库',
description: '系统内置知识库,帮助新用户了解知习的使用方法',
status: 'active',
};
@Injectable()
export class SystemKnowledgeBaseSeed implements OnModuleInit {
private readonly logger = new Logger(SystemKnowledgeBaseSeed.name);
constructor(private readonly prisma: PrismaService) {}
async onModuleInit() {
try {
await this.prisma.knowledgeBase.upsert({
where: { id: SYSTEM_KB.id },
update: {},
create: SYSTEM_KB,
});
} catch {
this.logger.warn('Failed to seed system knowledge base');
}
}
}