修复代码审查和安全扫描反馈 · ID碰撞修复+权限声明+正则安全+敏感信息过滤

Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/c4628b3c-e295-41e0-bdd7-1459958b5390

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-04-08 13:23:34 +00:00 committed by GitHub
parent 43105b62e4
commit 0189965e05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 39 additions and 26 deletions

View File

@ -29,6 +29,9 @@ jobs:
alert-scan:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
steps:
- name: 签出代码
@ -68,14 +71,16 @@ jobs:
console.log(JSON.stringify(commLink, null, 2));
// 输出结果
console.log('::set-output name=critical::' + alerts.critical);
console.log('::set-output name=total::' + alerts.total);
console.log('::set-output name=health::' + commLink.health);
const fs = require('fs');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'critical=' + alerts.critical + '\n');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'total=' + alerts.total + '\n');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'health=' + commLink.health + '\n');
} catch (err) {
console.error('扫描失败:', err.message);
console.log('::set-output name=critical::0');
console.log('::set-output name=total::0');
console.log('::set-output name=health::error');
const fs = require('fs');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'critical=0\n');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'total=0\n');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'health=error\n');
}
})();
"

View File

@ -35,6 +35,8 @@ jobs:
training:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- name: 签出代码
@ -65,12 +67,14 @@ jobs:
console.log(JSON.stringify(status, null, 2));
// 输出待处理数量
const pending = status.pending || 0;
console.log('::set-output name=pending::' + pending);
console.log('::set-output name=status::success');
const fs = require('fs');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'pending=' + pending + '\n');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'status=success\n');
} catch (err) {
console.error('语料检查失败:', err.message);
console.log('::set-output name=status::error');
console.log('::set-output name=error::' + err.message);
const fs = require('fs');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'status=error\n');
fs.appendFileSync(process.env.GITHUB_OUTPUT, 'error=' + err.message + '\n');
}
})();
"

View File

