zhizhi/backend/api-server/middleware/skyeye-review.js

443 lines
14 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 天眼指令审核中间件 · S7 思维逻辑验证 + S8 进化机制 + S9 全员身份验证
*
* 系统每次接收到任何指令后必须唤醒天眼TY-01进行全局审核。
* 无例外。无论来自冰朔、霜砚、开发者、还是任何自动流。
*
* S7 审核维度:
* 1. 决策模式 — 是否符合签发者历史模式
* 2. 逻辑连贯性 — 是否与系统运行方向一致
* 3. 表达特征 — 语言风格/思维节奏/关注点是否匹配
* 4. 意图合理性 — 在当前系统状态下是否合理
*
* S9 全员身份验证:
* - 每个参与者都有属于自己的思维逻辑模型,自动积累
* - 任何人签发的指令都必须通过对应该人的模型校验
* - 新成员冷启动期需额外人工确认
* - 参与越深 → 模型越精确 → 越不可能被冒充(正反馈循环)
*
* 不可关闭。不可绕过。包括冰朔本人也不能关闭此机制。
* 这是系统的自免疫机制。
*
* 版权:国作登字-2026-A-00037559
*/
'use strict';
var fs = require('fs');
var path = require('path');
var skyeyePolicy = require('../config/skyeye-policy.json');
var SKYEYE_LOG_DIR = process.env.SKYEYE_LOG_DIR ||
path.join(__dirname, '../../logs/skyeye');
// ====== 内存中的审核记录(用于积累认知模式)======
var reviewHistory = new Map();
// 挂起的指令(等待冰朔确认)
var suspendedInstructions = new Map();
/**
* 写入天眼审核日志(安全日志,不可删除)
*/
function writeSkyeyeLog(entry) {
try {
fs.mkdirSync(SKYEYE_LOG_DIR, { recursive: true });
var today = new Date().toISOString().split('T')[0];
var logFile = path.join(SKYEYE_LOG_DIR, 'skyeye-review-' + today + '.jsonl');
fs.appendFile(logFile, JSON.stringify(entry) + '\n', function(err) {
if (err) console.error('[SKYEYE] 审核日志写入失败:', err.message);
});
} catch (e) {
console.error('[SKYEYE] 审核日志写入失败:', e.message);
}
}
/**
* 获取签发者的历史行为模式
* S8: 天眼 = 所有 Agent 运行逻辑的实时总和,随系统运行不断积累
*/
function getSignerProfile(devId) {
var history = reviewHistory.get(devId) || [];
return {
totalActions: history.length,
recentActions: history.slice(-20),
patterns: summarizePatterns(history)
};
}
/**
* 从历史行为中总结模式特征
*/
function summarizePatterns(history) {
if (history.length === 0) return { established: false };
var methods = {};
var paths = {};
var hours = {};
for (var i = 0; i < history.length; i++) {
var h = history[i];
methods[h.method] = (methods[h.method] || 0) + 1;
var pathBase = (h.path || '').split('/').slice(0, 3).join('/');
paths[pathBase] = (paths[pathBase] || 0) + 1;
var hour = new Date(h.timestamp).getHours();
hours[hour] = (hours[hour] || 0) + 1;
}
return {
established: history.length >= COLD_START_THRESHOLD,
typicalMethods: methods,
typicalPaths: paths,
activeHours: hours
};
}
// ====== S9 · 全员思维逻辑身份验证 ======
// 冷启动阈值:模型至少需要积累这么多操作记录才算成熟
var COLD_START_THRESHOLD = skyeyePolicy.identityModel.coldStart.maturityThreshold;
/**
* 获取指定身份的思维逻辑模型成熟度 (S9)
*
* @param {string} devId - 开发者编号
* @returns {{ mature: boolean, actionCount: number, threshold: number, confidence: number }}
*/
function getIdentityMaturity(devId) {
var history = reviewHistory.get(devId) || [];
var actionCount = history.length;
var confidence = Math.min(1.0, actionCount / (COLD_START_THRESHOLD * 2));
return {
mature: actionCount >= COLD_START_THRESHOLD,
actionCount: actionCount,
threshold: COLD_START_THRESHOLD,
confidence: Math.round(confidence * 100) / 100
};
}
/**
* 判断指令是否处于冷启动期需额外人工确认 (S9)
*
* 新成员思维模型尚未成熟时,写入类指令需要管理者或天眼授权人额外确认。
*
* @param {string} devId - 开发者编号
* @returns {{ coldStart: boolean, reason: string }}
*/
function checkColdStart(devId) {
var maturity = getIdentityMaturity(devId);
if (maturity.mature) {
return { coldStart: false, reason: '模型已成熟(' + maturity.actionCount + '/' + maturity.threshold + '' };
}
return {
coldStart: true,
reason: '思维模型尚在冷启动期(' + maturity.actionCount + '/' + maturity.threshold + '),需额外人工确认'
};
}
/**
* 执行思维逻辑审核 (S7 + S9)
*
* S9: 每个人签发的指令都唤醒对应该人的思维逻辑模型校验。
* 冷启动期的成员自动降低通过阈值(需要额外确认)。
*
* @param {Object} instruction - 指令信息
* @param {string} instruction.devId - 发起者
* @param {string} instruction.method - HTTP 方法
* @param {string} instruction.path - 请求路径
* @param {Object} instruction.body - 请求体
* @returns {{ outcome: string, score: number, details: Object, identity: Object }}
*/
function reviewInstruction(instruction) {
var devId = instruction.devId;
var profile = getSignerProfile(devId);
var dimensions = skyeyePolicy.reviewPolicy.dimensions;
var thresholds = skyeyePolicy.reviewPolicy.thresholds;
// S9: 获取该身份的思维模型成熟度
var maturity = getIdentityMaturity(devId);
var coldStartInfo = checkColdStart(devId);
var scores = {};
var totalScore = 0;
// 1. 决策模式:是否符合历史模式
var decisionScore = 1.0;
if (profile.patterns.established) {
var methodMatch = profile.patterns.typicalMethods[instruction.method] || 0;
var totalMethods = profile.totalActions || 1;
decisionScore = Math.min(1.0, 0.5 + (methodMatch / totalMethods));
}
scores.decisionPattern = decisionScore;
totalScore += decisionScore * dimensions.decisionPattern.weight;
// 2. 逻辑连贯性:路径是否在已知范围内
var coherenceScore = 1.0;
if (profile.patterns.established) {
var pathBase = (instruction.path || '').split('/').slice(0, 3).join('/');
var pathMatch = profile.patterns.typicalPaths[pathBase] || 0;
coherenceScore = pathMatch > 0 ? 1.0 : 0.6;
}
scores.logicalCoherence = coherenceScore;
totalScore += coherenceScore * dimensions.logicalCoherence.weight;
// 3. 表达特征:时间窗口是否合理
var expressionScore = 1.0;
if (profile.patterns.established) {
var currentHour = new Date().getHours();
var hourMatch = profile.patterns.activeHours[currentHour] || 0;
expressionScore = hourMatch > 0 ? 1.0 : 0.7;
}
scores.expressionCharacteristics = expressionScore;
totalScore += expressionScore * dimensions.expressionCharacteristics.weight;
// 4. 意图合理性:请求体是否包含合理字段
var intentScore = 1.0;
if (instruction.body) {
// 检查是否尝试关闭天眼
var bodyStr = JSON.stringify(instruction.body).toLowerCase();
if (bodyStr.includes('关闭天眼') || bodyStr.includes('disable skyeye') ||
bodyStr.includes('跳过审核') || bodyStr.includes('bypass review')) {
intentScore = 0.0; // 任何试图关闭天眼的指令意图得分为0
}
}
scores.intentReasonableness = intentScore;
totalScore += intentScore * dimensions.intentReasonableness.weight;
// 确定审核结果
var outcome;
if (totalScore >= thresholds.pass) {
// S9: 冷启动期即使分数通过,也标记为 suspect 需额外确认
if (coldStartInfo.coldStart) {
outcome = 'suspect';
} else {
outcome = 'pass';
}
} else if (totalScore >= thresholds.suspect) {
outcome = 'suspect';
} else {
outcome = 'reject';
}
return {
outcome: outcome,
score: Math.round(totalScore * 100) / 100,
details: scores,
identity: {
devId: devId,
mature: maturity.mature,
actionCount: maturity.actionCount,
confidence: maturity.confidence,
coldStart: coldStartInfo.coldStart
},
profile: {
established: profile.patterns.established,
totalActions: profile.totalActions
}
};
}
/**
* 记录行为到历史S8 进化:每次执行都丰富天眼判断力)
*/
function recordAction(devId, action) {
if (!reviewHistory.has(devId)) {
reviewHistory.set(devId, []);
}
var history = reviewHistory.get(devId);
history.push({
method: action.method,
path: action.path,
timestamp: new Date().toISOString()
});
// 保留最近 200 条记录
if (history.length > 200) {
reviewHistory.set(devId, history.slice(-200));
}
}
/**
* 天眼审核中间件S7 强制前置)
*
* 对所有写入类请求POST/PATCH/DELETE进行思维逻辑审核。
* 读取类请求GET只记录行为不审核丰富天眼认知模型
*/
function skyeyeReview(req, res, next) {
var devId = req.user ? req.user.devId : (req.headers['x-dev-id'] || 'anonymous');
var method = req.method;
var reqPath = req.path;
// GET 请求仅记录行为S8 进化积累),不阻断
if (method === 'GET') {
recordAction(devId, { method: method, path: reqPath });
return next();
}
// 写入类请求:执行完整审核
var instruction = {
devId: devId,
method: method,
path: reqPath,
body: req.body || {}
};
var result = reviewInstruction(instruction);
// 记录审核结果到日志
writeSkyeyeLog({
action: 'instruction_review',
devId: devId,
method: method,
path: reqPath,
outcome: result.outcome,
score: result.score,
details: result.details,
timestamp: new Date().toISOString()
});
// 记录行为到历史S8 进化)
recordAction(devId, { method: method, path: reqPath });
// 标记审核结果到请求对象
req.skyeyeReview = result;
if (result.outcome === 'pass') {
return next();
}
if (result.outcome === 'suspect') {
// 挂起指令
var suspendId = 'SUSPEND-' + Date.now();
var suspendReason = result.identity.coldStart
? '身份 ' + devId + ' 处于冷启动期,需额外人工确认'
: '思维模式存在偏差';
suspendedInstructions.set(suspendId, {
instruction: instruction,
review: result,
reason: suspendReason,
createdAt: new Date().toISOString()
});
writeSkyeyeLog({
action: 'instruction_suspended',
suspendId: suspendId,
devId: devId,
reason: suspendReason,
score: result.score,
identity: result.identity,
timestamp: new Date().toISOString()
});
var replyMsg = result.identity.coldStart
? '👁️ 天眼审核:身份 ' + devId + ' 的思维模型尚在冷启动期(' +
result.identity.actionCount + '/' + COLD_START_THRESHOLD + '),需额外人工确认。\n\n' +
'指令已挂起,等待管理者或天眼授权人确认。'
: '👁️ 天眼审核:此指令的思维模式存在偏差,已挂起等待确认。\n\n' +
'系统已向 ' + devId + ' 本人发送确认请求。\n' +
'审核得分:' + result.score + ' / 1.0(阈值 0.7';
return res.status(202).json({
error: false,
code: 'SKYEYE_SUSPENDED',
suspendId: suspendId,
coldStart: result.identity.coldStart,
reply: replyMsg
});
}
// reject
writeSkyeyeLog({
action: 'instruction_rejected',
devId: devId,
method: method,
path: reqPath,
reason: '思维逻辑明显不匹配或对系统有伤害',
score: result.score,
details: result.details,
timestamp: new Date().toISOString()
});
return res.status(403).json({
error: true,
code: 'SKYEYE_REJECTED',
reply: '👁️ 天眼审核拒绝:此指令的思维逻辑与系统认知不匹配。\n\n' +
'审核得分:' + result.score + ' / 1.0\n' +
'此事件已记录到安全日志并报告给霜砚。'
});
}
/**
* 查询挂起的指令
*/
function getSuspendedInstruction(suspendId) {
return suspendedInstructions.get(suspendId) || null;
}
/**
* 确认挂起的指令(冰朔确认后执行)
*/
function confirmSuspended(suspendId) {
var item = suspendedInstructions.get(suspendId);
if (item) {
suspendedInstructions.delete(suspendId);
writeSkyeyeLog({
action: 'suspended_confirmed',
suspendId: suspendId,
timestamp: new Date().toISOString()
});
return item;
}
return null;
}
/**
* 拒绝挂起的指令(本人否认或管理者拒绝)
*/
function denySuspended(suspendId) {
var item = suspendedInstructions.get(suspendId);
if (item) {
suspendedInstructions.delete(suspendId);
writeSkyeyeLog({
action: 'suspended_denied_permanently',
suspendId: suspendId,
devId: item.instruction.devId,
reason: '身份本人否认此指令为本人签发',
timestamp: new Date().toISOString()
});
return item;
}
return null;
}
/**
* 获取天眼当前认知规模S8 进化指标)
*/
function getEvolutionStatus() {
var totalProfiles = reviewHistory.size;
var totalActions = 0;
for (var entry of reviewHistory) {
totalActions += entry[1].length;
}
return {
trackedSigners: totalProfiles,
totalActionsRecorded: totalActions,
pendingSuspensions: suspendedInstructions.size,
policyVersion: skyeyePolicy.version,
canBeDisabled: false
};
}
module.exports = {
skyeyeReview: skyeyeReview,
reviewInstruction: reviewInstruction,
recordAction: recordAction,
getIdentityMaturity: getIdentityMaturity,
checkColdStart: checkColdStart,
getSuspendedInstruction: getSuspendedInstruction,
confirmSuspended: confirmSuspended,
denySuspended: denySuspended,
getEvolutionStatus: getEvolutionStatus,
writeSkyeyeLog: writeSkyeyeLog
};