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

443 lines
14 KiB
JavaScript
Raw Normal View History

/**
* 天眼指令审核中间件 · 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
};