@ -389,7 +389,7 @@ function transformGPTToTCS(content, sourceKey) {
if (conversation.mapping) {
// ChatGPT格式
for (const [, node] of Object.entries(conversation.mapping)) {
if (node.message?.content?.parts) {
if (node.message?.content?.parts && Array.isArray(node.message.content.parts)) {
const text = node.message.content.parts.join('\n');
if (text.trim()) {
messages.push({

View File

@ -27,6 +27,7 @@
'use strict';
const crypto = require('crypto');
const cos = require('../cos');
// ─── 路径常量 ───
@ -145,7 +146,7 @@ async function cosDispatchTask(input) {
if (!title) throw new Error('缺少 title');
const targetBucket = bucket || 'team';
const tId = task_id || `TASK-${formatDate()}-${String(Math.floor(Math.random() * 1000)).padStart(3, '0')}`;
const tId = task_id || `TASK-${formatDate()}-${crypto.randomBytes(4).toString('hex')}`;
// 验证 task_id 安全性
if (!/^[a-zA-Z0-9_-]+$/.test(tId)) {

View File

@ -28,8 +28,8 @@
'use strict';
const crypto = require('crypto');
const cos = require('../cos');
// 运行时可选加载 notion-client不影响核心功能
let notionClient = null;
try {
@ -40,6 +40,7 @@ try {
// ─── 常量 ───
const MIRROR_PREFIX = 'notion-mirror/';
const MIRROR_PREFIX_REGEX = /^notion-mirror\/([^/]+)\//;
const WORKORDER_PREFIX = 'workorders/';
/**
@ -158,7 +159,7 @@ async function notionCosListMirror(input) {
// 提取唯一的page_id
const pageIds = new Set();
for (const file of result.files) {
const match = file.key.match(new RegExp(`^${MIRROR_PREFIX.replace(/[/]/g, '\\/')}([^/]+)\\/`));
const match = file.key.match(MIRROR_PREFIX_REGEX);
if (match) pageIds.add(match[1]);
}
@ -202,7 +203,7 @@ async function notionCosBuildIndex(input) {
// 提取唯一的page_id和元数据
const pageMap = {};
for (const file of result.files) {
const match = file.key.match(new RegExp(`^${MIRROR_PREFIX.replace(/[/]/g, '\\/')}([^/]+)\\/`));
const match = file.key.match(MIRROR_PREFIX_REGEX);
if (match) {
const pageId = match[1];
if (!pageMap[pageId]) pageMap[pageId] = { files: [] };
@ -277,7 +278,7 @@ async function notionCosWriteWorkorder(input) {
if (!title) throw new Error('缺少 title');
const targetBucket = bucket || 'team';
const woId = workorder_id || `WO-${formatDate()}-${String(Math.floor(Math.random() * 1000)).padStart(3, '0')}`;
const woId = workorder_id || `WO-${formatDate()}-${crypto.randomBytes(4).toString('hex')}`;
// 验证 workorder_id 安全性
if (!/^[a-zA-Z0-9_-]+$/.test(woId)) {

View File

@ -234,13 +234,10 @@ async function notionRepairPermissions(input) {
let repaired = 0;
let failed = 0;
// 1. 尝试重新连接(清除缓存的客户端实例)
// 1. 尝试重新连接
if (auto_retry) {
repairLog.push({ step: '重新初始化Notion客户端', status: 'attempting' });
try {
// 通过重新require来重置客户端
delete require.cache[require.resolve('../notion-client')];
notionClient = require('../notion-client');
const check = await notionClient.checkConnection();
if (check.connected) {
repairLog.push({ step: '重新连接', status: 'success', user: check.user });

View File

@ -27,6 +27,7 @@
'use strict';
const https = require('https');
const crypto = require('crypto');
const cos = require('../cos');
// ─── LLM 配置 ───
@ -71,6 +72,10 @@ const LLM_CONFIGS = {
// ─── 模型降级路由 ───
const MODEL_FALLBACK_CHAIN = ['deepseek-v3', 'qwen-max', 'glm-4-long', 'moonshot-128k'];
// ─── 常量 ───
const MAX_CONTENT_FOR_ANALYSIS = 3000;
const MAX_PROMPT_CONTENT = 5000;
/**
* trainingStartSession 启动训练会话
*
@ -85,7 +90,7 @@ async function trainingStartSession(input) {
const { persona_id, corpus_bucket, corpus_prefix, target_model, session_name } = input;
if (!persona_id) throw new Error('缺少 persona_id');
const sessionId = `train-${persona_id}-${Date.now()}`;
const sessionId = `train-${persona_id}-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
const now = new Date().toISOString();
// 扫描可用语料
@ -175,8 +180,8 @@ async function trainingProcessCorpus(input) {
for (const entry of toProcess) {
// 用LLM分析和分类
const contentForAnalysis = typeof entry.content === 'string'
? entry.content.substring(0, 3000)
: JSON.stringify(entry).substring(0, 3000);
? entry.content.substring(0, MAX_CONTENT_FOR_ANALYSIS)
: JSON.stringify(entry).substring(0, MAX_CONTENT_FOR_ANALYSIS);
const classificationPrompt = buildClassificationPrompt(persona_id, corpus.corpus_type, contentForAnalysis);
@ -246,7 +251,7 @@ async function trainingClassifyEntry(input) {
const prompt = buildClassificationPrompt(
persona_id,
corpus_type || 'generic',
content.substring(0, 5000)
content.substring(0, MAX_PROMPT_CONTENT)
);
const llmResult = await callLLMWithFallback(prompt, model);
@ -521,10 +526,10 @@ function callLLM(config, apiKey, prompt) {
tokens: data.usage || {}
});
} catch {
reject(new Error(`LLM响应解析失败: ${responseBody.substring(0, 200)}`));
reject(new Error(`LLM响应解析失败`));
}
} else {
reject(new Error(`LLM调用失败 ${res.statusCode}: ${responseBody.substring(0, 200)}`));
reject(new Error(`LLM调用失败 ${res.statusCode}`));
}
});
});