🔐 修复SFP nonce生成偏差 + 提取magic numbers为命名常量

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

View File

@ -2,8 +2,8 @@ name: "🎖️ 铸渊·将军唤醒 · Commander Wake-up"
on:
schedule:
- cron: '0 0 * * *' # UTC 00:00 = 北京 08:00
- cron: '0 12 * * *' # UTC 12:00 = 北京 20:00
- cron: '0 0 * * *' # UTC 00:00 = 北京 08:00(将军早班唤醒)
- cron: '0 12 * * *' # UTC 12:00 = 北京 20:00(将军晚班唤醒)
workflow_dispatch:
permissions:

View File

@ -157,6 +157,150 @@
"agent_id": "AG-TY",
"timestamp": "2026-03-19T00:22:24+08:00",
"content_hash": "7f4b1a99e8fc"
},
{
"nonce": "olnmim",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "05a17114410b"
},
{
"nonce": "r42f7r",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "d6cd1c87b887"
},
{
"nonce": "2pi1t3",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "0a5df5415ade"
},
{
"nonce": "sswkv7",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "pu7e0o",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "cbz6t0",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "b95bfcf4a347"
},
{
"nonce": "g5dfi3",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "10c4ec3aeafb"
},
{
"nonce": "cxu97j",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "902e455fe109"
},
{
"nonce": "w2dw4b",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "929460febd09"
},
{
"nonce": "aqyuid",
"agent_id": "AG-SY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "f85462954167"
},
{
"nonce": "oycw4f",
"agent_id": "AG-QQ",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "c10beff06c0b"
},
{
"nonce": "69xg61",
"agent_id": "AG-TY",
"timestamp": "2026-03-19T00:23:59+08:00",
"content_hash": "7f4b1a99e8fc"
},
{
"nonce": "3783f4",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "05a17114410b"
},
{
"nonce": "153ac0",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "d6cd1c87b887"
},
{
"nonce": "b1b39e",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "0a5df5415ade"
},
{
"nonce": "32af7a",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "bda41d",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "c3b54c6c243e"
},
{
"nonce": "2c6a56",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "b95bfcf4a347"
},
{
"nonce": "250ec9",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "10c4ec3aeafb"
},
{
"nonce": "eb8195",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "902e455fe109"
},
{
"nonce": "d20686",
"agent_id": "AG-ZY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "929460febd09"
},
{
"nonce": "18fa39",
"agent_id": "AG-SY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "f85462954167"
},
{
"nonce": "8d0d13",
"agent_id": "AG-QQ",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "c10beff06c0b"
},
{
"nonce": "7de110",
"agent_id": "AG-TY",
"timestamp": "2026-03-19T00:25:55+08:00",
"content_hash": "7f4b1a99e8fc"
}
]
}

View File

@ -20,6 +20,8 @@ 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;
const MAX_NONCE_REGISTRY_SIZE = 1000;
const MAX_ALERT_LOG_SIZE = 500;
// ━━━ SFP 指纹正则 ━━━
const SFP_REGEX = /⌜SFP::([^:]+)::([^:]+)::([0-9T+:.-]+)::([a-f0-9]{12})::([a-zA-Z0-9]{6})⌝/;
@ -62,13 +64,8 @@ function computeContentHash(content) {
// ━━━ 生成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;
// Use hex encoding of random bytes for unbiased distribution
return crypto.randomBytes(3).toString('hex');
}
// ━━━ 获取北京时间ISO字符串 ━━━
@ -107,8 +104,8 @@ function generateSFP(agentId, content) {
content_hash: contentHash
});
// 保留最近 1000 条 nonce 记录
if (nonceRegistry.used_nonces.length > 1000) {
nonceRegistry.used_nonces = nonceRegistry.used_nonces.slice(-1000);
if (nonceRegistry.used_nonces.length > MAX_NONCE_REGISTRY_SIZE) {
nonceRegistry.used_nonces = nonceRegistry.used_nonces.slice(-MAX_NONCE_REGISTRY_SIZE);
}
writeJSON(SFP_NONCE_PATH, nonceRegistry);
} catch (e) {
@ -236,8 +233,8 @@ function logAlert(alertEntry) {
logged_at: getBeijingTimestamp()
});
// 保留最近 500 条
if (alertLog.alerts.length > 500) {
alertLog.alerts = alertLog.alerts.slice(-500);
if (alertLog.alerts.length > MAX_ALERT_LOG_SIZE) {
alertLog.alerts = alertLog.alerts.slice(-MAX_ALERT_LOG_SIZE);
}
writeJSON(SFP_ALERT_PATH, alertLog);
} catch (e) {

View File

@ -18,6 +18,9 @@ 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');
const FAILURE_RATE_THRESHOLD = 20;
const CONSECUTIVE_FAILURE_THRESHOLD_DAYS = 7;
// ━━━ 安全读取 JSON ━━━
function readJSON(filePath) {
try {
@ -96,18 +99,18 @@ function scanSoldierHealth() {
}
// 故障率 > 20% → P0
if (result.failure_rate > 20) {
if (result.failure_rate > FAILURE_RATE_THRESHOLD) {
result.status = '❌';
result.issues.push({
type: 'high_failure_rate',
message: `小兵故障率 ${result.failure_rate}% > 20%`,
message: `小兵故障率 ${result.failure_rate}% > ${FAILURE_RATE_THRESHOLD}%`,
action: 'P0工单 · 全局小兵修复'
});
}
}
// 检查连续7天同一错误
const recentReports = getRecentReports(7);
const recentReports = getRecentReports(CONSECUTIVE_FAILURE_THRESHOLD_DAYS);
if (recentReports.length >= 2) {
// 收集各报告中的失败 workflow
const errorMap = {};
@ -124,7 +127,7 @@ function scanSoldierHealth() {
// 连续7天同一错误
for (const [name, count] of Object.entries(errorMap)) {
if (count >= 7) {
if (count >= CONSECUTIVE_FAILURE_THRESHOLD_DAYS) {
result.recurring_errors.push({
soldier: name,
consecutive_failures: count,

View File

@ -137,10 +137,10 @@ describe('SFP v1.0 · 系统指纹安全协议', () => {
expect(hash).toMatch(/^[a-f0-9]{12}$/);
});
test('generateNonce 返回6位字母数字', () => {
test('generateNonce 返回6位hex字符', () => {
const nonce = sfpCore.generateNonce();
expect(nonce).toHaveLength(6);
expect(nonce).toMatch(/^[a-z0-9]{6}$/);
expect(nonce).toMatch(/^[a-f0-9]{6}$/);
});
test('SFP_REGEX 能正确匹配指纹格式', () => {