Files
Genarrative/scripts/check-production-health-patrol-env-check.mjs
kdletters 071faa482c 统一 Rust 与 TypeScript 格式化门禁
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口

完成项目 TypeScript/Prettier 与 Rust 全量格式化

修复 Pingora expected executable 门禁的空白敏感误报

同步开发运维文档与 AGC skill pack 格式化忽略规则
2026-09-01 16:28:34 +08:00

277 lines
8.3 KiB
JavaScript

#!/usr/bin/env node
import { spawnSync } from 'node:child_process';
import {
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
writeFileSync,
} from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
const failures = [];
const tmpRoot = mkdtempSync(
path.join(tmpdir(), 'genarrative-health-patrol-env-check-'),
);
try {
main();
} finally {
rmSync(tmpRoot, { recursive: true, force: true });
}
if (failures.length > 0) {
console.error('[check:production-health-patrol-env] FAILED');
for (const failure of failures) {
console.error(`- ${failure}`);
}
process.exit(1);
}
console.log('[check:production-health-patrol-env] OK');
function main() {
assertAcceptsPingoraDirectLoopbackWithHost();
assertRejectsPingoraDirectLoopbackWithoutHost();
assertRejectsWrongGatewayMode();
assertAcceptsNginxWithEmptyPublicHost();
assertRejectsNginxWithStalePublicHost();
assertRejectsInvalidPublicHost();
assertRejectsInvalidEnvFilePaths();
assertRejectsInvalidBoolEnv();
assertExampleDocumentsDirectMode();
}
function assertAcceptsPingoraDirectLoopbackWithHost() {
const envFile = writeEnv('pingora-direct-ok.env', {
GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE: 'pingora-direct',
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL: 'https://127.0.0.1',
GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST: 'genarrative.example',
});
const result = runCheck([
'--env-file',
envFile,
'--expected-gateway-mode',
'pingora-direct',
'--expected-public-base-url',
'https://127.0.0.1',
'--expected-public-host',
'genarrative.example',
]);
assertStatus(result, 0, 'Pingora direct loopback 配正式 Host 应通过。');
}
function assertRejectsPingoraDirectLoopbackWithoutHost() {
const envFile = writeEnv('pingora-direct-missing-host.env', {
GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE: 'pingora-direct',
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL: 'https://127.0.0.1',
GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST: '',
});
const result = runCheck([
'--env-file',
envFile,
'--expected-gateway-mode',
'pingora-direct',
'--expected-public-base-url',
'https://127.0.0.1',
]);
assertStatus(result, 1, 'Pingora direct loopback 缺 Host 必须失败。');
assertIncludes(
`${result.stdout}\n${result.stderr}`,
'Pingora direct 模式使用本机 public base URL 时必须配置 GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST',
'Pingora direct loopback 缺 Host 必须给出明确错误。',
);
}
function assertRejectsWrongGatewayMode() {
const envFile = writeEnv('wrong-mode.env', {
GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE: 'nginx',
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL: 'https://127.0.0.1',
GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST: 'genarrative.example',
});
const result = runCheck([
'--env-file',
envFile,
'--expected-gateway-mode',
'pingora-direct',
]);
assertStatus(result, 1, 'gateway mode 与期望不一致必须失败。');
assertIncludes(
`${result.stdout}\n${result.stderr}`,
'GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE 应为 pingora-direct,实际 nginx',
'gateway mode mismatch 必须给出明确错误。',
);
}
function assertAcceptsNginxWithEmptyPublicHost() {
const envFile = writeEnv('nginx-empty-host.env', {
GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE: 'nginx',
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL: 'http://127.0.0.1',
GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST: '',
});
const result = runCheck([
'--env-file',
envFile,
'--expected-gateway-mode',
'nginx',
'--expected-public-base-url',
'http://127.0.0.1',
'--require-empty-public-host',
]);
assertStatus(result, 0, 'Nginx 模式回退且 Host 为空应通过。');
}
function assertRejectsNginxWithStalePublicHost() {
const envFile = writeEnv('nginx-stale-host.env', {
GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE: 'nginx',
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL: 'http://127.0.0.1',
GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST: 'genarrative.example',
});
const result = runCheck([
'--env-file',
envFile,
'--expected-gateway-mode',
'nginx',
'--require-empty-public-host',
]);
assertStatus(result, 1, 'Nginx 回退后残留 Host 覆盖必须失败。');
assertIncludes(
`${result.stdout}\n${result.stderr}`,
'GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST 应为空',
'Nginx 回退后残留 Host 覆盖必须给出明确错误。',
);
}
function assertRejectsInvalidPublicHost() {
const envFile = writeEnv('invalid-host.env', {
GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE: 'pingora-direct',
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL: 'https://127.0.0.1',
GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST: 'https://genarrative.example',
});
const result = runCheck([
'--env-file',
envFile,
'--expected-gateway-mode',
'pingora-direct',
]);
assertStatus(result, 1, '非法 public Host 必须失败。');
assertIncludes(
`${result.stdout}\n${result.stderr}`,
'GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST 只能是 host 或 host:port',
'非法 public Host 必须给出明确错误。',
);
}
function assertRejectsInvalidEnvFilePaths() {
const relativePath = runCheck([
'--env-file',
'health-patrol.env',
'--expected-gateway-mode',
'nginx',
]);
assertStatus(
relativePath,
1,
'health patrol env 复核必须拒绝相对 env 文件路径。',
);
assertIncludes(
`${relativePath.stdout}\n${relativePath.stderr}`,
'--env-file 必须是绝对路径',
'相对 env 文件路径必须给出明确错误。',
);
const rootPath = runCheck([
'--env-file',
'/',
'--expected-gateway-mode',
'nginx',
]);
assertStatus(rootPath, 1, 'health patrol env 复核必须拒绝文件系统根目录。');
assertIncludes(
`${rootPath.stdout}\n${rootPath.stderr}`,
'--env-file 不能是文件系统根目录',
'文件系统根目录 env 文件路径必须给出明确错误。',
);
}
function assertRejectsInvalidBoolEnv() {
const envFile = writeEnv('invalid-bool-env.env', {
GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE: 'nginx',
GENARRATIVE_HEALTH_PATROL_PUBLIC_BASE_URL: 'http://127.0.0.1',
GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST: '',
});
const result = runCheck(
['--env-file', envFile, '--expected-gateway-mode', 'nginx'],
{
GENARRATIVE_HEALTH_PATROL_REQUIRE_EMPTY_PUBLIC_HOST: 'enabled',
},
);
assertStatus(result, 1, 'health patrol env 复核必须拒绝非法布尔 env。');
assertIncludes(
`${result.stdout}\n${result.stderr}`,
'GENARRATIVE_HEALTH_PATROL_REQUIRE_EMPTY_PUBLIC_HOST 必须是布尔值',
'health patrol env 复核非法布尔 env 必须给出明确错误。',
);
}
function assertExampleDocumentsDirectMode() {
const example = readFileSync('deploy/env/health-patrol.env.example', 'utf8');
assertIncludes(
example,
'GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE=nginx',
'health patrol env 示例必须保留默认 nginx 模式。',
);
assertIncludes(
example,
'Pingora 直连切换后改为 pingora-direct',
'health patrol env 示例必须说明 Pingora direct 切换口径。',
);
}
function writeEnv(name, values) {
const filePath = path.join(tmpRoot, name);
mkdirSync(path.dirname(filePath), { recursive: true });
const body = Object.entries(values)
.map(([key, value]) => `${key}=${value}`)
.join('\n');
writeFileSync(filePath, `${body}\n`, 'utf8');
return filePath;
}
function runCheck(args, extraEnv = {}) {
return spawnSync(
process.execPath,
['--', 'scripts/check-production-health-patrol-env.mjs', ...args],
{
cwd: process.cwd(),
encoding: 'utf8',
env: {
...process.env,
GENARRATIVE_HEALTH_PATROL_ENV_FILE: '',
GENARRATIVE_HEALTH_PATROL_EXPECTED_GATEWAY_MODE: '',
GENARRATIVE_HEALTH_PATROL_EXPECTED_PUBLIC_BASE_URL: '',
GENARRATIVE_HEALTH_PATROL_EXPECTED_PUBLIC_HOST: '',
GENARRATIVE_HEALTH_PATROL_REQUIRE_EMPTY_PUBLIC_HOST: '',
...extraEnv,
},
},
);
}
function assertStatus(result, expected, reason) {
const actual = result.status ?? 0;
if (actual !== expected) {
failures.push(
`${reason} 预期退出码 ${expected},实际 ${actual}。\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`,
);
}
}
function assertIncludes(content, needle, reason) {
if (!content.includes(needle)) {
failures.push(`${reason} 缺少: ${needle}`);
}
}