import net from "node:net"; import { RUNTIME_DURABLE_ADAPTER_AUTH_BLOCKED, RUNTIME_DURABLE_ADAPTER_MIGRATION_BLOCKED, RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED, RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED, RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED, RUNTIME_DURABILITY_REQUIRED_EVIDENCE, RUNTIME_STORE_KIND_POSTGRES } from "../db/runtime-store.ts"; import { ENVIRONMENT_DEV } from "../protocol/index.mjs"; export const DEV_DB_ENV_CONTRACT = Object.freeze({ contractVersion: "v1", environment: ENVIRONMENT_DEV, requiredEnv: Object.freeze([ "HWLAB_CLOUD_DB_URL", "HWLAB_CLOUD_DB_SSL_MODE" ]), secretRefs: Object.freeze([ Object.freeze({ env: "HWLAB_CLOUD_DB_URL", secretName: "hwlab-cloud-api-dev-db", secretKey: "database-url" }) ]), endpointAuthority: Object.freeze({ source: "secret-url-host", env: "HWLAB_CLOUD_DB_URL", requiredForReadiness: true, valueRedacted: true, endpointRedacted: true }), dns: Object.freeze({ source: "optional-public-dns-alias", serviceName: "cloud-api-db", namespace: "hwlab-dev", host: "cloud-api-db.hwlab-dev.svc.cluster.local", port: 5432, portName: "postgres", requiredForReadiness: false, usedForProbe: false }), readinessLayers: Object.freeze([ "dns", "tcp", "ssl", "auth", "schema", "migration", "durability" ]), nonSecretDefaults: Object.freeze({ HWLAB_CLOUD_DB_SSL_MODE: "disable" }), forbidden: Object.freeze({ prodAllowed: false, secretPlaintextAllowed: false, liveDbEvidenceFromFixtures: false, invalidRuntimeHosts: Object.freeze([ ".invalid", "hwlab-dev-db.invalid" ]) }) }); export const V02_DB_ENV_CONTRACT = buildRuntimeLaneDbEnvContract("v02"); export const V03_DB_ENV_CONTRACT = buildRuntimeLaneDbEnvContract("v03"); function buildRuntimeLaneDbEnvContract(profile) { return Object.freeze({ ...DEV_DB_ENV_CONTRACT, environment: profile, secretRefs: Object.freeze([ Object.freeze({ env: "HWLAB_CLOUD_DB_URL", secretName: `hwlab-cloud-api-${profile}-db`, secretKey: "database-url" }) ]), dns: Object.freeze({ ...DEV_DB_ENV_CONTRACT.dns, serviceName: `hwlab-${profile}-postgres`, namespace: `hwlab-${profile}`, host: `hwlab-${profile}-postgres.hwlab-${profile}.svc.cluster.local` }) }); } const supportedDbProtocols = new Set(["postgres:", "postgresql:"]); const defaultProbeTimeoutMs = 1200; export function buildDbHealthContract(env = process.env) { const contract = dbEnvContractFor(env); const secretEnvNames = secretEnvNamesForContract(contract); const fields = contract.requiredEnv.map((name) => { const present = hasEnvValue(env, name); return { name, present, redacted: secretEnvNames.has(name), source: secretEnvNames.has(name) ? "k8s-secret-ref" : "runtime-env", required: true }; }); const missingEnv = fields.filter((field) => !field.present).map((field) => field.name); const configReady = missingEnv.length === 0; const connection = buildNotAttemptedConnection(configReady, missingEnv, contract); const connected = false; const connectionChecked = false; const status = configReady ? "degraded" : "blocked"; const endpoint = buildEndpointDiagnostics(env, contract); return { contractVersion: contract.contractVersion, environment: contract.environment, connected, liveConnected: connected, liveDbEvidence: connected, connectionChecked, connectionAttempted: connection.attempted, connectionResult: connection.result, configReady, ready: connected, status, mode: configReady ? "configured_without_live_connection_attempt" : "not_configured", fields, missingEnv, endpoint, endpointSource: endpoint.authoritative.source, optionalPublicDnsAlias: endpoint.optionalPublicDnsAlias, secretRefs: contract.secretRefs.map(({ env: envName, secretName, secretKey }) => ({ env: envName, secretName, secretKey, present: hasEnvValue(env, envName), envInjected: hasEnvValue(env, envName), secretPresent: "not_observed_by_runtime", secretKeyPresent: "not_observed_by_runtime", redacted: true })), connection, redaction: buildRedactionSafety(connection), safety: { environment: contract.environment, devOnly: contract.environment === ENVIRONMENT_DEV, prodAllowed: contract.forbidden.prodAllowed, secretsRead: false, secretMaterialRead: false, valuesRedacted: true, endpointRedacted: true, liveDbEvidence: connected, liveDbConnectedEvidence: connected }, readinessLayers: buildReadinessLayers(connection), blocker: configReady ? "live DB connection has not been attempted by this health contract" : missingEnvBlocker(missingEnv), evidence: configReady ? "env_presence_only_no_live_db" : "env_contract_blocked" }; } export async function buildDbRuntimeReadiness(env = process.env, options = {}) { const base = buildDbHealthContract(env); if (!base.configReady) { return base; } if (probeDisabled(env, options)) { return { ...base, blocker: "live DB probe is disabled for this runtime", evidence: "env_presence_only_probe_disabled" }; } const connection = await probeDbConnection(env, options); return applyConnectionResult(base, connection); } export function buildDbEnvManifestPlaceholder() { return { requiredEnv: [...DEV_DB_ENV_CONTRACT.requiredEnv], secretRefs: DEV_DB_ENV_CONTRACT.secretRefs.map((item) => ({ ...item })), endpointAuthority: { ...DEV_DB_ENV_CONTRACT.endpointAuthority }, dns: { ...DEV_DB_ENV_CONTRACT.dns }, readinessLayers: [...DEV_DB_ENV_CONTRACT.readinessLayers], forbiddenRuntimeHosts: [...DEV_DB_ENV_CONTRACT.forbidden.invalidRuntimeHosts], nonSecretDefaults: { ...DEV_DB_ENV_CONTRACT.nonSecretDefaults }, fixtureEvidence: { liveDbEvidence: false, summary: "This manifest contract records only env and Secret reference names. It is not live DB evidence." } }; } export function summarizeDbContract(db = buildDbHealthContract()) { const contract = dbEnvContractForDb(db); return { status: db.status, ready: db.ready, configReady: db.configReady, connected: db.connected, liveConnected: db.liveConnected ?? db.connected, connectionChecked: db.connectionChecked, connectionAttempted: db.connectionAttempted ?? db.connectionChecked, connectionResult: db.connectionResult ?? db.connection?.result ?? "unknown", liveDbEvidence: Boolean(db.liveDbEvidence ?? db.safety?.liveDbEvidence), requiredEnv: db.fields.map((field) => ({ name: field.name, present: field.present, redacted: field.redacted, source: field.source })), missingEnv: [...db.missingEnv], secretRefs: db.secretRefs.map( ({ env: envName, secretName, secretKey, present, envInjected, secretPresent, secretKeyPresent, redacted }) => ({ env: envName, secretName, secretKey, present, envInjected: envInjected ?? present, secretPresent: secretPresent ?? "not_observed", secretKeyPresent: secretKeyPresent ?? "not_observed", redacted }) ), endpointSource: db.endpointSource ?? db.endpoint?.authoritative?.source ?? db.connection?.endpointSource ?? contract.endpointAuthority.source, optionalPublicDnsAlias: summarizeOptionalPublicDnsAlias(db.optionalPublicDnsAlias ?? db.endpoint?.optionalPublicDnsAlias, contract), connection: summarizeConnection(db.connection, contract), redaction: summarizeRedaction(db.redaction), readinessLayers: db.readinessLayers ?? buildReadinessLayers(db.connection), blocker: db.blocker ?? null, fixtureEvidence: false }; } export function applyRuntimeDbReadinessLayers(db = buildDbHealthContract(), runtime = {}) { const baseLayers = buildReadinessLayers(db.connection); if (!db?.ready || db?.connectionResult !== "connected") { return { ...db, readinessLayers: baseLayers, runtimeReadiness: buildDbRuntimeReadinessSummary(runtime, { dbLiveReady: false }) }; } return { ...db, readinessLayers: { ...baseLayers, ssl: layerFromRuntimeGate(runtime, "ssl"), auth: layerFromRuntimeGate(runtime, "auth"), schema: layerFromRuntimeGate(runtime, "schema"), migration: layerFromRuntimeGate(runtime, "migration"), durability: layerFromRuntimeGate(runtime, "durability") }, runtimeReadiness: buildDbRuntimeReadinessSummary(runtime, { dbLiveReady: true }) }; } function hasEnvValue(env, name) { return typeof env?.[name] === "string" && env[name].trim().length > 0; } export function dbEnvContractFor(env = process.env) { const value = env?.HWLAB_GITOPS_PROFILE || env?.HWLAB_ENVIRONMENT || ""; const profile = typeof value === "string" ? value.trim().toLowerCase() : ""; return dbEnvContractForProfile(profile); } function dbEnvContractForDb(db = {}) { return dbEnvContractForProfile(db?.environment); } function dbEnvContractForProfile(profile) { if (profile === V02_DB_ENV_CONTRACT.environment) return V02_DB_ENV_CONTRACT; if (profile === V03_DB_ENV_CONTRACT.environment) return V03_DB_ENV_CONTRACT; if (isRuntimeLaneProfile(profile)) return buildRuntimeLaneDbEnvContract(profile); return DEV_DB_ENV_CONTRACT; } function isRuntimeLaneProfile(profile) { return typeof profile === "string" && /^v[0-9]{2,}$/u.test(profile); } function secretEnvNamesForContract(contract) { return new Set(contract.secretRefs.map((item) => item.env)); } function probeDisabled(env, options) { return options.probe === false || env?.HWLAB_CLOUD_DB_PROBE_DISABLED === "1"; } function buildNotAttemptedConnection(configReady, missingEnv, contract = DEV_DB_ENV_CONTRACT) { return { attempted: false, networkAttempted: false, result: configReady ? "not_attempted" : "not_attempted_missing_env", classification: configReady ? "configured_no_live_attempt" : "missing_runtime_env", endpointSource: contract.endpointAuthority.source, probeType: "tcp-connect", endpointRedacted: true, valueRedacted: true, timeoutMs: null, durationMs: 0, errorCode: null, missingEnv: [...missingEnv] }; } function buildRedactionSafety(connection) { return { valuesRedacted: true, endpointRedacted: connection?.endpointRedacted !== false, valueRedacted: connection?.valueRedacted !== false, secretMaterialRead: false, secretRefsOnly: true }; } async function probeDbConnection(env, options) { const contract = dbEnvContractFor(env); const timeoutMs = normalizeTimeoutMs(options.timeoutMs ?? env?.HWLAB_CLOUD_DB_PROBE_TIMEOUT_MS); if (typeof options.probe === "function") { return options.probe({ endpointSource: contract.endpointAuthority.source, timeoutMs }); } const parsed = parseDbUrlContract(env?.HWLAB_CLOUD_DB_URL, contract); if (!parsed.ok) { return { attempted: true, networkAttempted: false, result: parsed.result, classification: parsed.classification, endpointSource: contract.endpointAuthority.source, probeType: "tcp-connect", endpointRedacted: true, valueRedacted: true, timeoutMs, durationMs: 0, errorCode: parsed.errorCode, missingEnv: [] }; } return tcpConnect({ host: parsed.host, port: parsed.port, timeoutMs, endpointSource: contract.endpointAuthority.source }); } export function parseDbUrlContract(rawUrl, contract = DEV_DB_ENV_CONTRACT) { try { const url = new URL(rawUrl); if (!supportedDbProtocols.has(url.protocol)) { return { ok: false, result: "unsupported_protocol", classification: "db_url_unsupported_protocol", errorCode: "UNSUPPORTED_PROTOCOL" }; } if (!url.hostname) { return { ok: false, result: "invalid_url", classification: "db_url_missing_host", errorCode: "MISSING_HOST" }; } if (isForbiddenRuntimeHost(url.hostname, contract)) { return { ok: false, result: "forbidden_runtime_host", classification: "db_url_forbidden_invalid_host", errorCode: "FORBIDDEN_INVALID_HOST" }; } const port = url.port ? Number.parseInt(url.port, 10) : 5432; if (!Number.isInteger(port) || port <= 0 || port > 65535) { return { ok: false, result: "invalid_url", classification: "db_url_invalid_port", errorCode: "INVALID_PORT" }; } return { ok: true, host: url.hostname, port }; } catch { return { ok: false, result: "invalid_url", classification: "db_url_parse_error", errorCode: "INVALID_URL" }; } } function tcpConnect({ host, port, timeoutMs, endpointSource }) { return new Promise((resolve) => { const startedAt = Date.now(); const socket = net.connect({ host, port, timeout: timeoutMs }); let settled = false; function finish(result) { if (settled) return; settled = true; socket.destroy(); resolve({ attempted: true, networkAttempted: true, endpointSource, probeType: "tcp-connect", endpointRedacted: true, valueRedacted: true, timeoutMs, durationMs: Date.now() - startedAt, missingEnv: [], ...result }); } socket.on("connect", () => { finish({ result: "connected", classification: "tcp_connected", errorCode: null }); }); socket.on("timeout", () => { finish({ result: "timeout", classification: "tcp_timeout", errorCode: "ETIMEDOUT" }); }); socket.on("error", (error) => { finish(classifySocketError(error)); }); }); } function classifySocketError(error) { const code = typeof error?.code === "string" ? error.code : "UNKNOWN"; if (code === "ECONNREFUSED") { return { result: "refused", classification: "tcp_refused", errorCode: code }; } if (code === "ENOTFOUND" || code === "EAI_AGAIN") { return { result: "dns_error", classification: "dns_resolution_failed", errorCode: code }; } if (code === "ETIMEDOUT") { return { result: "timeout", classification: "tcp_timeout", errorCode: code }; } if (code === "EHOSTUNREACH" || code === "ENETUNREACH") { return { result: "network_unreachable", classification: "network_unreachable", errorCode: code }; } return { result: "error", classification: "tcp_error", errorCode: code }; } function applyConnectionResult(base, connection) { const liveConnected = connection.result === "connected"; return { ...base, connected: liveConnected, liveConnected, liveDbEvidence: liveConnected, connectionChecked: connection.attempted, connectionAttempted: connection.attempted, connectionResult: connection.result, ready: liveConnected, status: liveConnected ? "ready" : "degraded", mode: liveConnected ? "live_connection_ready" : "live_connection_blocked", connection, endpoint: base.endpoint, endpointSource: connection.endpointSource ?? base.endpointSource, optionalPublicDnsAlias: base.optionalPublicDnsAlias, redaction: buildRedactionSafety(connection), safety: { ...base.safety, endpointRedacted: connection.endpointRedacted !== false, liveDbEvidence: liveConnected, liveDbConnectedEvidence: liveConnected }, readinessLayers: buildReadinessLayers(connection), blocker: liveConnected ? null : blockerForConnection(connection), evidence: liveConnected ? "live_db_tcp_connection_ready" : "live_db_tcp_connection_blocked" }; } function blockerForConnection(connection) { if (connection.result === "invalid_url") { return "DB URL is injected but cannot be parsed as a supported postgres URL"; } if (connection.result === "forbidden_runtime_host") { return "DB URL is injected but points at a forbidden .invalid DEV runtime host"; } if (connection.result === "unsupported_protocol") { return "DB URL is injected but does not use a supported postgres protocol"; } if (connection.result === "refused") { return "DB endpoint refused a TCP connection from the cloud-api runtime"; } if (connection.result === "timeout") { return "DB endpoint TCP connection timed out from the cloud-api runtime"; } if (connection.result === "dns_error") { return "DB endpoint DNS resolution failed from the cloud-api runtime"; } if (connection.result === "network_unreachable") { return "DB endpoint network is unreachable from the cloud-api runtime"; } return "DB endpoint TCP connection did not complete from the cloud-api runtime"; } function missingEnvBlocker(missingEnv) { return `DB runtime config is missing ${missingEnv.join(", ")}`; } function normalizeTimeoutMs(value) { const parsed = Number.parseInt(String(value ?? ""), 10); if (!Number.isInteger(parsed) || parsed <= 0) { return defaultProbeTimeoutMs; } return Math.min(parsed, 5000); } function isForbiddenRuntimeHost(hostname, contract = DEV_DB_ENV_CONTRACT) { const normalized = String(hostname ?? "").toLowerCase(); return contract.forbidden.invalidRuntimeHosts.some((host) => host.startsWith(".") ? normalized.endsWith(host) : normalized === host ); } function buildReadinessLayers(connection = {}) { const result = connection?.result ?? "unknown"; const connected = result === "connected"; const dnsReady = connected || ["refused", "timeout", "network_unreachable", "error"].includes(result); const tcpReady = connected; return { dns: { status: dnsReady ? "pass" : "not_proven", result }, tcp: { status: tcpReady ? "pass" : "not_proven", result }, ssl: { status: "not_proven", result: connected ? "tcp_connected_ssl_not_checked" : result }, auth: { status: "not_proven", result: connected ? "tcp_connected_auth_not_checked" : result }, schema: { status: "not_proven", result: connected ? "tcp_connected_schema_not_checked" : result }, migration: { status: "not_proven", result: connected ? "tcp_connected_migration_not_checked" : result }, durability: { status: "not_proven", result: connected ? "tcp_connected_durability_not_checked" : result } }; } function layerFromRuntimeGate(runtime = {}, gateName) { if (!isPostgresRuntime(runtime)) { return { status: "not_proven", result: "runtime_adapter_not_postgres" }; } const gate = runtime.gates?.[gateName]; if (gate?.ready === true || gate?.status === "ready") { return { status: "pass", result: `runtime_${gateName}_ready`, blocker: null }; } if (gate?.status === "blocked" || runtimeGateBlockedAt(runtime, gateName)) { return { status: "blocked", result: runtimeLayerResult(runtime, gateName), blocker: gate?.blocker ?? runtime.blocker ?? null }; } return { status: "not_proven", result: `runtime_${gateName}_not_checked`, blocker: null }; } function isPostgresRuntime(runtime = {}) { return runtime?.adapter === RUNTIME_STORE_KIND_POSTGRES || runtime?.durableRequested === true; } function runtimeGateBlockedAt(runtime = {}, gateName) { const blocker = runtime?.blocker; if (gateName === "ssl") return blocker === RUNTIME_DURABLE_ADAPTER_SSL_BLOCKED; if (gateName === "auth") return blocker === RUNTIME_DURABLE_ADAPTER_AUTH_BLOCKED; if (gateName === "schema") return blocker === RUNTIME_DURABLE_ADAPTER_SCHEMA_BLOCKED; if (gateName === "migration") return blocker === RUNTIME_DURABLE_ADAPTER_MIGRATION_BLOCKED; if (gateName === "durability") return blocker === RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED; return false; } function runtimeLayerResult(runtime = {}, gateName) { const queryResult = runtime?.connection?.queryResult; if (typeof queryResult === "string" && queryResult.length > 0) return queryResult; if (gateName === "ssl") return "ssl_negotiation_blocked"; if (gateName === "auth") return "auth_blocked"; if (gateName === "schema") return "schema_blocked"; if (gateName === "migration") return "migration_blocked"; if (gateName === "durability") return "query_blocked"; return "runtime_query_blocked"; } function buildDbRuntimeReadinessSummary(runtime = {}, { dbLiveReady } = {}) { const contract = runtime?.durabilityContract ?? {}; return { adapter: runtime?.adapter ?? "unknown", durable: Boolean(runtime?.durable), durableRequested: Boolean(runtime?.durableRequested || runtime?.adapter === RUNTIME_STORE_KIND_POSTGRES), ready: runtime?.ready === true, status: runtime?.status ?? "unknown", blocker: runtime?.blocker ?? null, blockedLayer: contract.blockedLayer ?? null, queryAttempted: Boolean(runtime?.connection?.queryAttempted), queryResult: runtime?.connection?.queryResult ?? (dbLiveReady ? "not_checked" : "db_live_not_ready"), dbLiveEvidenceObserved: Boolean(dbLiveReady), dbLiveEvidenceIsDurabilityEvidence: false, requiredEvidence: contract.requiredEvidence ?? RUNTIME_DURABILITY_REQUIRED_EVIDENCE, secretMaterialRead: false, valuesRedacted: true, endpointRedacted: true }; } function summarizeConnection(connection, contract = DEV_DB_ENV_CONTRACT) { if (!connection) { return { attempted: false, result: "unknown", endpointRedacted: true, valueRedacted: true }; } return { attempted: Boolean(connection.attempted), networkAttempted: Boolean(connection.networkAttempted), result: connection.result, classification: connection.classification, endpointSource: connection.endpointSource ?? contract.endpointAuthority.source, probeType: connection.probeType, endpointRedacted: true, valueRedacted: true, timeoutMs: connection.timeoutMs, durationMs: connection.durationMs, errorCode: connection.errorCode ?? null }; } function buildEndpointDiagnostics(env, contract = dbEnvContractFor(env)) { const authority = contract.endpointAuthority; return { authoritative: { source: authority.source, env: authority.env, requiredForReadiness: authority.requiredForReadiness, usedForProbe: true, endpointRedacted: true, valueRedacted: true }, optionalPublicDnsAlias: buildOptionalPublicDnsAlias(env, contract) }; } function buildOptionalPublicDnsAlias(env, contract = dbEnvContractFor(env)) { const alias = contract.dns; const serviceNamePresent = env?.HWLAB_CLOUD_DB_SERVICE_NAME === alias.serviceName; const namespacePresent = env?.HWLAB_CLOUD_DB_SERVICE_NAMESPACE === alias.namespace; const hostPresent = env?.HWLAB_CLOUD_DB_HOST === alias.host; const portPresent = env?.HWLAB_CLOUD_DB_PORT === String(alias.port); const envPresent = serviceNamePresent || namespacePresent || hostPresent || portPresent; return { source: alias.source, serviceName: alias.serviceName, namespace: alias.namespace, port: alias.port, portName: alias.portName, requiredForReadiness: false, usedForProbe: false, envPresent, readyGate: "not_readiness_authority", note: envPresent ? "optional alias env observed; live DB readiness still follows the redacted Secret URL host" : "optional alias is not configured and is not required for live DB readiness" }; } function summarizeOptionalPublicDnsAlias(alias, contract = DEV_DB_ENV_CONTRACT) { const fallback = buildOptionalPublicDnsAlias({}, contract); const value = alias ?? fallback; return { source: value.source ?? fallback.source, serviceName: value.serviceName ?? fallback.serviceName, namespace: value.namespace ?? fallback.namespace, port: value.port ?? fallback.port, portName: value.portName ?? fallback.portName, requiredForReadiness: value.requiredForReadiness === true ? true : false, usedForProbe: value.usedForProbe === true ? true : false, envPresent: value.envPresent === true, readyGate: value.readyGate ?? "not_readiness_authority" }; } function summarizeRedaction(redaction) { return { valuesRedacted: redaction?.valuesRedacted !== false, endpointRedacted: redaction?.endpointRedacted !== false, valueRedacted: redaction?.valueRedacted !== false, secretMaterialRead: redaction?.secretMaterialRead === true, secretRefsOnly: redaction?.secretRefsOnly !== false }; }