fix: harden release gate and page delivery
Memind CI / Test, build, and release guards (push) Failing after 12m3s
Memind CI / Test, build, and release guards (push) Failing after 12m3s
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
const FORBIDDEN_HOSTS = new Set([
|
||||
'58.38.22.103',
|
||||
'm.tkmind.cn',
|
||||
'plaza.tkmind.cn',
|
||||
]);
|
||||
|
||||
const TARGET_ENV_KEYS = [
|
||||
'STUDIO_HOST',
|
||||
'STUDIO_HEALTH_URL',
|
||||
'H5_PUBLIC_BASE_URL',
|
||||
'MINDSPACE_BASE_URL',
|
||||
'DATABASE_URL',
|
||||
'MINDSPACE_USERDATA_PG_URL',
|
||||
'MYSQL_HOST',
|
||||
'PGHOST',
|
||||
'REDIS_URL',
|
||||
'SEARXNG_URL',
|
||||
'DEEP_SEARCH_URL',
|
||||
];
|
||||
|
||||
function extractHostname(value) {
|
||||
const text = String(value ?? '').trim();
|
||||
if (!text) return '';
|
||||
try {
|
||||
return new URL(text.includes('://') ? text : `tcp://${text}`).hostname.toLowerCase();
|
||||
} catch {
|
||||
return text.split('/')[0].split(':')[0].toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
export function isProductionTarget(value) {
|
||||
const text = String(value ?? '').toLowerCase();
|
||||
const hostname = extractHostname(text);
|
||||
return FORBIDDEN_HOSTS.has(hostname)
|
||||
|| hostname.endsWith('.tkmind.cn')
|
||||
|| text.includes('58.38.22.103')
|
||||
|| text.includes('/users/john/project/memind');
|
||||
}
|
||||
|
||||
export function assertNonProductionTarget(value, label = 'target') {
|
||||
if (isProductionTarget(value)) {
|
||||
throw new Error(`Release gate refused production ${label}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertSafePortalBase(portalBase) {
|
||||
assertNonProductionTarget(portalBase, 'Portal base URL');
|
||||
const parsed = new URL(portalBase);
|
||||
if (!['127.0.0.1', 'localhost', '::1', '[::1]'].includes(parsed.hostname)) {
|
||||
throw new Error('Release gate Portal base must use an isolated loopback host');
|
||||
}
|
||||
return parsed.toString().replace(/\/$/, '');
|
||||
}
|
||||
|
||||
export function assertSafeGateEnvironment({
|
||||
env = process.env,
|
||||
targets = [],
|
||||
} = {}) {
|
||||
const unsafeKeys = [];
|
||||
for (const key of TARGET_ENV_KEYS) {
|
||||
if (env[key] && isProductionTarget(env[key])) {
|
||||
unsafeKeys.push(key);
|
||||
}
|
||||
}
|
||||
for (const [index, target] of targets.entries()) {
|
||||
if (target && isProductionTarget(target)) {
|
||||
unsafeKeys.push(`target[${index}]`);
|
||||
}
|
||||
}
|
||||
if (unsafeKeys.length) {
|
||||
throw new Error(
|
||||
`Release gate refused production-linked configuration: ${unsafeKeys.join(', ')}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const productionTargetPolicy = Object.freeze({
|
||||
forbiddenHosts: [...FORBIDDEN_HOSTS],
|
||||
inspectedEnvironmentKeys: [...TARGET_ENV_KEYS],
|
||||
});
|
||||
Reference in New Issue
Block a user