774 lines
24 KiB
TypeScript
774 lines
24 KiB
TypeScript
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
|
|
};
|
|
}
|