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], });