🎁 Sync 2026-10-28 19:35:15

This commit is contained in:
github-actions[bot] committed 2026-10-28 19:35:15 +08:00
1 parent 85209f310d
commit 390801c844
90 files changed
+5821 -1967

No files matched your search

+127
View File
@@ -65,3 +65,130 @@ test('log trimming is scheduled and the visitor list reads the rotated access lo
assert.match(init, /\/bin\/sh \/usr\/lib\/minigate\/proxy\.sh trim-logs/);
assert.match(controller, /cat \/var\/log\/minigate-access\.log\.1 \/var\/log\/minigate-access\.log 2>\/dev\/null \| tail -n 500/);
});
// 用假的 uci / nginx 生成完整配置,检查跳过规则、回滚和状态文件
function generate(db, { nginxFails = false } = {}) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'minigate-proxy-gen-'));
const bin = path.join(dir, 'bin');
fs.mkdirSync(bin);
fs.mkdirSync(path.join(dir, 'sites'));
fs.writeFileSync(path.join(dir, 'uci.db'), db.trim() + '\n');
fs.writeFileSync(path.join(bin, 'uci'), `#!/bin/sh
DB=${JSON.stringify(path.join(dir, 'uci.db'))}
[ "$1" = "-q" ] && shift
case "$1" in
show) grep "^$2" "$DB" ;;
get) v=$(grep "^$2=" "$DB" | head -1 | cut -d= -f2-); [ -n "$v" ] && echo "$v" || exit 1 ;;
esac
`, { mode: 0o755 });
fs.writeFileSync(path.join(bin, 'nginx'), `#!/bin/sh
[ "$1" = "-v" ] && { echo "nginx version: nginx/1.26.3" >&2; exit 0; }
${nginxFails ? 'echo "nginx: [emerg] unknown directive in site_1.conf:3" >&2; exit 1' : 'exit 0'}
`, { mode: 0o755 });
fs.writeFileSync(path.join(bin, 'openssl'), '#!/bin/sh\nexit 0\n', { mode: 0o755 });
fs.writeFileSync(path.join(dir, 'sites/site_1.conf'), '# previous good site\n');
fs.writeFileSync(path.join(dir, 'main.conf'), '# previous good main\n');
const result = spawnSync('/bin/sh', [script, 'prepare'], {
encoding: 'utf8',
env: {
...process.env,
PATH: `${bin}:${process.env.PATH}`,
TMPDIR: dir,
MINIGATE_PROXY_LOCK: path.join(dir, 'proxy.lock'),
MINIGATE_PROXY_STATUS: path.join(dir, 'proxy.status'),
MINIGATE_NGINX_CONF: path.join(dir, 'main.conf'),
MINIGATE_MIME_TYPES: '/dev/null',
MINIGATE_SITES_DIR: path.join(dir, 'sites'),
MINIGATE_STREAMS_DIR: path.join(dir, 'streams'),
MINIGATE_CERT_DIR: path.join(dir, 'certs'),
MINIGATE_LOGFILE: path.join(dir, 'proxy.log'),
MINIGATE_SOCKET_DIR: path.join(dir, 'sock')
}
});
const sites = fs.readdirSync(path.join(dir, 'sites')).sort();
const conf = sites.map(name => fs.readFileSync(path.join(dir, 'sites', name), 'utf8')).join('\n');
const status = fs.existsSync(path.join(dir, 'proxy.status')) ? fs.readFileSync(path.join(dir, 'proxy.status'), 'utf8') : '';
const leftovers = fs.readdirSync(dir).filter(name => name.startsWith('minigate-gen.'));
return { result, dir, sites, conf, status, leftovers, main: fs.readFileSync(path.join(dir, 'main.conf'), 'utf8') };
}
const BASE = `
minigate.global=global
minigate.global.enabled=1
minigate.global.http_redirect=0
minigate.wc=proxy_wildcard
minigate.wc.enabled=WC_ENABLED
minigate.wc.domain=*.example.com
minigate.wc.listen_port=443
minigate.wc.ssl=1
minigate.sub1=subproxy
minigate.sub1.parent_domain=example.com
minigate.sub1.prefix=nas
minigate.sub1.target_addr=192.168.2.10
minigate.sub1.target_port=5000
`;
test('subdomains are skipped when their wildcard parent is disabled instead of falling back to plain HTTP', () => {
const disabled = generate(BASE.replace('WC_ENABLED', '0'));
assert.equal(disabled.result.status, 0, disabled.result.stderr);
assert.doesNotMatch(disabled.conf, /nas\.example\.com/);
assert.match(disabled.status, /warning=跳过 nas\.example\.com:通配符主域名 \*\.example\.com 未启用或不存在/);
const enabled = generate(BASE.replace('WC_ENABLED', '1'));
assert.equal(enabled.result.status, 0, enabled.result.stderr);
assert.match(enabled.conf, /listen 443 ssl;\n server_name nas\.example\.com;/);
assert.doesNotMatch(enabled.conf, /listen 443;\n server_name nas/);
});
test('a disabled subdomain rule is not generated', () => {
const result = generate(BASE.replace('WC_ENABLED', '1') + 'minigate.sub1.enabled=0\n');
assert.equal(result.result.status, 0, result.result.stderr);
assert.doesNotMatch(result.conf, /nas\.example\.com/);
});
test('HTTP and HTTPS rules on one port never produce two default servers', () => {
const result = generate(BASE.replace('WC_ENABLED', '1') + `
minigate.plain=proxy
minigate.plain.enabled=1
minigate.plain.domain=plain.example.org
minigate.plain.listen_port=443
minigate.plain.target_addr=192.168.2.30
minigate.plain.ssl=0
`);
assert.equal(result.result.status, 0, result.result.stderr);
// 普通规则先生成并占用端口,之后的子域名 HTTPS 规则被跳过
assert.equal((result.conf.match(/default_server/g) || []).length, 1);
assert.match(result.conf, /server_name plain\.example\.org;/);
assert.doesNotMatch(result.conf, /nas\.example\.com/);
assert.match(result.status, /warning=跳过 nas\.example\.com:端口 443 已用于HTTP,不能同时用于HTTPS/);
});
test('missing certificates and every site get WebSocket support and a visible warning', () => {
const result = generate(BASE.replace('WC_ENABLED', '1'));
assert.match(result.status, /warning=nas\.example\.com 没有可用证书/);
assert.match(result.conf, /proxy_set_header Connection \$minigate_connection_upgrade;/);
assert.match(result.main, /map \$http_upgrade \$minigate_connection_upgrade/);
assert.match(result.status, /^result=ok$/m);
assert.deepEqual(result.leftovers, [], 'temporary generation directory is removed');
});
test('a configuration nginx rejects is rolled back so the last working files stay on disk', () => {
const result = generate(BASE.replace('WC_ENABLED', '1'), { nginxFails: true });
assert.equal(result.result.status, 1);
assert.deepEqual(result.sites, ['site_1.conf']);
assert.equal(fs.readFileSync(path.join(result.dir, 'sites/site_1.conf'), 'utf8'), '# previous good site\n');
assert.equal(result.main, '# previous good main\n');
assert.match(result.status, /^result=error$/m);
assert.match(result.status, /配置检查失败,已保留上一份配置:\[emerg\] unknown directive/);
assert.deepEqual(result.leftovers, []);
});
test('nginx runs in the foreground under procd and clears stale sockets first', () => {
const source = fs.readFileSync(script, 'utf8');
assert.match(source, /do_run\(\) \{\n mkdir -p "\$SOCKET_DIR"\n rm -f "\$SOCKET_DIR"\/\*\.sock\n exec nginx -c "\$NGINX_CONF" -g 'daemon off;'/);
const init = fs.readFileSync(path.join(root, 'root/etc/init.d/minigate'), 'utf8');
assert.match(init, /USE_PROCD=1/);
assert.match(init, /procd_set_param command \/bin\/sh "\$PROXY" run/);
assert.match(init, /procd_add_reload_trigger "minigate"/);
assert.match(source, /MINIGATE_SKIP_PREPARE=1 "\$INIT_SCRIPT" start 6>&-/);
});