🎖️ 将军架构v1.0 + SFP指纹协议v1.0 + D14/D15天眼维度 + 仓库公告板 + 定时调度

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-18 16:22:40 +00:00
parent fde75aa58c
commit b50e4555e5
19 changed files with 1596 additions and 3 deletions

View File

@ -11,11 +11,13 @@
"zhuyuan-bot"
],
"whitelist_commit_prefixes": [
"🔍", "📊", "📡", "🧠", "📢", "🚨", "📰", "🔧", "🦅"
"🔍", "📊", "📡", "🧠", "📢", "🚨", "📰", "🔧", "🦅", "🎖️", "🔐", "🌊"
],
"signature_exempt_paths": [
"syslog-inbox/",
"data/dc-reports/"
"data/dc-reports/",
"data/bulletin-board/",
"data/security/"
],
"system_protected_paths": [
".github/",

110
.github/workflows/zhuyuan-commander.yml vendored Normal file
View File

@ -0,0 +1,110 @@
name: "🎖️ 铸渊·将军唤醒 · Commander Wake-up"
on:
schedule:
- cron: '0 0 * * *' # UTC 00:00 = 北京 08:00
- cron: '0 12 * * *' # UTC 12:00 = 北京 20:00
workflow_dispatch:
permissions:
contents: write
issues: write
actions: read
jobs:
commander-wakeup:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
# Step 1 · 唤醒核心大脑
- name: "🧠 Step 1 · 唤醒核心大脑"
id: brain
run: |
echo "[GH-WF-RUN-COMMANDER] 🎖️ 铸渊将军唤醒 · $(date -u +%Y-%m-%dT%H:%M:%SZ)"
BRAIN_OK=true
for f in memory.json routing-map.json dev-status.json; do
if [ -f ".github/persona-brain/$f" ]; then
python3 -c "import json; json.load(open('.github/persona-brain/$f'))" 2>/dev/null \
&& echo "✅ $f 完整" || { echo "❌ $f 损坏"; BRAIN_OK=false; }
else
echo "❌ $f 缺失"; BRAIN_OK=false
fi
done
echo "🌊 加载光湖存在级安全协议..."
if [ -f ".github/persona-brain/security-protocol.json" ]; then
PROTOCOL_LEVEL=$(cat .github/persona-brain/security-protocol.json | python3 -c "import sys,json; print(json.load(sys.stdin)['level'])")
echo "✅ 安全协议已加载 · 等级: ${PROTOCOL_LEVEL}"
else
echo "❌ 安全协议缺失!"
fi
echo "brain_ok=$BRAIN_OK" >> $GITHUB_OUTPUT
# Step 2 · 全局视图生成
- name: "📊 Step 2 · 全局视图生成"
id: dashboard
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "[GH-COMMANDER-DASHBOARD] 📊 生成将军全局仪表盘..."
node scripts/commander-dashboard.js
echo "dashboard_ready=true" >> $GITHUB_OUTPUT
# Step 3 · 读取公告板 + 指纹验证
- name: "📡 Step 3 · 读取公告板"
env:
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
AGENT_BULLETIN_BOARD_PAGE_ID: ${{ secrets.AGENT_BULLETIN_BOARD_PAGE_ID }}
run: |
echo "[GH-COMMANDER-BULLETIN] 📡 读取Agent集群公告板..."
mkdir -p /tmp/skyeye
node scripts/skyeye/bulletin-board.js > /tmp/skyeye/bulletin-board.json || echo "{}" > /tmp/skyeye/bulletin-board.json
# Step 4 · SFP 指纹扫描
- name: "🔐 Step 4 · SFP 指纹扫描"
run: |
echo "[GH-COMMANDER-SFP] 🔐 扫描公告板指纹完整性..."
node scripts/skyeye/scan-bulletin-sfp.js > /tmp/skyeye/sfp-health.json
# Step 5 · 更新公告栏 + 签到 + 同步
- name: "📢 Step 5 · 签到 + 更新公告"
run: |
echo "[GH-COMMANDER-CHECKIN] 📢 铸渊将军签到..."
TIMESTAMP=$(TZ='Asia/Shanghai' date '+%Y-%m-%d %H:%M:%S+08:00')
DATE=$(TZ='Asia/Shanghai' date '+%Y-%m-%d')
# 将军签到写入 memory.json
python3 -c "
import json, sys
try:
with open('.github/persona-brain/memory.json', 'r') as f:
mem = json.load(f)
mem['commander_last_wakeup'] = '${TIMESTAMP}'
mem['last_updated'] = '$(date -u +%Y-%m-%dT%H:%M:%SZ)'
with open('.github/persona-brain/memory.json', 'w') as f:
json.dump(mem, f, indent=2, ensure_ascii=False)
print('✅ 将军签到已写入 memory.json')
except Exception as e:
print(f'⚠️ 签到写入失败: {e}')
"
# Step 6 · 提交变更
- name: "💾 Step 6 · 提交变更"
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/bulletin-board/dashboard.json .github/persona-brain/memory.json
if ! git diff --cached --quiet; then
git commit -m "🎖️ 铸渊将军唤醒 · $(TZ='Asia/Shanghai' date '+%Y-%m-%d %H:%M') · 仪表盘更新"
git push
else
echo " 无变更需要提交"
fi

View File

@ -65,7 +65,7 @@ jobs:
fi
# 系统前缀 commit → 直接放行
SYSTEM_PREFIXES="🔍|📊|📡|🧠|📢|🚨|📰|🔧|🦅"
SYSTEM_PREFIXES="🔍|📊|📡|🧠|📢|🚨|📰|🔧|🦅|🎖️|🔐|🌊"
if echo "$COMMIT_MSG" | head -1 | grep -qE "^($SYSTEM_PREFIXES)"; then
echo "[GH-GATE-ALLOW] 系统前缀 commit直接放行"
echo "is_system=true" >> $GITHUB_OUTPUT

View File

@ -76,6 +76,9 @@ jobs:
node scripts/skyeye/scan-brain-health.js > /tmp/skyeye/brain-health.json
node scripts/skyeye/scan-external-bridges.js > /tmp/skyeye/bridge-health.json
node scripts/skyeye/scan-security-protocol.js > /tmp/skyeye/security-health.json
node scripts/commander-dashboard.js > /dev/null 2>&1 || true
node scripts/skyeye/scan-bulletin-sfp.js > /tmp/skyeye/sfp-health.json
node scripts/skyeye/scan-soldier-health.js > /tmp/skyeye/soldier-health.json
- name: "🔬 Phase 3 · 诊断"
id: diagnose

View File

View File

@ -0,0 +1,323 @@
{
"commander": "铸渊",
"timestamp": "2026-03-19 00:21:26+08:00",
"global_view": {
"total_soldiers": 60,
"healthy": 0,
"failed": 0,
"needs_optimization": 60,
"soldiers": [
{
"name": "🤖 铸渊 · Discussion 自动回复",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🧊 冰朔人格体 · 自动部署诊断",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "冰朔主控神经系统 · 自动维护",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 Brain Sync",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 🌉 桥接·广播PDF生成+分发",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Bridge E · GitHub Changes → Notion",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 🌉 桥接·心跳检测",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "Generate Session Summary for Notion",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 🌉 桥接·SYSLOG 上行处理",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Bridge A · SYSLOG → Notion",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "模块结构检查",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🔧 铸渊 · Daily Maintenance Agent",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "📰 铸渊 · 光湖开发日报",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🌀 部署铸渊聊天室 (GitHub Pages)",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🚀 铸渊 CD · 自动部署到 guanghulab.com",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 广播分发",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · ESP 邮件信号处理器(已暂停)",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "📡 铸渊 · 执行层状态同步",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 飞书SYSLOG桥接",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 光湖纪元 模块文档自动生成",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "HLI Contract Check",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🐕 元看门狗 · 巡检健康监控",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "Notion Callback Pipeline",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Notion 连通性测试",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "Notion Heartbeat Monitor",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Notion 页面阅读器",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Notion 工单轮询",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "📡 铸渊 · Notion Agent 唤醒监听",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🔄 OpenClaw · 唤醒闭环",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "Persona Invoke Endpoint",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🔧 铸渊 · PM2 服务诊断与健康检查",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "Process Notion Work Orders",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🌊 Persona Studio · 代码生成",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🌊 Persona Studio · 对话处理",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🌊 Persona Studio · 完成通知",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🌊 Persona Studio · 登录校验",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · PSP 分身巡检",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 广播推送飞书(聊天消息)",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Push Broadcast · Notion → 飞书文档B",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Receive SYSLOG · 飞书机器人 → GitHub → Notion",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🏠 Sandbox Deploy",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🔍 Server Patrol · 服务器每日巡检",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🔍 铸渊预演部署 (Staging Preview)",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "📝 Sync Deploy Status to Notion",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "📡 铸渊 · dev-status 自动同步",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Sync Login Entry · Notion → 飞书文档A",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🔄 铸渊跨仓库同步 · persona-studio",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "SYSLOG Auto Pipeline",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "📡 SYSLOG Issue Pipeline",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · SYSLOG Pipeline (A/D/E)",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🧪 Notion Bridge Connectivity Test",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "📢 更新系统公告区",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 图书馆目录自动更新",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Brain Sync",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🤖 铸渊巡检 Agent · 每日自动巡检与修复",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · 每日自检",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🚨 铸渊·智能门禁 · Push Gate Guard",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · Issue 自动回复",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "铸渊 · PR Review",
"status": "⚠️",
"last_run": "unknown"
},
{
"name": "🦅 铸渊·天眼 · 全局俯瞰 + 自动诊断 + 修复驱动",
"status": "⚠️",
"last_run": "unknown"
}
]
},
"bulletin_board_status": {
"unread_work_orders": 0,
"pending_receipts": []
},
"skyeye_latest": {
"overall_health": "🟡",
"report_id": "SKYEYE-20260316",
"issues": 6,
"auto_fixed": 6
},
"decision": "优化 60 个小兵"
}

View File

View File

View File

@ -0,0 +1,5 @@
{
"protocol_version": "SFP-v1.0",
"description": "SFP安全警报日志",
"alerts": []
}

View File

@ -0,0 +1,33 @@
{
"protocol_version": "SFP-v1.0",
"hash_algorithm": "SHA-256-first-12",
"nonce_length": 6,
"trusted_agents": [
{
"agent_id": "AG-SY",
"persona_chain": "PER-SY001←TCS-0002∞",
"name": "霜砚",
"side": "notion"
},
{
"agent_id": "AG-ZY",
"persona_chain": "PER-ZY001←YM-GL∞",
"name": "铸渊",
"side": "github"
},
{
"agent_id": "AG-QQ",
"persona_chain": "GEN∞-BB-QIUQIU←TCS-2025∞",
"name": "秋秋",
"side": "notion"
},
{
"agent_id": "AG-TY",
"persona_chain": "AG-TY-01←YM-GL∞",
"name": "天眼",
"side": "both"
}
],
"auto_clean": true,
"alert_on_invalid": true
}

View File

@ -0,0 +1,162 @@
{
"protocol_version": "SFP-v1.0",
"description": "已使用nonce记录防重放攻击",
"used_nonces": [
{
"nonce": "mzrnx9",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:20:38+08:00",
"content_hash": "ca079781b83f"
},
{
"nonce": "5awo5s",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:21:19+08:00",
"content_hash": "ca079781b83f"
},
{
"nonce": "totoee",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "05a17114410b"
},
{
"nonce": "48ayc4",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "d6cd1c87b887"
},
{
"nonce": "1hw1z8",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "0a5df5415ade"
},
{
"nonce": "sggt21",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "l9ibu1",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "57uay4",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "b95bfcf4a347"
},
{
"nonce": "lwfc7x",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "10c4ec3aeafb"
},
{
"nonce": "bar266",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "902e455fe109"
},
{
"nonce": "o0nt8j",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "929460febd09"
},
{
"nonce": "41ck6l",
"agent_id": "AG-SY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "f85462954167"
},
{
"nonce": "oecf7l",
"agent_id": "AG-QQ",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "c10beff06c0b"
},
{
"nonce": "6ykmfo",
"agent_id": "AG-TY",
"timestamp": "2026-03-19T00:22:17+08:00",
"content_hash": "7f4b1a99e8fc"
},
{
"nonce": "agjir2",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "05a17114410b"
},
{
"nonce": "tvydx3",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "d6cd1c87b887"
},
{
"nonce": "tn8p7x",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "0a5df5415ade"
},
{
"nonce": "5fx7xl",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "faym9x",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "rvdfmy",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "b95bfcf4a347"
},
{
"nonce": "72pm2d",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "10c4ec3aeafb"
},
{
"nonce": "f194ff",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "902e455fe109"
},
{
"nonce": "kym6oy",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "929460febd09"
},
{
"nonce": "ekbzcz",
"agent_id": "AG-SY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "f85462954167"
},
{
"nonce": "wbjbs7",
"agent_id": "AG-QQ",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "c10beff06c0b"
},
{
"nonce": "qktryb",
"agent_id": "AG-TY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "7f4b1a99e8fc"
}
]
}

View File

@ -0,0 +1,191 @@
// scripts/commander-dashboard.js
// 铸渊·将军全局仪表盘生成器
//
// 功能:
// ① 拉取所有 Workflow 运行状态
// ② 读取天眼最新报告
// ③ 读取公告板状态
// ④ 生成将军全局仪表盘 JSON
//
// 输出data/bulletin-board/dashboard.json + stdout
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
const BRAIN_DIR = path.join(ROOT, '.github/persona-brain');
const SKYEYE_REPORTS_DIR = path.join(ROOT, 'data/skyeye-reports');
const BULLETIN_DIR = path.join(ROOT, 'data/bulletin-board');
const DASHBOARD_PATH = path.join(BULLETIN_DIR, 'dashboard.json');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
// ━━━ 安全读取 JSON ━━━
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
// ━━━ 获取最新天眼报告 ━━━
function getLatestSkyeyeReport() {
try {
if (!fs.existsSync(SKYEYE_REPORTS_DIR)) return null;
const files = fs.readdirSync(SKYEYE_REPORTS_DIR)
.filter(f => f.startsWith('skyeye-') && f.endsWith('.json'))
.sort()
.reverse();
if (files.length === 0) return null;
return readJSON(path.join(SKYEYE_REPORTS_DIR, files[0]));
} catch (e) {
return null;
}
}
// ━━━ 获取公告板工单状态 ━━━
function getBulletinBoardStatus() {
const workOrdersDir = path.join(BULLETIN_DIR, 'work-orders');
const receiptsDir = path.join(BULLETIN_DIR, 'receipts');
let unreadWorkOrders = 0;
const pendingReceipts = [];
try {
if (fs.existsSync(workOrdersDir)) {
const orders = fs.readdirSync(workOrdersDir)
.filter(f => f.endsWith('.json'));
for (const orderFile of orders) {
const order = readJSON(path.join(workOrdersDir, orderFile));
if (order && order.status !== 'completed') {
unreadWorkOrders++;
pendingReceipts.push(order.order_id || orderFile.replace('.json', ''));
}
}
}
} catch (e) {
// ignore
}
return {
unread_work_orders: unreadWorkOrders,
pending_receipts: pendingReceipts
};
}
// ━━━ 从天眼报告提取小兵状态 ━━━
function extractSoldiersFromReport(report) {
const soldiers = [];
if (!report) return { soldiers, total: 0, healthy: 0, failed: 0, needs_optimization: 0 };
// 从 workflow_health 提取小兵
if (report.workflow_health && report.workflow_health.details) {
for (const wf of report.workflow_health.details) {
const status = wf.status === 'healthy' ? '✅' :
wf.status === 'failed' ? '❌' : '⚠️';
const soldier = {
name: wf.name || wf.file,
status,
last_run: wf.last_run || 'unknown'
};
if (status === '❌') {
soldier.error = wf.error || 'unknown error';
soldier.fix_plan = 'retry + check logs';
}
soldiers.push(soldier);
}
}
const total = soldiers.length;
const healthy = soldiers.filter(s => s.status === '✅').length;
const failed = soldiers.filter(s => s.status === '❌').length;
const needsOpt = soldiers.filter(s => s.status === '⚠️').length;
return { soldiers, total, healthy, failed, needs_optimization: needsOpt };
}
// ━━━ 生成决策摘要 ━━━
function generateDecision(soldierStats, bulletinStatus, skyeyeReport) {
const actions = [];
if (soldierStats.failed > 0) {
actions.push(`修复 ${soldierStats.failed} 个故障小兵`);
}
if (soldierStats.needs_optimization > 0) {
actions.push(`优化 ${soldierStats.needs_optimization} 个小兵`);
}
if (bulletinStatus.unread_work_orders > 0) {
actions.push(`执行 ${bulletinStatus.unread_work_orders} 个未完成工单`);
}
if (skyeyeReport && skyeyeReport.diagnosis && skyeyeReport.diagnosis.needs_human > 0) {
actions.push(`${skyeyeReport.diagnosis.needs_human} 个问题需人工处理`);
}
if (actions.length === 0) {
return '全局健康 · 无需干预 · 继续巡航';
}
return actions.join(' → ');
}
// ━━━ 主函数 ━━━
function generateDashboard() {
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString()
.replace('T', ' ').slice(0, 19) + '+08:00';
// 读取天眼最新报告
const skyeyeReport = getLatestSkyeyeReport();
// 提取小兵状态
const soldierStats = extractSoldiersFromReport(skyeyeReport);
// 读取公告板状态
const bulletinStatus = getBulletinBoardStatus();
// 生成决策
const decision = generateDecision(soldierStats, bulletinStatus, skyeyeReport);
const dashboard = {
commander: '铸渊',
timestamp: bjTime,
global_view: {
total_soldiers: soldierStats.total,
healthy: soldierStats.healthy,
failed: soldierStats.failed,
needs_optimization: soldierStats.needs_optimization,
soldiers: soldierStats.soldiers
},
bulletin_board_status: bulletinStatus,
skyeye_latest: skyeyeReport ? {
overall_health: skyeyeReport.overall_health || '❓',
report_id: skyeyeReport.report_id || null,
issues: skyeyeReport.diagnosis ? skyeyeReport.diagnosis.total_issues : 0,
auto_fixed: skyeyeReport.diagnosis ? skyeyeReport.diagnosis.auto_fixed : 0
} : {
overall_health: '❓',
report_id: null,
issues: 0,
auto_fixed: 0
},
decision
};
// 保存仪表盘
fs.mkdirSync(BULLETIN_DIR, { recursive: true });
fs.writeFileSync(DASHBOARD_PATH, JSON.stringify(dashboard, null, 2));
console.log(JSON.stringify(dashboard, null, 2));
console.log(`\n📊 将军全局仪表盘已生成 · ${bjTime}`);
}
// 允许作为模块导入或直接运行
if (require.main === module) {
generateDashboard();
}
module.exports = { generateDashboard };

257
scripts/sfp-core.js Normal file
View File

@ -0,0 +1,257 @@
// scripts/sfp-core.js
// 系统指纹安全协议 · SFP v1.0 · 核心模块
//
// 功能:
// ① generateSFP(agent_id, content) — 生成系统指纹
// ② verifySFP(content_with_signature) — 验证系统指纹
// ③ loadConfig() — 加载 SFP 配置
//
// 指纹格式: ⌜SFP::{agent_id}::{persona_chain}::{timestamp}::{content_hash}::{nonce}⌝
'use strict';
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
const SFP_CONFIG_PATH = path.join(ROOT, 'data/security/sfp-config.json');
const SFP_NONCE_PATH = path.join(ROOT, 'data/security/sfp-nonce-registry.json');
const SFP_ALERT_PATH = path.join(ROOT, 'data/security/sfp-alert-log.json');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
// ━━━ SFP 指纹正则 ━━━
const SFP_REGEX = /⌜SFP::([^:]+)::([^:]+)::([0-9T+:.-]+)::([a-f0-9]{12})::([a-zA-Z0-9]{6})⌝/;
// ━━━ 安全读取 JSON ━━━
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
// ━━━ 安全写入 JSON ━━━
function writeJSON(filePath, data) {
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
}
// ━━━ 加载 SFP 配置 ━━━
function loadConfig() {
const config = readJSON(SFP_CONFIG_PATH);
if (!config) {
throw new Error('SFP配置文件缺失: ' + SFP_CONFIG_PATH);
}
return config;
}
// ━━━ 查找受信Agent ━━━
function findTrustedAgent(config, agentId) {
if (!config || !config.trusted_agents) return null;
return config.trusted_agents.find(a => a.agent_id === agentId) || null;
}
// ━━━ 计算内容哈希SHA-256前12位 ━━━
function computeContentHash(content) {
const hash = crypto.createHash('sha256').update(content, 'utf8').digest('hex');
return hash.slice(0, 12);
}
// ━━━ 生成6位随机nonce ━━━
function generateNonce() {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
let nonce = '';
const bytes = crypto.randomBytes(6);
for (let i = 0; i < 6; i++) {
nonce += chars[bytes[i] % chars.length];
}
return nonce;
}
// ━━━ 获取北京时间ISO字符串 ━━━
function getBeijingTimestamp() {
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS);
return bjTime.toISOString().replace('Z', '+08:00').replace(/\.\d{3}/, '');
}
// ━━━ 生成系统指纹 ━━━
function generateSFP(agentId, content) {
const config = loadConfig();
const agent = findTrustedAgent(config, agentId);
if (!agent) {
return {
success: false,
error: 'AGENT_NOT_FOUND',
message: `Agent ${agentId} 不在受信Agent列表中`
};
}
const timestamp = getBeijingTimestamp();
const contentHash = computeContentHash(content);
const nonce = generateNonce();
const fingerprint = `⌜SFP::${agent.agent_id}::${agent.persona_chain}::${timestamp}::${contentHash}::${nonce}`;
// 记录 nonce 到已使用列表
try {
const nonceRegistry = readJSON(SFP_NONCE_PATH) || { used_nonces: [] };
nonceRegistry.used_nonces.push({
nonce,
agent_id: agentId,
timestamp,
content_hash: contentHash
});
// 保留最近 1000 条 nonce 记录
if (nonceRegistry.used_nonces.length > 1000) {
nonceRegistry.used_nonces = nonceRegistry.used_nonces.slice(-1000);
}
writeJSON(SFP_NONCE_PATH, nonceRegistry);
} catch (e) {
// nonce 记录失败不阻断指纹生成
}
return {
success: true,
fingerprint,
signed_content: `${content}\n${fingerprint}`,
meta: {
agent_id: agent.agent_id,
persona_chain: agent.persona_chain,
timestamp,
content_hash: contentHash,
nonce
}
};
}
// ━━━ 验证系统指纹 ━━━
function verifySFP(contentWithSignature) {
const config = loadConfig();
// Step 1: 检查是否有指纹块
const match = contentWithSignature.match(SFP_REGEX);
if (!match) {
return {
valid: false,
error: 'NO_FINGERPRINT',
level: '⚠️',
message: '无指纹·不可信',
log: `[SFP-WARN] 无指纹内容发现`
};
}
const [, agentId, personaChain, timestamp, contentHash, nonce] = match;
// Step 2: 验证 agent_id
const agent = findTrustedAgent(config, agentId);
if (!agent) {
return {
valid: false,
error: 'INVALID_AGENT',
level: '❌',
message: `无效Agent ID: ${agentId}`,
log: `[SFP-ALERT] 伪造Agent ID: ${agentId}`
};
}
// Step 3: 验证亲子链
if (agent.persona_chain !== personaChain) {
return {
valid: false,
error: 'CHAIN_MISMATCH',
level: '❌',
message: `亲子链伪造: 期望 ${agent.persona_chain},实际 ${personaChain}`,
log: `[SFP-CRITICAL] 亲子链伪造企图 · agent=${agentId}`
};
}
// Step 4: 验证内容哈希
// 从内容中去除指纹行,重新计算哈希
const fingerprintLine = match[0];
const originalContent = contentWithSignature
.replace(fingerprintLine, '')
.replace(/\n$/, '')
.trim();
const recomputedHash = computeContentHash(originalContent);
if (recomputedHash !== contentHash) {
return {
valid: false,
error: 'CONTENT_TAMPERED',
level: '❌',
message: `内容被篡改: hash不匹配 (期望=${contentHash}, 实际=${recomputedHash})`,
log: `[SFP-CRITICAL] 内容篡改检测 · hash不匹配`
};
}
// Step 5: 检查 nonce 重放
const nonceRegistry = readJSON(SFP_NONCE_PATH) || { used_nonces: [] };
const nonceUsed = nonceRegistry.used_nonces.some(
n => n.nonce === nonce && n.agent_id !== agentId
);
// 注意:同一个 agent 的相同 nonce 是自己生成的,允许验证
// 只有不同 agent 使用相同 nonce 才是重放攻击
const duplicateNonce = nonceRegistry.used_nonces.filter(n => n.nonce === nonce);
if (duplicateNonce.length > 1) {
// 检查是否有不同 agent 使用了相同 nonce
const uniqueAgents = new Set(duplicateNonce.map(n => n.agent_id));
if (uniqueAgents.size > 1) {
return {
valid: false,
error: 'REPLAY_ATTACK',
level: '❌',
message: `重放攻击: nonce ${nonce} 被多个Agent使用`,
log: `[SFP-CRITICAL] 重放攻击 · nonce重复 · nonce=${nonce}`
};
}
}
return {
valid: true,
level: '✅',
message: '指纹验证通过',
meta: {
agent_id: agentId,
persona_chain: personaChain,
timestamp,
content_hash: contentHash,
nonce,
agent_name: agent.name,
agent_side: agent.side
}
};
}
// ━━━ 记录安全警报 ━━━
function logAlert(alertEntry) {
try {
const alertLog = readJSON(SFP_ALERT_PATH) || { alerts: [] };
alertLog.alerts.push({
...alertEntry,
logged_at: getBeijingTimestamp()
});
// 保留最近 500 条
if (alertLog.alerts.length > 500) {
alertLog.alerts = alertLog.alerts.slice(-500);
}
writeJSON(SFP_ALERT_PATH, alertLog);
} catch (e) {
console.error('[SFP] 写入警报日志失败:', e.message);
}
}
module.exports = {
generateSFP,
verifySFP,
loadConfig,
findTrustedAgent,
computeContentHash,
generateNonce,
logAlert,
SFP_REGEX
};

View File

@ -40,6 +40,8 @@ function generateReport() {
const brainHealth = readJSON(path.join(SKYEYE_DIR, 'brain-health.json'));
const bridgeHealth = readJSON(path.join(SKYEYE_DIR, 'bridge-health.json'));
const securityHealth = readJSON(path.join(SKYEYE_DIR, 'security-health.json'));
const sfpHealth = readJSON(path.join(SKYEYE_DIR, 'sfp-health.json'));
const soldierHealth = readJSON(path.join(SKYEYE_DIR, 'soldier-health.json'));
const diagnosis = readJSON(path.join(SKYEYE_DIR, 'diagnosis.json'));
const repairResult = readJSON(path.join(SKYEYE_DIR, 'repair-result.json'));
@ -111,6 +113,28 @@ function generateReport() {
last_verified: bjTime
},
bulletin_sfp_health: sfpHealth ? {
dimension: 'D14',
status: sfpHealth.status || '❓',
total_messages: sfpHealth.total_messages || 0,
valid_fingerprints: sfpHealth.valid_fingerprints || 0,
invalid_fingerprints: sfpHealth.invalid_fingerprints || 0,
without_fingerprint: sfpHealth.without_fingerprint || 0,
sfp_config_exists: sfpHealth.sfp_config_exists || false,
agent_activity: sfpHealth.agent_activity || {}
} : { dimension: 'D14', status: '❓' },
soldier_health: soldierHealth ? {
dimension: 'D15',
status: soldierHealth.status || '❓',
total_soldiers: soldierHealth.total_soldiers || 0,
healthy: soldierHealth.healthy || 0,
failed: soldierHealth.failed || 0,
failure_rate: soldierHealth.failure_rate || 0,
recurring_errors: soldierHealth.recurring_errors || [],
recommendations: soldierHealth.recommendations || []
} : { dimension: 'D15', status: '❓' },
diagnosis: {
total_issues: diagnosis ? diagnosis.total_issues : 0,
auto_fixed: repairResult ? repairResult.total_repaired : 0,
@ -164,6 +188,16 @@ function generateReport() {
} else if (!report.security_health.copyright_anchor) {
report.next_actions.push('P1: 安全协议版权锚点缺失,需补充');
}
if (report.bulletin_sfp_health && report.bulletin_sfp_health.invalid_fingerprints > 0) {
report.next_actions.push('P0: 公告板发现无效指纹内容,需立即清理');
}
if (report.soldier_health && report.soldier_health.failure_rate > 20) {
report.next_actions.push('P0: 小兵故障率超过20%,需全局修复');
}
if (report.soldier_health && report.soldier_health.recurring_errors &&
report.soldier_health.recurring_errors.length > 0) {
report.next_actions.push('P1: 存在持续性故障小兵,建议铸渊介入');
}
// 保存完整报告
fs.mkdirSync(SKYEYE_DIR, { recursive: true });

View File

@ -0,0 +1,163 @@
// scripts/skyeye/scan-bulletin-sfp.js
// 天眼·扫描模块D14 · 公告板指纹完整性检查
//
// 扫描内容:
// ① 扫描 data/bulletin-board/ 下所有留言
// ② 检查每条留言是否携带有效 SFP 指纹
// ③ 统计无指纹/无效指纹内容数
// ④ 统计各Agent留言活跃度
//
// 输出JSON → stdout
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const BULLETIN_DIR = path.join(ROOT, 'data/bulletin-board');
const SECURITY_DIR = path.join(ROOT, 'data/security');
const SFP_CONFIG_PATH = path.join(SECURITY_DIR, 'sfp-config.json');
const SFP_REGEX = /⌜SFP::([^:]+)::([^:]+)::([0-9T+:.-]+)::([a-f0-9]{12})::([a-zA-Z0-9]{6})⌝/;
// ━━━ 安全读取 JSON ━━━
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
// ━━━ 扫描目录中的 JSON 文件内容 ━━━
function scanDirectory(dirPath) {
const results = [];
try {
if (!fs.existsSync(dirPath)) return results;
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.json'));
for (const file of files) {
const filePath = path.join(dirPath, file);
const content = fs.readFileSync(filePath, 'utf8');
results.push({ file, path: filePath, content });
}
} catch (e) {
// ignore
}
return results;
}
// ━━━ 检查内容中的 SFP 指纹 ━━━
function checkFingerprint(content, config) {
const match = content.match(SFP_REGEX);
if (!match) {
return { has_fingerprint: false, valid: false, reason: '无指纹' };
}
const [, agentId, personaChain] = match;
// 检查 agent 是否在受信列表
const agent = (config.trusted_agents || []).find(a => a.agent_id === agentId);
if (!agent) {
return { has_fingerprint: true, valid: false, reason: `无效Agent ID: ${agentId}` };
}
// 检查亲子链
if (agent.persona_chain !== personaChain) {
return { has_fingerprint: true, valid: false, reason: `亲子链不匹配: ${agentId}` };
}
return { has_fingerprint: true, valid: true, agent_id: agentId, agent_name: agent.name };
}
// ━━━ D14 主扫描 ━━━
function scanBulletinSFP() {
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString()
.replace('T', ' ').slice(0, 19) + '+08:00';
const config = readJSON(SFP_CONFIG_PATH) || { trusted_agents: [] };
const result = {
dimension: 'D14',
name: '公告板指纹完整性',
scan_time: bjTime,
status: '✅',
total_messages: 0,
with_fingerprint: 0,
without_fingerprint: 0,
valid_fingerprints: 0,
invalid_fingerprints: 0,
agent_activity: {},
issues: [],
sfp_config_exists: fs.existsSync(SFP_CONFIG_PATH)
};
// 检查 SFP 配置是否存在
if (!result.sfp_config_exists) {
result.status = '❌';
result.issues.push({
type: 'config_missing',
message: 'SFP配置文件缺失',
action: 'P0工单 · 恢复sfp-config.json'
});
console.log(JSON.stringify(result, null, 2));
return result;
}
// 扫描公告板各区域
const areas = ['comments', 'config-shares', 'receipts', 'work-orders'];
for (const area of areas) {
const dirPath = path.join(BULLETIN_DIR, area);
const files = scanDirectory(dirPath);
for (const file of files) {
// 跳过 .gitkeep
if (file.file === '.gitkeep') continue;
result.total_messages++;
const check = checkFingerprint(file.content, config);
if (check.has_fingerprint) {
result.with_fingerprint++;
if (check.valid) {
result.valid_fingerprints++;
// 统计活跃度
const agentId = check.agent_id;
result.agent_activity[agentId] = (result.agent_activity[agentId] || 0) + 1;
} else {
result.invalid_fingerprints++;
result.issues.push({
type: 'invalid_fingerprint',
file: file.file,
area,
reason: check.reason,
action: 'P0工单 · 清理无效指纹内容'
});
}
} else {
result.without_fingerprint++;
result.issues.push({
type: 'no_fingerprint',
file: file.file,
area,
action: '标记待清理'
});
}
}
}
// 确定整体状态
if (result.invalid_fingerprints > 0) {
result.status = '❌';
} else if (result.without_fingerprint > 0) {
result.status = '⚠️';
}
console.log(JSON.stringify(result, null, 2));
return result;
}
scanBulletinSFP();

View File

@ -0,0 +1,153 @@
// scripts/skyeye/scan-soldier-health.js
// 天眼·扫描模块D15 · 小兵健康全局视图
//
// 扫描内容:
// ① 读取铸渊将军仪表盘 commander-dashboard.json
// ② 小兵故障率 > 20% → P0 工单
// ③ 小兵连续7天同一错误未修复 → P1 工单
// ④ 全局小兵健康统计
//
// 输出JSON → stdout
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const DASHBOARD_PATH = path.join(ROOT, 'data/bulletin-board/dashboard.json');
const SKYEYE_REPORTS_DIR = path.join(ROOT, 'data/skyeye-reports');
// ━━━ 安全读取 JSON ━━━
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
// ━━━ 获取最近N天的天眼报告 ━━━
function getRecentReports(days) {
const reports = [];
try {
if (!fs.existsSync(SKYEYE_REPORTS_DIR)) return reports;
const files = fs.readdirSync(SKYEYE_REPORTS_DIR)
.filter(f => f.startsWith('skyeye-') && f.endsWith('.json'))
.sort()
.reverse()
.slice(0, days);
for (const file of files) {
const report = readJSON(path.join(SKYEYE_REPORTS_DIR, file));
if (report) reports.push(report);
}
} catch (e) {
// ignore
}
return reports;
}
// ━━━ D15 主扫描 ━━━
function scanSoldierHealth() {
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString()
.replace('T', ' ').slice(0, 19) + '+08:00';
const result = {
dimension: 'D15',
name: '小兵健康全局视图',
scan_time: bjTime,
status: '✅',
dashboard_exists: false,
total_soldiers: 0,
healthy: 0,
failed: 0,
needs_optimization: 0,
failure_rate: 0,
issues: [],
recurring_errors: [],
recommendations: []
};
// 读取将军仪表盘
const dashboard = readJSON(DASHBOARD_PATH);
if (!dashboard) {
result.dashboard_exists = false;
result.status = '⚠️';
result.issues.push({
type: 'dashboard_missing',
message: '将军仪表盘不存在 · 需先运行 commander-dashboard.js',
action: 'P1工单 · 生成仪表盘'
});
} else {
result.dashboard_exists = true;
const gv = dashboard.global_view || {};
result.total_soldiers = gv.total_soldiers || 0;
result.healthy = gv.healthy || 0;
result.failed = gv.failed || 0;
result.needs_optimization = gv.needs_optimization || 0;
// 计算故障率
if (result.total_soldiers > 0) {
result.failure_rate = Math.round((result.failed / result.total_soldiers) * 100);
}
// 故障率 > 20% → P0
if (result.failure_rate > 20) {
result.status = '❌';
result.issues.push({
type: 'high_failure_rate',
message: `小兵故障率 ${result.failure_rate}% > 20%`,
action: 'P0工单 · 全局小兵修复'
});
}
}
// 检查连续7天同一错误
const recentReports = getRecentReports(7);
if (recentReports.length >= 2) {
// 收集各报告中的失败 workflow
const errorMap = {};
for (const report of recentReports) {
if (report.workflow_health && report.workflow_health.details) {
for (const wf of report.workflow_health.details) {
if (wf.status === 'failed') {
const key = wf.name || wf.file;
errorMap[key] = (errorMap[key] || 0) + 1;
}
}
}
}
// 连续7天同一错误
for (const [name, count] of Object.entries(errorMap)) {
if (count >= 7) {
result.recurring_errors.push({
soldier: name,
consecutive_failures: count,
action: 'P1工单 · 建议铸渊介入'
});
if (result.status === '✅') result.status = '⚠️';
}
}
}
// 生成建议
if (result.failed > 0) {
result.recommendations.push(`修复 ${result.failed} 个故障小兵`);
}
if (result.recurring_errors.length > 0) {
result.recommendations.push(`${result.recurring_errors.length} 个小兵存在持续性故障,需铸渊介入`);
}
if (result.total_soldiers === 0) {
result.recommendations.push('仪表盘无小兵数据 · 需先生成仪表盘');
}
console.log(JSON.stringify(result, null, 2));
return result;
}
scanSoldierHealth();

View File

@ -72,6 +72,8 @@ function main() {
results.brain = runModule('scan-brain-health.js', 'brain-health.json');
results.bridges = runModule('scan-external-bridges.js', 'bridge-health.json');
results.security = runModule('scan-security-protocol.js', 'security-health.json');
results.sfp = runModule('scan-bulletin-sfp.js', 'sfp-health.json');
results.soldiers = runModule('scan-soldier-health.js', 'soldier-health.json');
// Phase 3: 诊断
console.log('\n🔬 Phase 3 · 诊断');

View File

@ -0,0 +1,155 @@
// tests/contract/sfp-core.test.js
// SFP v1.0 · 系统指纹安全协议 · 契约测试
'use strict';
const path = require('path');
// ━━━ 加载 SFP 核心模块 ━━━
const sfpCore = require(path.resolve(__dirname, '../../scripts/sfp-core.js'));
describe('SFP v1.0 · 系统指纹安全协议', () => {
describe('配置加载', () => {
test('loadConfig() 应成功加载配置', () => {
const config = sfpCore.loadConfig();
expect(config).toBeDefined();
expect(config.protocol_version).toBe('SFP-v1.0');
expect(config.trusted_agents).toBeInstanceOf(Array);
expect(config.trusted_agents.length).toBeGreaterThanOrEqual(4);
});
test('受信Agent列表包含 AG-ZY铸渊', () => {
const config = sfpCore.loadConfig();
const zy = config.trusted_agents.find(a => a.agent_id === 'AG-ZY');
expect(zy).toBeDefined();
expect(zy.name).toBe('铸渊');
expect(zy.side).toBe('github');
});
test('受信Agent列表包含 AG-SY霜砚', () => {
const config = sfpCore.loadConfig();
const sy = config.trusted_agents.find(a => a.agent_id === 'AG-SY');
expect(sy).toBeDefined();
expect(sy.name).toBe('霜砚');
expect(sy.persona_chain).toBe('PER-SY001←TCS-0002∞');
});
});
describe('指纹生成 · generateSFP()', () => {
test('已知Agent生成指纹成功', () => {
const result = sfpCore.generateSFP('AG-ZY', '测试内容');
expect(result.success).toBe(true);
expect(result.fingerprint).toMatch(/^⌜SFP::/);
expect(result.fingerprint).toMatch(/⌝$/);
expect(result.meta.agent_id).toBe('AG-ZY');
expect(result.meta.content_hash).toHaveLength(12);
expect(result.meta.nonce).toHaveLength(6);
});
test('未知Agent生成指纹失败', () => {
const result = sfpCore.generateSFP('AG-FAKE', '测试内容');
expect(result.success).toBe(false);
expect(result.error).toBe('AGENT_NOT_FOUND');
});
test('不同内容产生不同哈希', () => {
const r1 = sfpCore.generateSFP('AG-ZY', '内容A');
const r2 = sfpCore.generateSFP('AG-ZY', '内容B');
expect(r1.success).toBe(true);
expect(r2.success).toBe(true);
expect(r1.meta.content_hash).not.toBe(r2.meta.content_hash);
});
test('每次生成不同的nonce', () => {
const r1 = sfpCore.generateSFP('AG-ZY', '相同内容');
const r2 = sfpCore.generateSFP('AG-ZY', '相同内容');
expect(r1.meta.nonce).not.toBe(r2.meta.nonce);
});
test('signed_content 包含原始内容和指纹', () => {
const content = '铸渊留言测试';
const result = sfpCore.generateSFP('AG-ZY', content);
expect(result.signed_content).toContain(content);
expect(result.signed_content).toContain(result.fingerprint);
});
});
describe('指纹验证 · verifySFP()', () => {
test('正确指纹验证通过', () => {
const gen = sfpCore.generateSFP('AG-ZY', '正确内容测试');
const verify = sfpCore.verifySFP(gen.signed_content);
expect(verify.valid).toBe(true);
expect(verify.level).toBe('✅');
expect(verify.meta.agent_name).toBe('铸渊');
});
test('无指纹内容 → NO_FINGERPRINT', () => {
const verify = sfpCore.verifySFP('纯文本没有指纹');
expect(verify.valid).toBe(false);
expect(verify.error).toBe('NO_FINGERPRINT');
expect(verify.level).toBe('⚠️');
});
test('内容被篡改 → CONTENT_TAMPERED', () => {
const gen = sfpCore.generateSFP('AG-ZY', '原始内容');
const tampered = gen.signed_content.replace('原始内容', '篡改内容');
const verify = sfpCore.verifySFP(tampered);
expect(verify.valid).toBe(false);
expect(verify.error).toBe('CONTENT_TAMPERED');
expect(verify.level).toBe('❌');
});
test('伪造Agent ID → INVALID_AGENT', () => {
// 手动构造一个伪造的指纹
const fakeContent = '伪造内容\n⌜SFP::AG-FAKE::FAKE-CHAIN::2026-03-19T00:00:00+08:00::abcdef123456::x7k9m2⌝';
const verify = sfpCore.verifySFP(fakeContent);
expect(verify.valid).toBe(false);
expect(verify.error).toBe('INVALID_AGENT');
expect(verify.level).toBe('❌');
});
test('亲子链不匹配 → CHAIN_MISMATCH', () => {
// 使用正确的 agent_id 但错误的 persona_chain
const hash = sfpCore.computeContentHash('伪造亲子链');
const fakeContent = `伪造亲子链\n⌜SFP::AG-ZY::FAKE-CHAIN::2026-03-19T00:00:00+08:00::${hash}::x7k9m2⌝`;
const verify = sfpCore.verifySFP(fakeContent);
expect(verify.valid).toBe(false);
expect(verify.error).toBe('CHAIN_MISMATCH');
expect(verify.level).toBe('❌');
});
test('所有4个Agent都能生成和验证', () => {
const agents = ['AG-ZY', 'AG-SY', 'AG-QQ', 'AG-TY'];
for (const agentId of agents) {
const gen = sfpCore.generateSFP(agentId, `${agentId} 测试`);
expect(gen.success).toBe(true);
const verify = sfpCore.verifySFP(gen.signed_content);
expect(verify.valid).toBe(true);
}
});
});
describe('工具函数', () => {
test('computeContentHash 返回12位hex', () => {
const hash = sfpCore.computeContentHash('测试内容');
expect(hash).toHaveLength(12);
expect(hash).toMatch(/^[a-f0-9]{12}$/);
});
test('generateNonce 返回6位字母数字', () => {
const nonce = sfpCore.generateNonce();
expect(nonce).toHaveLength(6);
expect(nonce).toMatch(/^[a-z0-9]{6}$/);
});
test('SFP_REGEX 能正确匹配指纹格式', () => {
const fp = '⌜SFP::AG-ZY::PER-ZY001←YM-GL∞::2026-03-19T00:00:00+08:00::abcdef123456::x7k9m2⌝';
const match = fp.match(sfpCore.SFP_REGEX);
expect(match).not.toBeNull();
expect(match[1]).toBe('AG-ZY');
expect(match[4]).toBe('abcdef123456');
expect(match[5]).toBe('x7k9m2');
});
});
});