铸渊专线全面排查修复: Shell注入防护+SMTP持久化+loadConfig通用化+ecosystem环境变量补全
Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/f9b09d73-b949-4f02-b3b9-2e69f90cd8b6 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
parent
2967fce24f
commit
faf2f28c7c
|
|
@ -91,6 +91,8 @@ jobs:
|
||||||
"cd /opt/zhuyuan/proxy-deploy && \
|
"cd /opt/zhuyuan/proxy-deploy && \
|
||||||
export ZY_SERVER_HOST='${{ secrets.ZY_SERVER_HOST }}' && \
|
export ZY_SERVER_HOST='${{ secrets.ZY_SERVER_HOST }}' && \
|
||||||
export ZY_CN_RELAY_HOST='${{ secrets.ZY_CN_SERVER_HOST }}' && \
|
export ZY_CN_RELAY_HOST='${{ secrets.ZY_CN_SERVER_HOST }}' && \
|
||||||
|
export ZY_SMTP_USER='${{ secrets.ZY_SMTP_USER }}' && \
|
||||||
|
export ZY_SMTP_PASS='${{ secrets.ZY_SMTP_PASS }}' && \
|
||||||
bash deploy-proxy.sh ${{ github.event.inputs.action }}"
|
bash deploy-proxy.sh ${{ github.event.inputs.action }}"
|
||||||
|
|
||||||
- name: '🧹 清理SSH密钥'
|
- name: '🧹 清理SSH密钥'
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ ensure_log_permissions() {
|
||||||
chmod 755 "$PROXY_DIR/logs"
|
chmod 755 "$PROXY_DIR/logs"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── 共用: 保存ZY_SERVER_HOST到.env.keys ──
|
# ── 共用: 保存环境变量到.env.keys ──
|
||||||
save_server_host() {
|
save_server_host() {
|
||||||
KEYS_FILE="$PROXY_DIR/.env.keys"
|
KEYS_FILE="$PROXY_DIR/.env.keys"
|
||||||
if [ -n "${ZY_SERVER_HOST:-}" ] && [ -f "$KEYS_FILE" ]; then
|
if [ -n "${ZY_SERVER_HOST:-}" ] && [ -f "$KEYS_FILE" ]; then
|
||||||
|
|
@ -84,6 +84,26 @@ save_server_host() {
|
||||||
fi
|
fi
|
||||||
echo " ✅ ZY_CN_RELAY_HOST 已保存到 .env.keys"
|
echo " ✅ ZY_CN_RELAY_HOST 已保存到 .env.keys"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 保存SMTP凭据 (如果有) — 使守护Agent和流量监控可发送告警邮件
|
||||||
|
if [ -n "${ZY_SMTP_USER:-}" ] && [ -f "$KEYS_FILE" ]; then
|
||||||
|
if grep -q "^ZY_SMTP_USER=" "$KEYS_FILE" 2>/dev/null; then
|
||||||
|
sed -i "s|^ZY_SMTP_USER=.*|ZY_SMTP_USER=${ZY_SMTP_USER}|" "$KEYS_FILE"
|
||||||
|
else
|
||||||
|
echo "" >> "$KEYS_FILE"
|
||||||
|
echo "# SMTP凭据 (部署时自动写入·守护Agent告警用)" >> "$KEYS_FILE"
|
||||||
|
echo "ZY_SMTP_USER=${ZY_SMTP_USER}" >> "$KEYS_FILE"
|
||||||
|
fi
|
||||||
|
echo " ✅ ZY_SMTP_USER 已保存到 .env.keys"
|
||||||
|
fi
|
||||||
|
if [ -n "${ZY_SMTP_PASS:-}" ] && [ -f "$KEYS_FILE" ]; then
|
||||||
|
if grep -q "^ZY_SMTP_PASS=" "$KEYS_FILE" 2>/dev/null; then
|
||||||
|
sed -i "s|^ZY_SMTP_PASS=.*|ZY_SMTP_PASS=${ZY_SMTP_PASS}|" "$KEYS_FILE"
|
||||||
|
else
|
||||||
|
echo "ZY_SMTP_PASS=${ZY_SMTP_PASS}" >> "$KEYS_FILE"
|
||||||
|
fi
|
||||||
|
echo " ✅ ZY_SMTP_PASS 已保存到 .env.keys"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── install: 首次完整安装 ─────────────────────
|
# ── install: 首次完整安装 ─────────────────────
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ module.exports = {
|
||||||
instances: 1,
|
instances: 1,
|
||||||
env: {
|
env: {
|
||||||
NODE_ENV: 'production',
|
NODE_ENV: 'production',
|
||||||
ZY_PROXY_DATA_DIR: '/opt/zhuyuan/proxy/data'
|
ZY_PROXY_DATA_DIR: '/opt/zhuyuan/proxy/data',
|
||||||
|
ZY_PROXY_KEYS_FILE: '/opt/zhuyuan/proxy/.env.keys'
|
||||||
},
|
},
|
||||||
max_memory_restart: '64M',
|
max_memory_restart: '64M',
|
||||||
log_file: '/opt/zhuyuan/proxy/logs/monitor.log',
|
log_file: '/opt/zhuyuan/proxy/logs/monitor.log',
|
||||||
|
|
@ -43,7 +44,8 @@ module.exports = {
|
||||||
env: {
|
env: {
|
||||||
NODE_ENV: 'production',
|
NODE_ENV: 'production',
|
||||||
ZY_PROXY_DATA_DIR: '/opt/zhuyuan/proxy/data',
|
ZY_PROXY_DATA_DIR: '/opt/zhuyuan/proxy/data',
|
||||||
ZY_PROXY_LOG_DIR: '/opt/zhuyuan/proxy/logs'
|
ZY_PROXY_LOG_DIR: '/opt/zhuyuan/proxy/logs',
|
||||||
|
ZY_PROXY_KEYS_FILE: '/opt/zhuyuan/proxy/.env.keys'
|
||||||
},
|
},
|
||||||
max_memory_restart: '128M',
|
max_memory_restart: '128M',
|
||||||
log_file: '/opt/zhuyuan/proxy/logs/guardian.log',
|
log_file: '/opt/zhuyuan/proxy/logs/guardian.log',
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { execSync, exec } = require('child_process');
|
const { execSync, execFileSync } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
|
|
@ -275,10 +275,11 @@ async function consultLLM(issue) {
|
||||||
function sendAlertEmail(subject, body) {
|
function sendAlertEmail(subject, body) {
|
||||||
try {
|
try {
|
||||||
const sendScript = path.join(__dirname, 'send-subscription.js');
|
const sendScript = path.join(__dirname, 'send-subscription.js');
|
||||||
execSync(
|
// 使用execFileSync避免Shell命令注入 (不经过shell解释器)
|
||||||
`node "${sendScript}" alert "${subject}\n\n${body}"`,
|
execFileSync('node', [sendScript, 'alert', `${subject}\n\n${body}`], {
|
||||||
{ encoding: 'utf8', timeout: 30000 }
|
encoding: 'utf8',
|
||||||
);
|
timeout: 30000
|
||||||
|
});
|
||||||
console.log('[守护Agent] 告警邮件已发送');
|
console.log('[守护Agent] 告警邮件已发送');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[守护Agent] 邮件发送失败:', err.message);
|
console.error('[守护Agent] 邮件发送失败:', err.message);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ const path = require('path');
|
||||||
const KEYS_FILE = process.env.ZY_PROXY_KEYS_FILE || '/opt/zhuyuan/proxy/.env.keys';
|
const KEYS_FILE = process.env.ZY_PROXY_KEYS_FILE || '/opt/zhuyuan/proxy/.env.keys';
|
||||||
|
|
||||||
// ── 加载配置 ─────────────────────────────────
|
// ── 加载配置 ─────────────────────────────────
|
||||||
|
// 优先级: 环境变量 > .env.keys文件
|
||||||
|
// 通用读取所有键值对,确保guardian/monitor等服务也能获取完整配置
|
||||||
function loadConfig() {
|
function loadConfig() {
|
||||||
const config = {
|
const config = {
|
||||||
smtp_user: process.env.ZY_SMTP_USER || '',
|
smtp_user: process.env.ZY_SMTP_USER || '',
|
||||||
|
|
@ -37,13 +39,21 @@ function loadConfig() {
|
||||||
sub_token: process.env.ZY_PROXY_SUB_TOKEN || ''
|
sub_token: process.env.ZY_PROXY_SUB_TOKEN || ''
|
||||||
};
|
};
|
||||||
|
|
||||||
// 尝试从本地密钥文件读取Token
|
// 从.env.keys文件读取所有键值对(环境变量未设置时回退)
|
||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(KEYS_FILE, 'utf8');
|
const content = fs.readFileSync(KEYS_FILE, 'utf8');
|
||||||
for (const line of content.split('\n')) {
|
for (const line of content.split('\n')) {
|
||||||
if (line.startsWith('ZY_PROXY_SUB_TOKEN=')) {
|
if (line.startsWith('#') || !line.includes('=')) continue;
|
||||||
config.sub_token = line.split('=')[1].trim();
|
const [key, ...vals] = line.split('=');
|
||||||
}
|
const k = key.trim();
|
||||||
|
const v = vals.join('=').trim();
|
||||||
|
if (!v) continue;
|
||||||
|
|
||||||
|
// 仅在环境变量未设置时使用文件中的值
|
||||||
|
if (k === 'ZY_PROXY_SUB_TOKEN' && !config.sub_token) config.sub_token = v;
|
||||||
|
if (k === 'ZY_SERVER_HOST' && !config.server_host) config.server_host = v;
|
||||||
|
if (k === 'ZY_SMTP_USER' && !config.smtp_user) config.smtp_user = v;
|
||||||
|
if (k === 'ZY_SMTP_PASS' && !config.smtp_pass) config.smtp_pass = v;
|
||||||
}
|
}
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { execSync } = require('child_process');
|
const { execSync, execFileSync } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
|
@ -177,10 +177,11 @@ async function sendAlert(alert, quota) {
|
||||||
const usedGB = ((quota.upload_bytes + quota.download_bytes) / (1024 ** 3)).toFixed(2);
|
const usedGB = ((quota.upload_bytes + quota.download_bytes) / (1024 ** 3)).toFixed(2);
|
||||||
const totalGB = (quota.total_bytes / (1024 ** 3)).toFixed(0);
|
const totalGB = (quota.total_bytes / (1024 ** 3)).toFixed(0);
|
||||||
|
|
||||||
execSync(
|
// 使用execFileSync避免Shell命令注入 (不经过shell解释器)
|
||||||
`node "${sendScript}" alert "${alert.message} 已用 ${usedGB}GB / ${totalGB}GB"`,
|
execFileSync('node', [sendScript, 'alert', `${alert.message} 已用 ${usedGB}GB / ${totalGB}GB`], {
|
||||||
{ encoding: 'utf8', timeout: 30000 }
|
encoding: 'utf8',
|
||||||
);
|
timeout: 30000
|
||||||
|
});
|
||||||
console.log(`[流量监控] 告警邮件已发送: ${alert.level}`);
|
console.log(`[流量监控] 告警邮件已发送: ${alert.level}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[流量监控] 告警邮件发送失败:', err.message);
|
console.error('[流量监控] 告警邮件发送失败:', err.message);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue